使用gcc,g++进行编译时,可在调用命令时添加参数,来控制编译器的行为,达到某种优化目的。
比如:
gcc -O2 -o test mytest.cpp
上面语句就是使用level 2优化级别来编译mytest.cpp文件。
编译器的优化通过参数可以控制,有多种配置。
如果没有指定优化选项,编译器就仅仅为了减少编译时间,并保证能正常调试。
这时每条语句都是独立的,就是说程序停在断点处,你可以更改变量值或改变程序计数器,使程序调到同函数的其他语句执行。而执行结果和代码保持一致。
一旦打开优化开关,编译器就会以增加编译时间和减少调试功能为代价,来提高程序运行性能或者减小目标程序大小。
编译器优化是因程序而异,当编译多个源文件输出一个程序文件时,编译器会根据所有文件的情况有针对性的来编译每一个文件。
不是所有的优化过程都是有开关控制的。我们只关注于开放给我们有开关选项的相关优化。
所以大部分的优化在没有设置“-O”选项,或者设定“-O0”时是关闭的,不过一些独立的开关还是可以生效。同样,“-Og”选项指定后,结果类似,很多编译优化也没有了。
使用“-O”选项可以指定优化级别,但根据不同的目标文件种类(比如x86,ARM不同平台的不同型号CPU)和GCC配置,优化实现会略有不同。若要找到确定的优化选项集合,可以执行GCC命令,并在命令行上加上选项:“-Q --help=optimizers”。
比如: gcc -O2 -Q --help=optimizers
上述命令就是显示优化level2的各优化选项开关情况。
各个优化级别的介绍:
-O
-O1
编译器优化后,增加编译时间,并处理大函数时会占用更大的内存。
优化结果,使得程序文件变小,执行时间变短。
Level1优化,不是执行需占用很多编译时间的优化操作。
此时打开的优化flag选项为:
-fauto-inc-dec
-fbranch-count-reg
-fcombine-stack-adjustments
-fcompare-elim
-fcprop-registers
。。。。。。
-O2
比O1优化更多。GCC会尽可能的引入不造成空间-时间(space-speed tradeoff,不为了降低执行时间而增大使用内存,或降低使用内存而增加执行时间)影响的优化。和没有优化相比,这选项增加了编译时间,同时提高了代码执行性能。
Level 2优化打开了所有Level 1打开的选项。另外增加了下面的选项:
-falign-functions
-falign-jumps
-falign-labels
-falign-loops
。。。。。。
请注意,当打开-fgcse时,因为使用了goto语句,所以可能会有编译警告。
-O3
比Level 2还要优化更多。Level 3除Level 2打开的选项以外,还会打开下面选项:
-fgcse-after-reload
-fipa-cp-clone
。。。。。。
-O0
单纯降低编译时间和保证调式功能正常。此为不指定优化选项时的默认选项。
-Os
降低目标文件大小(code size)的优化。除了会增加目标文件大小的选项外,所有的Level 2的选项都会打开。
还打开了-finline-functions选项,这样的调整会减小代码大小却增加执行时间;还有执行一些进一步的优化来降低目标文件大小。
-Ofast
无视严格的标准规范的优化。打开所有Level 3的优化选项,然后针对输出的目标文件还会做一些非标准兼容的优化。
-Og
针对调试体验的优化。此优化选项一般应用在开发阶段,编辑-编译-调试环节中使用。为了保证调试体验,保持快速的编译时间,而设置了这个level。对于生成可调式代码,此Level比-O0更合适,因为在-O0中一些收集调试信息的编译器操作(compiler passes)被禁用了。
类似-O0,-Og禁止了一些优化操作,所以这些优化选项再单独设置也不会起作用。
此外,-Og使能了所有的-O1的优化选项,除了那些会影响到调试的。
最后,如果你使用了多个-O选项,不管后面加不加数字,都只有最后一个生效。
除了上面介绍的优化级别,还有一些独立选项,供程序员来进一步微调程序,来达到某些特殊的优化目标。
比如:
-fno-defer-pop
-fforward-propagate
。。。。。。
注:
1,gcc命令后面的选项,"-f"前缀表示所设置的为flag。
2,主要参考:https://gcc.gnu.org/onlinedocs/gcc-11.1.0/gcc/Optimize-Options.html#Optimize-Options
3,上面使用的选项,-fflag,表示的使机器无关的开关。大部分都有打开和关闭两种方式:-ffoo和-fno-foo。