在调用者内部扩展callee的指导原则是什么(内联 - 编译器优化)

ult*_*use 1 c c++ caching inline compiler-optimization

我的理解是编译器遵循某些语义来决定是否应该内联扩展函数.例如,如果被调用者无条件地(无if /élse-if返回)返回一个值,它可以在调用者本身中扩展.同样,函数调用开销也可以指导这种扩展.(我可能完全错了)

类似地,诸如高速缓存使用之类的硬件参数也可以在扩展中起作用.

作为程序员,我想了解这些语义和指导内联扩展的算法.最终,我应该能够编写(或识别)一个肯定会内联的代码(非内联).我并不是要覆盖编译器,或者我认为我能够比编译器本身更好地编写代码.问题是要理解编译器的内部.

编辑:由于我在工作中使用gcc/g ++,我们可以将范围限制在这两个范围内.虽然,我认为在这种情况下编译器会有几个共同点.

Bas*_*tch 6

您不需要了解内联(或其他优化)条件,因为根据定义(假设优化编译器在这方面没有错误),内联代码的行为应与非内联代码相同.

你的第一个例子(callee无条件地返回一个值)实际上肯定是错误的,因为有几个编译器能够内联条件返回.

例如,请考虑以下f.c文件:

static int fact (int n) {
  if (n <= 0) return 1;
  else
    return n * fact (n - 1);
}

int foo () {
  return fact (10);
}
Run Code Online (Sandbox Code Playgroud)

编译它gcc -O3 -fverbose-asm -S f.c; 生成的f.s程序集文件只包含一个函数(foo),fact函数已经完全消失,并且fact(10)已经内联(递归)和替换(常量折叠)3628800.

随着GCC -current版本的GCC 5.2七月2015 -假设你问它来优化(例如,编译gcc -O2或g++ -O2或-O3)内联的决定是不容易理解.编译器很可能会比你能做的更好地内联决策.有许多内部启发式指导它(所以没有简单的指导原则,但有一些启发式内联,其他避免内联,可能还有一些元启发式选择).阅读有关优化选项(-finline-limit=...),功能属性的信息.

您可以使用always_inlineand gnu_inline和noinline(以及noclone)函数属性,但我不建议您这样做.

您可以禁用内联,noinline但通常生成的代码会更慢.所以不要这样做......

关键是编译器比你合理的更好地优化和内联,所以相信内联和优化.

优化的编译器(另见本)可以(做)内联函数即使没有你知道,比如他们有时内联没有标明功能inline或没有内联标记某些功能inline.

所以不,你不想"理解这些语义和指导内联扩展的算法",它们太难了......并且从一个编译器到另一个版本(甚至一个版本到另一个版本)各不相同.如果你真的想了解为什么GCC正在内联(这意味着花费数月的工作,我相信你不应该浪费你的时间),使用-fdump-tree-all和其他转储标志,使用MELT检测编译器- 我正在开发 - ,潜水进入源代码(因为GCC是一个免费软件).

您需要超过您的生命周期,或至少几十年,才能了解所有GCC(超过一千万行源代码)及其优化方式.当你理解某些东西时,海湾合作委员会社区将致力于新的优化等等......

顺便说一句,如果编译和链接与整个应用程序或库gcc -flto -O3(例如使用make CC='gcc -flto -O3')的GCC编译器会做链接时优化和内联几个电话翻过翻译单元(例如,在f1.c你调用foo定义的f2.c,和一些通话以foo在f1.c将得到内联).

编译器优化确实考虑了缓存大小(用于决定内联,展开,寄存器分配和溢出以及其他优化),特别是在编译时 gcc -mtune=native -O3

除非你强制编译器(例如通过在GCC中使用noinline或alwaysinline函数属性,这通常是错误的并且会产生更糟糕的代码),否则你将无法在实践中猜测给定的代码块肯定会被内联.即使是那些致力于GCC中端优化的人也无法可靠地猜测出来!因此,您无法可靠地理解并预测编译器在实践中的行为,因此甚至不会浪费您的时间来尝试.

另请参阅MILEPOST GCC ; 通过使用机器学习技术来调整一些GCC参数,他们有时能够获得惊人的性能改进,但他们肯定无法解释或理解它们.

如果您在编写某些C或C++时需要了解您的特定编译器,那么您的代码可能是错误的(例如可能有一些未定义的行为).您应该针对某些语言规范(C11或C++ 14标准,或特定的GCC方言,例如-std=gnu11由GCC编译器记录和实现)进行编码,并相信您的编译器忠实于该规范.