the*_*ejh 11 c++ optimization gcc
gcc在我传递-O2
标志时优化代码,但是我想知道如果我将所有源文件编译为目标文件然后再将它们链接起来,它实际上能做到多少.
这是一个例子:
// in a.h
int foo(int n);
// in foo.cpp
int foo(int n) {
return n;
}
// in main.cpp
#include "a.h"
int main(void) {
return foo(5);
}
// code used to compile it all
gcc -c -O2 foo.cpp -o foo.o
gcc -c -O2 main.cpp -o main.o
gcc -O2 foo.o main.o -o executable
Run Code Online (Sandbox Code Playgroud)
通常情况下,gcc应该内联,foo
因为它是一个很小的功能并-O2
启用-finline-small-functions
,对吧?但是在这里,gcc只能在创建目标文件之前看到代码foo
和main
独立代码,所以不会有这样的优化,对吧?那么,像这样的编译真的会让代码更慢吗?
但是,我也可以像这样编译它:
gcc -O2 foo.cpp main.cpp -o executable
Run Code Online (Sandbox Code Playgroud)
会更快吗?如果没有,这样会更快吗?
// in foo.cpp
int foo(int n) {
return n;
}
// in main.cpp
#include "foo.cpp"
int main(void) {
return foo(5);
}
Run Code Online (Sandbox Code Playgroud)
编辑:我看了看objdump
,它的反汇编代码显示只有这个#include "foo.cpp"
东西有效.
您似乎已经自行重新发现了C和C++使用的单独编译模型的问题.虽然它确实简化了内存需求(这在创建时很重要),但它只通过向编译器公开最少的信息来实现,这意味着无法执行某些优化(如此).
较新的语言及其模块系统可以根据需要公开尽可能多的信息,如果模块进入下一版本的C++,我们希望能够获得这些好处......
与此同时,最简单的方法是链接时优化.我们的想法是,您将在每个TU(翻译单元)上执行尽可能多的优化以获取目标文件,但您还将使用IR(中间表示)丰富传统目标文件(包含程序集),编译器使用它来优化)部分或全部功能.
当调用链接器将这些目标文件合并在一起时,它不是仅将文件合并在一起,而是合并IR表示,重新执行一些优化传递(常量传播,内联,......),然后在其上创建汇编.拥有.这意味着它不仅仅是一个链接器,它实际上是一个后端优化器.
当然,像所有优化过程一样,这会产生成本,因此需要更长的编译时间.此外,这意味着编译器和链接器都应该传递一个特殊选项来触发此行为,在gcc的情况下,它将是-lto
或-O4
.