LTO中的优化是否与正常编译中的优化相同?

时间:2015-07-30 10:04:53

标签: c++ optimization compiler-construction g++ llvm

在编译翻译单元时,编译器正在进行大量优化 - 内联,常量折叠/传播,别名分析,循环展开,死代码消除以及我甚至都听不到的其他许多优化。 当在多个翻译单元之间使用LTO / LTCG / WPO时,是否所有这些都完成了,或者只是它们的子集(或变体)(我听说过内联)? 如果不是所有的优化都完成了,我会认为统一构建优于LTO(或者当有超过1个统一源文件时可以使用它们)。

我的猜测是它不一样(统一版本具有完整的优化集),并且它在编译器之间变化很大。

关于每个编译器的lto的文档并没有准确地回答这个问题(或者我没有理解它)。

由于lto涉及在理论上将中间表示保存在目标文件中,LTO可以进行所有优化......对吗?

请注意,我不是在询问构建速度 - 这是一个单独的问题。

修改: 我最感兴趣的是gcc / llvm。

1 个答案:

答案 0 :(得分:8)

如果你看一下你找到的gcc文档:

  

-flto [= N]

     

此选项运行标准链接时优化程序。当使用源代码调用时,它会生成GIMPLE(GCC的内部表示之一)并将其写入目标文件中的特殊ELF部分。当目标文件链接在一起时,所有函数体都从这些ELF部分读取并实例化,就好像它们是同一个翻译单元的一部分一样。

     

要使用链接时优化器,应在编译时和最终链接期间指定-flto和优化选项。例如:

          gcc -c -O2 -flto foo.c
          gcc -c -O2 -flto bar.c
          gcc -o myprog -flto -O2 foo.o bar.o
  

GCC的前两次调用将GIMPLE的字节码表示保存到foo.o和bar.o中的特殊ELF部分。最后的调用从foo.o和bar.o读取GIMPLE字节码,将两个文件合并为一个内部图像,并像往常一样编译结果。由于foo.o和bar.o都合并为单个图像,因此会导致GCC中的所有过程间分析和优化在两个文件中一起工作,就像它们是单个文件一样。这意味着,例如,内联器能够将bar.o中的函数内联到foo.o中的函数中,反之亦然。

正如文档所说,是的,全部!优化是指程序在单个文件中编译。这也可以通过-fwhole-program完成,以获得相同的"优化结果。

如果你编译这个非常简单的例子:

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    $0x15,%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] - GT;内部编译器错误