This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

static function called once is not inlined automatically



I have a function declared static.

This function is called only once in my compilation unit (in an ISR). It compiles to 16 words of machine code.

My compiler (IAR C/C++ Compiler for MSP430 5.10.6 [Kickstart LMS] (5.10.6.40180)) is set to the highest level of optimization (size or speed show no difference in that matter).

The optimizer does not inline the function automatically. Using the inline keyword has the desired effect, though.

Is there any reason why the optimizer would not inline the function automatically? Besides saving some instructions for the call and return, it saves some slots on the stack.

  • Gauthier ��stervall said:
    I have a function declared static.

    What reason do you have to declare the function static?

    Actually, any function that is no class function is a static function. (non-static functions require a this pointer)

    Declaring a function static does not make it automatically suitable for inlining.

    Under mspgcc, you can declare a function 'pure', which tells the compiler that this functions output is based only on its parameters (and no global or static variables) and has no side-effects, so it can be inlined and/or optimized in its use at-will. It's no 'must' anyway.

    Gauthier ��stervall said:
    This function is called only once in my compilation unit (in an ISR).

    Fine. Still no 'must' to inline it. It might be called from outside too. And it may have static local variables which won't allow inlining, or may have side-effects.

    Gauthier ��stervall said:
    Using the inline keyword has the desired effect, though.

    Yes, that's the way to tell the compiler that it should be inlined where possible.

    It is still the compilers choice to inline or not to inline. You cannot force the compiler if it doesn't want to for some reason. Size may be a consideration (e.g. if the threshold is set to 14, your 16 byte function will never be inlined). Or usage. Perhaps its usage inside an ISR might be a K.O. criteria for automatic inlining.

    If you're lucky, the strategy is descibed in the compiler manual. If not, well, bad luck. Inlining is a compiler strategy and no mandatory part of any C language implementation.
    (and after all, in a different thread we discovered that CCS does not claim at all to follow any C/C++ standard.  The manual only describes which parts of which standard it actually implements.

    Gauthier ��stervall said:
    Besides saving some instructions for the call and return, it saves some slots on the stack.

    Are you sure? Maybe the use of registers inside the function will hinder optimization more than the funciton call (especially if there are other function calls near). I admit that inside an ISR, inlining will eliminate the need to save and restore the transfer registers, but maybe the compiler does not differentiate for being inside an ISR (only the entry/exit code generator needs to)

    Anyway, you found the solution that seems to work for you: using the inline keyword.

    I think (but that's jsut a distant memory) that using the static modifier together with inline will prevent the creation of an instance of this function (which is usually still created even if the function is inlined, since it could be called from other compilation units anyway if it cannot be inlined there for some reason) At least that's what I discovered once for the mspgcc compiler.

  • Thank you for the answer. I should have been clearer: I am using C, not C++.

    The reason for the function to be static is modularity, I do not want it to be accessible outside this compilation unit. As such, the compiler is aware that the function may not be directly called from outside, and thus knows where all calls to the function are (that is, in this very unit).

    I am aware that the compiler has no requirement to inline functions, even if the inline keyword is used. I agree that the compiler does follow the standard in that way, I am just surprised that it did not inline automatically, since it seems the sensible thing to do and a pretty trivial optimization. Therefore I was wondering if I missed something.
    The presence of the inline keyword - though not forcing it - makes the compiler choose to inline. When given the hint the optimizer optimizes; I wonder why it does not optimize automatically.

    The reason I can think of for an optimizer not to inline a function: the function is big enough, and called enough times, that not inlining it saves memory.
    - if a function is not static, the compiler does not know where and how many times it is called, thus no inlining.
    - if the function is static but called many times, there is memory to save by not inlining it. The decision must depend on the number of times the function is called as well as its size.

    As you pointed out, the solution in my case is to use the inline keyword, which I do. The aim of my question was not this specific case, but to understand how the optimizer is working and if there were some aspects of the inline exansion optimization that I missed. I understand that optimizer heuristics are not perfect, and would accept that this optimization could be missed, I want to be sure that I am not the one at fault.

    Jens-Michael Gross said:

    Are you sure? Maybe the use of registers inside the function will hinder optimization more than the funciton call (especially if there are other function calls near). I admit that inside an ISR, inlining will eliminate the need to save and restore the transfer registers, but maybe the compiler does not differentiate for being inside an ISR (only the entry/exit code generator needs to)

    I checked the disassembly result again: inlining reduces the amount of registers stacked at the start of the ISR (2 words instead of 4). The function called produced the same amount of machine code, but one reta and one calla were saved in the inlined version. The registers used changed slightly (the inline version could use the same register for several different things, which explains the reduced number of stacked registers).

     

    Jens-Michael Gross said:

    I think (but that's jsut a distant memory) that using the static modifier together with inline will prevent the creation of an instance of this function (which is usually still created even if the function is inlined, since it could be called from other compilation units anyway if it cannot be inlined there for some reason) At least that's what I discovered once for the mspgcc compiler.

    I do not know about this. In C I believe that the optimizer may choose to inline a static inline function, or choose not to.

     

    I was not aware of CCS not following any standard! I suppose many were disappointed...

  • The IAR compiler lets the user select or unselect the inline optimization. The optimization is only for High optimization level, but the fact that it is selectable speaks for a inline expansion that is possible even without the keyword. Sadly the documentation does not give any detail on the heuristic.

  • Gauthier ��stervall said:
    I wonder why it does not optimize automatically.

    Maybe inlining is an optimization that is independent (and therefore not implicitely handled) by teh optimization. After all, the inline keyword is part of the C language (a source code component) while the compiler optimization settings are a compiler-specific thing and a component of the toolchain.

    If you disable optimizations, does it prevent inlining too? In mspgcc, I think this is independent. Jsu tthat with optimization on, the inlined code can be globally optimized (across the border of the inlined content) while it won't be optimized at all if optimization is off. It is still inlined if I use the keyword.

    I agree that automatic inlining could be done even without the keyword as an optimization feature.

    Gauthier ��stervall said:
    In C I believe that the optimizer may choose to inline a static inline function, or choose not to

    Well, the C standard shouldn't (if it does at all) make any statement about what an optimizer may or may not do. Optimizing is as far off the scope of the C language definition as the usage of the target processor registers or generated opcodes :) Thsi is why the 'inline' keyword is just considered a hint and not a must. It's a nice addition, but basically, i tis important that the code does what it is told to, not how large the generated code is or how efficient.

    Gauthier ��stervall said:
    The aim of my question was not this specific case, but to understand how the optimizer is working and if there were some aspects of the inline exansion optimization that I missed.

    Unfortunately, the 'how' is intellectual property of the compiler developer and often treated as secret. I too often stumble across things where I wanted or needed more details and nothing was to be found or revealed.
    It nicely fits into the evolution of the current OS's(especially windows) where things are silently done wihout telling the user (or the admin) and without any explanation how to stop it.

    Gauthier ��stervall said:
    In C I believe that the optimizer may choose to inline a static inline function, or choose not to.

    Well, a 'static' alone doesn't make anything in mspgcc (AFAIK). But when inlining code with inline keyword or without, there will still be a separate instance of the function in case it is called from outside. Which disappears when adding the static modifier. (Which does not contradict your expectation for the static keyword)

    However, I don't use inline/inlined functions anymore as they are pretty much useless if you write modular code. Usually, you need them in different compilation units and here the typical inlining fails. of course you can put them into a header file and declare them static inline. It would work, perhaps (as this is not ensured), but function definitions in a header file are, well, against my sense of coding. In all cases where I had used inline function, I use macros instead. If I need a return parameter, I pass a target pointer. The code is as tight or sometimes tighter than inlined code and I have no problems to force an inlining.
    It's not a 100% replacement for inline functions, but for my cases it works fine.

    Gauthier ��stervall said:
    I was not aware of CCS not following any standard! I suppose many were disappointed...

    Well, the compiler documentation lists in every detail which part of which standard (usually K&R) it implements. But it lists the parts it implements instead of claiming to implement the whole standard and then lists the exceptions.
    Which is a smart move, I think, since it is easier to guarantee what you have implemented than to guarantee everything and list the exceptions. If you forget to list an exception, people will complain rightfully. If you forget to list a feature, nobody has a right to complain. :)

     

  • Jens-Michael Gross said:
    I agree that automatic inlining could be done even without the keyword as an optimization feature.

    Could, and should, IMO. In the case of a function that is unaccessible from outside, and called only once, I can't see why it wouldn't. My question is if there are reasons for not doing it, that I missed.

    Jens-Michael Gross said:
    Well, the C standard shouldn't (if it does at all) make any statement about what an optimizer may or may not do.

    This is precisely my point. The optimizer may choose to, or may choose not to.

    Jens-Michael Gross said:
    Unfortunately, the 'how' is intellectual property of the compiler developer and often treated as secret.

    It sure is. I meant "how " as in the effect of the optimizer, not the heuristics. Specifically I expected an optimizer to inline my function, and it did not.

    Jens-Michael Gross said:
    Well, a 'static' alone doesn't make anything in mspgcc (AFAIK). But when inlining code with inline keyword or without, there will still be a separate instance of the function in case it is called from outside. Which disappears when adding the static modifier. (Which does not contradict your expectation for the static keyword)

    static alone does quite a lot: it gives the function internal linkage (and besides that it gives the future reader a useful hint about the function). I don't know about mspgcc, but I'd be surprised if it discarded static in function definitions. Adding the static specifier removes the separate instance, but (and because) it prevents calling from outside.

    Jens-Michael Gross said:
    However, I don't use inline/inlined functions anymore as they are pretty much useless if you write modular code. Usually, you need them in different compilation units and here the typical inlining fails.

    This might be true for functions with external linkage. In my case, the function has internal linkage, and inlining it is not useless: it saves two pushes, two pops, a calla, and a reta. In an ISR running at 15 kHz, it is quite valuable. Yet having the function as a function instead of a macro is also valuable, for readability, type checking, and other issues with macros. By the way, you can combine inline and extern, with help of an inline definition.

     

     

     

  • Jens-Michael Gross said:

    If you disable optimizations, does it prevent inlining too? In mspgcc, I think this is independent. Jsu tthat with optimization on, the inlined code can be globally optimized (across the border of the inlined content) while it won't be optimized at all if optimization is off. It is still inlined if I use the keyword.

    Disabling inline expansion in the IAR optimizer options prevents inlining, even if the function is defined as inline. This makes sense I think: the inline keyword is as mentioned only a hint, and the optimizer is free to use inline expansion whenever it wants (whether or not the keyword is present) if the optimization is turned on. Turning it off prevents all inlining (whatever if hinted or not).

    Inline expansion is a form of optimization, I am surprised that mspgcc runs this optimization even if the optimizer is off. It means that you have no control over the inlining options (not that the standard says anything against it, but I find it strange). And I mean in the settings of the build toolchain, not in the source code.

     

  • Gauthier ��stervall said:
    Disabling inline expansion in the IAR optimizer options prevents inlining, even if the function is defined as inline. This makes sense I think: the inline keyword is as mentioned only a hint, and the optimizer is free to use inline expansion whenever it wants (whether or not the keyword is present) if the optimization is turned on. Turning it off prevents all inlining (whatever if hinted or not).

    Actually the optimizer can do anything it wants as long as the code still works the same. This includes not optimizing at all. Which kinds of optimization are available and active completely depend in the compiler designer.

    Gauthier ��stervall said:
    I am surprised that mspgcc runs this optimization even if the optimizer is off.

    Well, if teh optimizer is off, then not. But using the -o0 switch does not necessarily turn the optimizer off, nor is there any 'must' that the optimizer can be turned off at all.

    I think, GCC (and mspgcc, which build on gcc) has separate switches for controlling the inlining. I really don't remember which switches are available and what they control and when thy do not control something. It's a really huge list, includign many switches which only apply to a certain target structure (and do not apply to mspgcc), that it is difficult to figure out.

    I found a set of switches that works for me, including full optimization (my project on the 1232 won't fit into flash if not optimized) and if I detect a problem (there are many, some well documented, some mysterious), I try to figure out why and how to work around it. Just like the inlining: once I got it working the way I needed it, I (mostly) forgot about the problem. (I might be a Guru, but I'm no Yogi or Lama, so I don't need to contemplate about everything)

  • I understand there is no "must". It could just as well produce code that is 5 times larger than necessary if it wanted to.

    However, I have expectations from an optimizer, and they include performing inline expansion when beneficial. Again, the question is: is there another reason than "I do what I want" for not performing inline expansion in this case?

  • Gauthier ��stervall said:
    is there another reason than "I do what I want" for not performing inline expansion in this case?

    No obvious one. Further details can only come from the compiler designer. And for this, this is the wrong forum.
    As I said, the way the optimizer works and makes decisions (including this one) is a 'secret technology' that separates one compiler rom the other. (else we'd only need one).

    Perhaps they jsut forgot to implement it, perhaps the compiler does not consider a function as inlining candidate if it was not detected as such when being parsed. It depends on how the compiler and the optimizer are implemented. Maybe there are side-effects to other compier options (e.g. the option to place each funciton into its own relocatable segment instead of the whole compileaiton unit - so you can later eliminate unused function form the binary- interferes with global optimizations and common subexpression elimination. An example from mspgcc, if you use one, the other is disabled or limited)

    Again,l only the one who made the compiler can tell. Or maybe it's in the documentation but on a place you wouldn't look for it.

**Attention** This is a public forum