From some words on net I know that GCC is smart enough to decide whether to inline a function or not. The inline
key word is just a hint:
GCC may inline a common function, and may not inline an inline function.
But for this function in my project:
struct vb_pos{
union{
struct{
int offset;
int l;
};
unsigned long long g_offset;
};
};
static inline void vi_write_vtail_smart(struct vi *vi){
struct vb_pos *vhead, *vtail, *cursor;
vhead = &vi->v_head;
vtail = &vi->v_tail;
cursor = &vi->cursor;
int curoff = vi->curr - vi->lines[vi->currl].buf;
cursor->offset = curoff;
if(cursor->g_offset >= vhead->g_offset){
*vtail = *cursor;
}
else{
*vtail = *vhead;
*vhead = *cursor;
}
}
compiled with -O2.
I checked the assembly code, and knew this function was inlined as expected.
However, when I deleted its inline
modifier, and recompiled, I found it was no loner inlined. Its function body appeared in final binary file:
0000000000000000 <vi_write_vtail_smart>:
0: 48 63 47 14 movslq 0x14(%rdi),%rax
4: 48 8b 17 mov (%rdi),%rdx
7: 48 8d 04 40 lea (%rax,%rax,2),%rax
b: 48 8d 04 c2 lea (%rdx,%rax,8),%rax
f: 48 8b 57 18 mov 0x18(%rdi),%rdx
13: 48 2b 10 sub (%rax),%rdx
16: 89 57 10 mov %edx,0x10(%rdi)
19: 48 8b 47 10 mov 0x10(%rdi),%rax
1d: 48 3b 47 38 cmp 0x38(%rdi),%rax
21: 73 0d jae 30 <vi_write_vtail_smart+0x30>
23: 48 8b 57 38 mov 0x38(%rdi),%rdx
27: 48 89 47 38 mov %rax,0x38(%rdi)
2b: 48 89 57 40 mov %rdx,0x40(%rdi)
2f: c3 retq
30: 48 89 47 40 mov %rax,0x40(%rdi)
34: c3 retq
I want to know, since GCC is smart enough, why didn't it has its own decision? Why it performed inline when I specified, and no when I not?
Because he didn't find enough clue to make a strong decision? or, because he already got a decision, and his decision is: there is no much difference to inline or not, and since you ask me, i inline for you; otherwise, i leave it as a common function.
I want to know the real reason.
If it's the first case, i think we may need reconsider the viewpoint(very popular on the net) in this post beginning————At least, GCC is not as smart as they said, and the inline key word is not as useless as they said.
In the article end, I want to add more description for the context of the code snippet above:
1, I originally want vi_write_vtail_smart()
to be inlined into function A()
and B()
, which are exported as library APIs and both will be often invoked by users.
2, A()
and B()
are within the same file with vi_write_vtail_smart()
.
3, vi_write_vtail_smart()
is only used in A()
and B()
, no where else.
4, the function body size of A()
is about 450 bytes, B()
is similar.
5, A()
and B()
are basically plain machine code, no big loop or heavy computations involved, and only one subfunction is invoked, except vi_write_vtail_smart()
. That subfunction is in another file.
6, I did a small test, I added one line return;
before if(cursor->g_offset >= vhead->g_offset){, (I wanted to see what happened when this function is small enough), namely:
...
int curoff = vi->curr - vi->lines[vi->currl].buf;
cursor->offset = curoff;
return;
if(cursor->g_offset >= vhead->g_offset){
...
And compiled without inline
modifier, and checked the assembly code————this time GCC inlined it and its function definition disappeared from final binary file.
7, My develop enviroment:
ubuntu-16.04 /64bit
gcc version 5.4.0 20160609
architecture: intel X86 Ivybridge Mobile
9,Compile flag( have to write here again, some people miss it when read) -O2 -std=gnu99
What is the reason? Remember, inlining is only a request to the compiler, not a command. Compiler can ignore the request for inlining.
GCC automatically inlines member functions defined within the class body of C++ programs even if they are not explicitly declared inline .
When we should avoid the use of inline? We should not use functions that are I/O bound as inline functions. When large code is used in some function, then we should avoid the inline. When recursion is used, inline function may not work properly.
If you need to make sure that function is inlined and OK to go with proprietary extension in MS VC++, check out the __forceinline declarator. The compiler will either inline the function or, if it falls into the list of documented special cases, you will get a warning - so you will know the inlining status.
According to GCC documentation, GCC has an optimization setting called -finline-functions
. This is actually the setting that makes GCC to use its heuristic inlining criteria on all functions, even if they are not declared inline
. This setting is enabled at -O3
optimization level. So, it you want to give GCC full freedom to apply its heuristics to all functions, you have to specify -O3
at least (or specify -finline-functions
explicitly).
Without -finline-functions
GCC does not generally attempt to inline functions that are not declared inline
, with some notable exceptions: a number of other inlining options might also lead to non-inline functions getting inlined. However, these options are targeted at very specific cases
-finline-functions-called-once
is enabled as early as -O1
. Static functions called only once are inlined, even if they are not declared inline
.
-finline-small-functions
is enabled at -O2
. It triggers inlining if it results in reduction of code size, even if the function is not declared inline
.
Your function apparently does not pass these specific inlining filters active at -O2
level: it is relatively large and (apparently) called more than once. For this reason GCC does not consider it for inlining at -O2
, unless you explicitly request it with inline
keyword. Note, that explicit inline
keyword is basically like -finline-functions
setting turned on for that specific function only. It will make GCC to consider it for inlining, but does not guarantee inlining.
Again, if you want GCC to completely take over these decisions you need -finline-functions
or -O3
. The fact that explicit inline
keyword triggers inlining at -O2
means that GCC should decide to inline it at -O3
regardless of whether inline
is present there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With