Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why didn't gcc decide inline-or-not for me for this function?

Tags:

c++

c

gcc

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

like image 509
weiweishuo Avatar asked Jul 02 '17 23:07

weiweishuo


People also ask

Why would a compiler not inline?

What is the reason? Remember, inlining is only a request to the compiler, not a command. Compiler can ignore the request for inlining.

Does GCC automatically inline functions?

GCC automatically inlines member functions defined within the class body of C++ programs even if they are not explicitly declared inline .

When inline method should not be used?

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.

How do you check if a function is inline or not?

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.


1 Answers

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.

like image 187
AnT Avatar answered Oct 19 '22 19:10

AnT