LTO 中的优化与普通编译中的优化相同吗?
Are the optimizations done in LTO the same as in normal compilation?
在编译翻译单元时,编译器会进行大量优化 - 内联、常量 folding/propagation、别名分析、循环展开、死代码消除以及许多我什至从未听说过的其他优化。
在多个翻译单元之间使用 LTO/LTCG/WPO 时是否全部完成,或者只是完成了其中的一个子集(或变体)(我听说过内联)?
如果没有完成所有优化,我会考虑 unity 构建优于 LTO(或者当有超过 1 个 unity 源文件时可能同时使用它们)。
我的猜测是它不一样(统一构建具有全套优化)并且它在不同编译器之间差异很大。
各个编译器关于 lto 的文档并没有准确回答这个问题(或者我没理解)。
由于 lto 涉及在目标文件中保存中间表示,理论上 LTO 可以进行所有优化...对吗?
请注意,我不是在询问构建速度 - 这是一个单独的问题。
编辑:
我最感兴趣的是 gcc/llvm.
如果您查看 gcc 文档,您会发现:
-flto[=n]
This option runs the standard link-time optimizer. When invoked with source code, it generates GIMPLE (one of GCC's internal representations) and writes it to special ELF sections in the object file. When the object files are linked together, all the function bodies are read from these ELF sections and instantiated as if they had been part of the same translation unit.
To use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link. For example:
gcc -c -O2 -flto foo.c
gcc -c -O2 -flto bar.c
gcc -o myprog -flto -O2 foo.o bar.o
The first two invocations to GCC save a bytecode representation of GIMPLE into special ELF sections inside foo.o and bar.o. The final invocation reads the GIMPLE bytecode from foo.o and bar.o, merges the two files into a single internal image, and compiles the result as usual. Since both foo.o and bar.o are merged into a single image, this causes all the interprocedural analyses and optimizations in GCC to work across the two files as if they were a single one. This means, for example, that the inliner is able to inline functions in bar.o into functions in foo.o and vice-versa.
如文档所述,是的,全部!优化是因为程序被编译在一个文件中。这也可以用 -fwhole-program
来完成以获得 "same" 优化结果。
如果你编译这个非常简单的例子:
f1.cpp:
int f1() { return 10; }
f2.cpp:
int f2(int i) { return 2*i; }
main.cpp:
int main()
{
int res=f1();
res=f2(res);
res++;
return res;
}
我得到了汇编输出:
00000000004005e0 <main>:
4005e0: b8 15 00 00 00 mov [=14=]x15,%eax
4005e5: c3 retq
4005e6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4005ed: 00 00 00
所有代码都按预期内联。
我的经验是,实际的 gcc 使用 lto 进行优化,就像在单个文件中编译一样。在极少数情况下,我在使用 lto 时得到了 ICE。但是真正的 5.2.0 版本我再也没有看到任何 ICE。
[ICE]-> 内部编译器错误
在编译翻译单元时,编译器会进行大量优化 - 内联、常量 folding/propagation、别名分析、循环展开、死代码消除以及许多我什至从未听说过的其他优化。 在多个翻译单元之间使用 LTO/LTCG/WPO 时是否全部完成,或者只是完成了其中的一个子集(或变体)(我听说过内联)? 如果没有完成所有优化,我会考虑 unity 构建优于 LTO(或者当有超过 1 个 unity 源文件时可能同时使用它们)。
我的猜测是它不一样(统一构建具有全套优化)并且它在不同编译器之间差异很大。
各个编译器关于 lto 的文档并没有准确回答这个问题(或者我没理解)。
由于 lto 涉及在目标文件中保存中间表示,理论上 LTO 可以进行所有优化...对吗?
请注意,我不是在询问构建速度 - 这是一个单独的问题。
编辑: 我最感兴趣的是 gcc/llvm.
如果您查看 gcc 文档,您会发现:
-flto[=n]
This option runs the standard link-time optimizer. When invoked with source code, it generates GIMPLE (one of GCC's internal representations) and writes it to special ELF sections in the object file. When the object files are linked together, all the function bodies are read from these ELF sections and instantiated as if they had been part of the same translation unit.
To use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link. For example:
gcc -c -O2 -flto foo.c
gcc -c -O2 -flto bar.c
gcc -o myprog -flto -O2 foo.o bar.o
The first two invocations to GCC save a bytecode representation of GIMPLE into special ELF sections inside foo.o and bar.o. The final invocation reads the GIMPLE bytecode from foo.o and bar.o, merges the two files into a single internal image, and compiles the result as usual. Since both foo.o and bar.o are merged into a single image, this causes all the interprocedural analyses and optimizations in GCC to work across the two files as if they were a single one. This means, for example, that the inliner is able to inline functions in bar.o into functions in foo.o and vice-versa.
如文档所述,是的,全部!优化是因为程序被编译在一个文件中。这也可以用 -fwhole-program
来完成以获得 "same" 优化结果。
如果你编译这个非常简单的例子:
f1.cpp:
int f1() { return 10; }
f2.cpp:
int f2(int i) { return 2*i; }
main.cpp:
int main()
{
int res=f1();
res=f2(res);
res++;
return res;
}
我得到了汇编输出:
00000000004005e0 <main>:
4005e0: b8 15 00 00 00 mov [=14=]x15,%eax
4005e5: c3 retq
4005e6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4005ed: 00 00 00
所有代码都按预期内联。
我的经验是,实际的 gcc 使用 lto 进行优化,就像在单个文件中编译一样。在极少数情况下,我在使用 lto 时得到了 ICE。但是真正的 5.2.0 版本我再也没有看到任何 ICE。
[ICE]-> 内部编译器错误