繁体   English   中英

为什么gcc没有为此函数决定是否为inline-or-not?

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

从网上的一些话来看,我知道GCC足够聪明,可以决定是否内联函数。 inline关键字只是一个提示:
GCC可以内联一个共同的功能 ,并且可能不会内联内联函数

但是对于我的项目中的这个功能:

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;
    }
}

用-O2编译。
我检查了汇编代码,并且知道这个函数是按预期内联的。
但是,当我删除它的inline修饰符并重新编译时,我发现它并不是独行侠。 它的函数体出现在最终的二进制文件中:

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

我想知道,既然海湾合作委员会足够聪明,为什么它没有自己的决定呢? 为什么它在我指定时执行内联,而不是在我没有时执行?

因为他没有找到足够的线索做出有力的决定? 或者,因为他已经做出了决定,他的决定是:内联与否没有太大的区别,因为你问我,我为你排忧; 否则,我把它作为一个共同的功能。

我想知道真正的原因。
如果这是第一种情况,我认为我们可能需要重新考虑这个帖子开头的观点(在网上非常受欢迎)----至少,GCC并不像他们所说的那么聪明,并且内联关键词不是没用的正如他们所说。

在文章的最后,我想为上面的代码片段的上下文添加更多描述:

1,我原本希望将vi_write_vtail_smart()内联到函数A()B() ,这些函数作为库API导出,并且两者都经常被用户调用。

2, A()B()vi_write_vtail_smart()在同一个文件中。

3, vi_write_vtail_smart()仅用于A()B() ,否则用于其他地方。

如图4所示, A()的函数体大小约为450字节, B()类似。

5, A()B()基本上是普通的机器代码,没有涉及大循环或繁重的计算,只有一个子函数被调用,除了vi_write_vtail_smart() 该子功能在另一个文件中。

6,我做了一个小测试,我加了一行return; if之前(cursor-> g_offset> = vhead-> g_offset){ ,(我想看看当这个函数足够小时发生了什么),即:

...
int curoff = vi->curr - vi->lines[vi->currl].buf;
cursor->offset = curoff;    

return;
if(cursor->g_offset >= vhead->g_offset){
...

并且编译时没有inline修饰符,并检查汇编代码----这次GCC内联它,它的函数定义从最终的二进制文件中消失了。

7,我的发展环境:
ubuntu-16.04 / 64bit
gcc版本5.4.0 20160609
架构:intel X86 Ivybridge Mobile

9,编译标志(必须再次写入,有些人在阅读时会错过它)-O2 -std = gnu99

根据GCC文档,GCC有一个名为-finline-functions的优化设置。 这实际上是使GCC在所有函数上使用其启发式内联条件的设置,即使它们未以内inline声明。 此设置在-O3优化级别启用。 因此,您希望GCC完全自由地将其启发式应用于所有函数,您必须至少指定-O3 (或明确指定-finline-functions )。

没有-finline-functions GCC通常不会尝试内联未声明inline联的函数,但有一些值得注意的例外:许多其他内联选项也可能导致非内联函数内联。 但是,这些选项针对非常具体的情况

  • -finline-functions-called-once早在-O1就启用了。 只调用一次的静态函数被内联,即使它们未被inline声明。

  • -finline-small-functions-O2启用。 如果它导致代码大小减少,它会触发内联,即使该函数未声明为inline函数。

你的函数显然没有通过这些在-O2级激活的特定内联过滤器:它相对较大且(显然)被调用多次。 出于这个原因,GCC不会将其视为内联-O2 ,除非您使用inline关键字明确请求它。 请注意,显式inline关键字基本上类似于仅针对该特定函数启用的-finline-functions设置。 它将使GCC将其视为内联,但不保证内联。

同样,如果您希望GCC完全接管这些决策,您需要-finline-functions-O3 显式inline关键字触发内联-O2的事实意味着GCC应决定将其内联到-O3而不管inline是否存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM