链接时间优化和内联[英] Link-time optimization and inline

本文是小编为大家收集整理的关于链接时间优化和内联的处理方法,想解了链接时间优化和内联的问题怎么解决?链接时间优化和内联问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

根据我的经验,有很多代码明确使用内联函数,这是在权衡处进行的:

  1. 该代码变得不那么简洁,稍微降低.
  2. 有时,内部会大大增加运行时性能.
  3. 内部是在固定时间点确定的,也许没有非常好的对它的用途的好处,或者没有考虑所有(未来)周围环境.

问题是:链接时间优化(例如,在GCC中)是否渲染手册内部,例如在C99中声明一个函数"内联"并提供实现,过时了吗?我们不需要自己考虑自己的大多数功能吗? 始终受益的函数如何受益,例如deg_to_rad(x)?

澄清:我不是在考虑相同的翻译单元中的函数,而是关于应在逻辑上驻留在不同翻译单元中的函数.

更新:我经常看到反对"内联"的对立,并建议过时.但是,我个人确实会看到明确嵌套的函数通常:按照班级主体定义的功能.

推荐答案

即使使用LTO,编译器仍然必须使用启发式方法来确定是否对每个呼叫 inline a inline a inline (请注意,它不是每个函数的决定,而是每个呼叫的决定) .启发式方法考虑到诸如循环中的因素,是循环展开,功能的大小,全球称为一次.以及代码扩展是否可能会在编译时吹出特定CPU的指令/trace/loop/microcode缓存.

配置文件指导优化应该是解决此问题的一步可以朝任一方向! :-)这仍然是正在进行的工作.

如果性能是您的最终目标,并且您真的知道自己在做什么,并且真正对您的代码进行了彻底的分析,那么真正需要的是告诉编译器内联或不嵌入每个电话的方法基础,不是每个功能提示.在实践中,我已经通过使用编译器特定的" force_no_inline"类型来对此进行管理,我不需要内部的情况和一个单独的" force_inline"副本(或在极少数情况下,这会失败的宏). .如果有人知道如何用编译器特定的提示(对于任何C/C ++编译器)以更清洁的方式执行此操作,请让我知道.

专门解决您的观点:

1.代码变得不那么简洁,稍低.

通常,没有 - 这只是一个关键字提示,它可以控制它的内衬方式.但是,如果您像我在上一段中所描述的那样跳过箍,那么是.

2.有时,插入可以大大增加运行时性能.

将编译器留在自己的设备上时 - 是的,当然可以,但大多数情况下.编译器具有良好的启发式方法,尽管并不总是最佳的决策,虽然并非总是最佳的.从关键字方面来说,编译器可能会完全忽略关键字,或用作关键字作为弱提示 - 通常,它们似乎确实不喜欢嵌入的代码,这些代码会危及他们的持久性(例如将16K函数插入循环独立的16倍).

3.在固定点上决定,也许没有非常好的对其用途的好处,或者没有考虑所有(未来)周围环境的情况.

是的,它使用静态分析.动态分析可以来自您的见解,您按每句话或理论上从PGO(仍然很糟糕)手动控制插入.

.

其他推荐答案

GCC 9 Binutils 2.33实验表明LTO可以在线

对于那些好奇的ld是否跨对象文件的嵌入式的人来说,这是一个快速实验,可以证实它可以:

main.c

int notmain(void);

int main(void) {
    return notmain();
}

notmain.c

int notmain(void) {
    return 42;
}

用LTO编译并拆卸:

gcc -O3 -flto -ggdb3 -std=c99 -Wall -Wextra -pedantic -c -o main.o main.c
gcc -O3 -flto -ggdb3 -std=c99 -Wall -Wextra -pedantic -c -o notmain.o notmain.c
gcc -O3 -flto -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out notmain.o main.o
gdb -batch -ex "disassemble/rs main" main.out

拆卸输出:

   0x0000000000001040 <+0>:     b8 2a 00 00 00  mov    $0x2a,%eax
   0x0000000000001045 <+5>:     c3      retq 

因此,我们看到没有callq或其他跳跃,这意味着呼叫是在两个对象文件中夹住的.

没有-flto,但是我们看到:

   0x0000000000001040 <+0>:     f3 0f 1e fa     endbr64 
   0x0000000000001044 <+4>:     e9 f7 00 00 00  jmpq   0x1140 <notmain>

因此,如何有jmpq,这意味着呼叫未被列入.

请注意,编译器选择的JMPQ不会像更幼稚的CallQ作为优化那样进行任何堆栈更改,我认为这是A