g++ 优化标志:-fuse-linker-plugin 和 -fwhole-program 的区别

22
我正在阅读:
http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

它首先建议:
-flto 结合使用时,不应使用此选项(-fwhole-program)。相反,依赖于链接器插件应提供更安全和更精确的信息。

然后,它建议:
如果程序不需要导出任何符号,则可以组合使用 -flto-fwhole-program,以允许过程间优化器使用更激进的假设,这可能会带来改进的优化机会。当链接器插件处于活动状态时,不需要使用 -fwhole-program(请参见 -use-linker-plugin)。

这是否意味着理论上始终使用 -fuse-linker-plugin-flto 比使用 -fwhole-program-flto 获得更好的优化可执行文件?

我尝试使用ld分别链接 -fuse-linker-plugin-fwhole-program,至少可执行文件的大小是不同的。

P.S. 我正在使用CentOS 6上的gcc 4.6.2和ld 2.21.53.0.1。


2
顺便提一下,根据您的引用 - “当链接器插件处于活动状态时不需要使用-fwhole-program选项(请参阅-fuse-linker-plugin)。”- 我们随后在文档中看到 - “启用此选项[-fuse-linker-plugin]是默认情况下启用的,当启用GCC的LTO支持并且GCC已配置为使用支持插件的链接器(GNU ld 2.21或更高版本或gold)。”- 所以我猜这涵盖了大多数合理的现代gcc安装。 意味着他们有一个默认选项,使-fwhole-program不必要。但这只是我的解释! - underscore_d
@underscore_d 太好了!现在我们该怎么把这个该死的东西关掉呢?(我是指fuse-linker-plugin。)请参见:https://stackoverflow.com/questions/68582122/gcc-10-3-1-1-fc32-build-failing-with-gcc-fatal-error-fuse-linker-plugin-b - Richard T
1个回答

10
更新:请参考下方@PeterCordes的评论。实际上,-fuse-linker-plugin 不再必要。
这些差异微妙。首先,了解 -flto 实际上是做什么的。它本质上创建一个可以在“链接时间”后进行优化的输出。 -fwhole-program 的作用是假设“当前编译单元代表正在编译的整个程序”,无论是否实际如此。因此,GCC 将假定它知道所有调用特定函数的位置。正如它所说,它可能使用更积极的过程间优化器。稍后我会解释一下。
最后,-fuse-linker-plugin 实际上是在链接时执行通常在每个编译单元执行时完成的优化。因此,这个选项被设计与 -flto 配合使用,因为 -flto 意味着保存足够的信息以便以后进行优化,而 -fuse-linker-plugin 意味着实际上执行这些优化。
那么,它们的区别在哪里?正如 GCC 文档所建议的那样,使用 -fwhole-program 在原则上没有优势,因为该选项假定您必须确保为真。要打破它,只需在一个 .cpp 文件中定义一个函数并在另一个文件中使用它。您会收到链接器错误。 -fwhole-program 有优势吗?如果只有一个编译单元,那么可以使用它,但是老实说,它不会更好。我能够通过使用等效的程序获得不同大小的可执行文件,但是当检查实际生成的机器代码时,它们是相同的。事实上,我看到的唯一区别是具有调试信息的行号不同。

3
据我所知,现在使用 gcc -O3 -march=native ... -flto 进行链接工作非常顺利,并且会执行所有必要的链接器插件操作。(将编译时使用的相同优化选项传递给链接命令。) - Peter Cordes
@PeterCordes,你知道gcc -O2 -march=native ... -flto是否也会这样做吗?很多时候,特别是对于热路径上机器码大于跟踪缓存的程序,O2的性能优于O3,而O3最好应用于选择的函数。感谢更新! - Nick Apperson
1
-O2当然也可以“直接运行”了。但只有-O3能启用自动向量化。如果任何重要循环可以受益于自动向量化,通常情况下它是值得付出代码大小代价的。现代x86 CPU不使用跟踪缓存,那只有Pentium 4才有。Sandybridge / Ryzen中的uop缓存不是跟踪缓存; 它不会跟着跳跃。此外,与P4相比,遗留的解码带宽要大得多,因此uop缓存未命中并不是一场灾难。但是,如果L1i未命中是一个问题,对于一些大型程序而言,O2整体上可能更好。 - Peter Cordes
3
请注意,现代GCC的-O3选项并会启用-funroll-loops;只有在使用-fprofile-generate / -fprofile-use 进行PGO时才会对热循环进行这样的操作。此外,GCC 8及更高版本通常会使用未对齐的加载/存储自动矢量化,而不是完全展开的序言/尾声来达到对齐边界。这种方式一直很糟糕且非常庞大,将大部分代码大小用于启动/清除而不是展开实际重要部分的循环!顺便说一下,clang的-O2选项会默认进行自动向量化,并展开小型循环。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接