14

I have a function which operates on piece of data (let's say, an int), and I want to change it in place by passing a reference to the valule. As such, I have the function: void myFunction(int *thing) { ... }. When I use it I call it thus: myFunction(&anInt).

As my function is called frequently (but from many different places) I am concerned about its performance. The reason I have refactored it into a function is testability and code reuse.

Will the compiler be able to optimize the function, inlining it to operate directly on my anInt variable?

I hope you'll take this question in the spirit in which it's asked (i.e. I'm not prematurely worrying about optimisation, I'm curious about the answer). Similarly, I don't want to make it into a macro.

Joe
  • 46,419
  • 33
  • 155
  • 245

8 Answers8

18

One way to find out if the function is inlined is to use -Winline gcc option:

-Winline
  Warn if a function can not be inlined and it was declared as inline.
  Even with this option, the compiler will not warn about failures to inline
  functions declared in system headers.

  The compiler uses a variety of heuristics to determine whether or not to
  inline a function. For example, the compiler takes into account the size
  of the function being inlined and the amount of inlining that has already
  been done in the current function.  Therefore, seemingly insignificant
  changes in the source program can cause the warnings produced by -Winline
  to appear or disappear.
Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
9

GCC is quite smart. Consider this code fragment:

#include <stdio.h>

void __inline__ inc(int *val)
{
    ++ *val;
}

int main()
{
    int val;

    scanf("%d", &val);

    inc(&val);

    printf("%d\n", val);

    return 0;
}

After a gcc -S -O3 test.c you'll get the following relevant asm:

...
call    __isoc99_scanf
movl    12(%rsp), %esi
movl    $.LC1, %edi
xorl    %eax, %eax
addl    $1, %esi
movl    %esi, 12(%rsp)
call    printf
...

As you can see, there's no need to be an asm expert to see the inc() call has been converted to an increment instruction.

ntd
  • 7,372
  • 1
  • 27
  • 44
  • At least with GCC 4.4.2, it doesn't even need to be marked `inline`! (Although using `static` will avoid an extra copy of the function in the generated binary.) – ephemient Jan 07 '10 at 16:21
7

There are two issues here - can the code be optimised, and will it. It certainly can be, but the "will" depends on the mood the optimiser is in. If this is really important to you, compile the code and take a look at the assembly language output.

Also, you seem to be conflating two issues. An inlined function effectively has its body pasted at the call site. Whether or not you are using pointers is neither here nor there. But you seem to be asking if the compiler can transform:

int x = 42;
int * p = & x;
* p = * p + 1;

into

x = x + 1;

This is much more difficult for the optimiser to see.

  • I'm not quite at the stage where I'm ready to read the assembly output! – Joe Jan 07 '10 at 15:07
  • Re your most recent edit with `x` and `p`: yes, that's exactly the question I'm asking. I know it's difficult, that's why I was asking if it was possible or not! – Joe Jan 07 '10 at 15:14
  • As I said, it's possible. Does GCC do i? I don't know. –  Jan 07 '10 at 15:17
  • IMHO the compiler may have it easier to optimize the code, if you change your function to `int myFunction(int thing)` and call it like `thing=myFunction(thing)`. In this way you omit all the indirections, and the result will be plain arithmetic that the compiler (probably) can easily optimize away. – Frunsi Jan 07 '10 at 15:19
  • It's not just an int in the real code, it's a bit more complex. – Joe Jan 07 '10 at 15:27
  • 2
    Don't mind if it is a pointer to a struct, in this case the compiler has to apply pointer arithmetic anyway. Or at least use an address register (containing the address of the struct) and offsets for accessing the fields of the struct. This case may not make a difference after inlining. – Frunsi Jan 07 '10 at 15:34
  • Thank you frunsi, that's a useful insight I hadn't considered. – Joe Jan 07 '10 at 15:57
2

It should not matter whether the argument is a pointer or not.

But first, if the compiler should automatically inline the function, it must be static. And it must be contained in the same compilation unit. NOTE: we are talking about C, not C++. C++ inline rules differ.

If it is not possible to have the function in the same compilation unit, then try global optimizations (check documentation of your compiler for details).

C99 gives you an "inline" keyword, just as in C++. Which lifts the restriction to the compilation unit.

Here is some further information.

Frunsi
  • 7,099
  • 5
  • 36
  • 42
  • 2
    As C89 says nothing whatsoever about inlining, a C89 compiler is certainly free to inline any function it fancies. Of course, such a program might not link (which is the real issue here), but a compiler whith an integrated linker could get round this by performing a global code analysis. –  Jan 07 '10 at 15:23
  • So I guess, a compiler might automatically inline non-static functions if all files are compiled and linked in a single step into an executable (not into an object file or library). Well, ok, but its usually not very practical ;) The "must be static" rule still applies otherwise. – Frunsi Jan 07 '10 at 15:31
  • 1
    Depending on optimizer settings, size of function, frequency of calls, etc., GCC will inline non-static functions within the same compilation unit. It will still generate a non-inline function as well. – ephemient Jan 07 '10 at 16:49
  • Keep in mind that a compiler can pretty much do whatever it likes as long as the result matches the intent you wrote in the source code. As such a function can very well be inlined, or optimized away entierly without it being static or marked as inline. (e.g. gcc will easily do this in many scenarios). – nos Jan 07 '10 at 20:04
  • nos: why do you think gcc will optimize away a non-static function? It won't - at least not when it will produce an ELF file, without special compiler switches ;) – Frunsi Jan 07 '10 at 20:46
  • You are right that it'll keep the (non static) function body around, however it can optimize away/inline calls to it within the same translation unit. – nos Jan 08 '10 at 20:11
1

It will (or at least can). There are some reasons where the function cannot be inlined - e.g. when you try to access a pointer of the function (calling function by reference - you are accessing parameters by reference which is ok). There may be other situation (static variables? unsure)

Try to declare the function with "extern inline" - this prevents the compiler from emitting the standalone body. If it cannot inline the function, it will emit an error.

ondra
  • 9,122
  • 1
  • 25
  • 34
  • C99 says that `extern inline` does cause stand-alone object code to be generated, and GCC will follow these odd rules if put into C99 mode. Otherwise, GCC's default behavior is what you've stated. (C89 doesn't say anything, and arguably those are better semantics.) – ephemient Jan 08 '10 at 02:46
0

If you're concerned about the compiler generating suboptimal code and want to change a simple valuetype, declare your function as int myFunction(int) and return the new value.

tstenner
  • 10,080
  • 10
  • 57
  • 92
-1

What compiler version are you using? With what options? On what platform?

All these questions effect the answer. You really need to compile the code and look at the assembly to be sure.

mikelong
  • 3,694
  • 2
  • 35
  • 40
-1

This looks to me like a classic case of premature optimization. Do you really know there is a performance issue here? One worth wasting your valuable time worrying about. I mean, really know? Like, have you measured it?

By itself this isn't too bad, but if you take this attitude over a large amount of code, you can do some serious damage and waste a large amount of deveolpement and maintanence time for no good reason.

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • Like I said in the question, I'm not worrying about optimization, I'm trying to learn more about the language and GCC. I certainly believe in measuring before optimizing but I think it's useful to at least know these things. – Joe Jan 07 '10 at 15:40