【Linux】gcc优化选项剖析

一、概述

-O0 :默认值,不加-On
-O1 :或 -O,优化栈退出、线程跳转、减少代码长度和执行时间;
-O2 :O1 + CPU指令调度和调整;
-O3 :O2 + 循环展开,CPU特性优化;
-Os :针对size进行优化,适用于代码空间有限的场景,比如fsbl

二、具体信息

1. O0

Minimum optimization. Turns off most optimizations.It gives the best possible debug view and the lowest level of optimization
如果出现调试时在源码行无法设置断点,一般就是因为该行代码被优化了。如果一定要调试这时候可以改成O0
特点:最少的优化,可以最大程度上配合产生代码调试信息,可以在任何代码行打断点

2. O1

Restricted optimization. Removes unused inline functions and unused static functions. Turns off optimizations that seriously degrade the debug view. If used with --debug, this option gives a satisfactory debug view with good code density
最基本的优化等级。不花费太多编译时间,同时试图生成更快更小的代码。移除未调用的内联函数和静态函数等

特点:有限的优化,去除无用的inline和无用的static函数、死代码消除等,在影响到调试信息的地方均不进行优化。在适当的代码体积和充分的调试之间平衡,代码编写阶段最常用的优化等级。

增加的优化有以下这些
-fauto-inc-dec
-fbranch-count-reg
-fcombine-stack-adjustments
-fcompare-elim
-fcprop-registers
-fdce
-fdefer-pop
-fdelayed-branch
-fdse
-fforward-propagate
-fguess-branch-probability
-fif-conversion
-fif-conversion2
-finline-functions-called-once
-fipa-modref
-fipa-profile
-fipa-pure-const
-fipa-reference
-fipa-reference-addressable
-fmerge-constants
152 Using the GNU Compiler Collection (GCC)
-fmove-loop-invariants
-fomit-frame-pointer
-freorder-blocks
-fshrink-wrap
-fshrink-wrap-separate
-fsplit-wide-types
-fssa-backprop
-fssa-phiopt
-ftree-bit-ccp
-ftree-ccp
-ftree-ch
-ftree-coalesce-vars
-ftree-copy-prop
-ftree-dce
-ftree-dominator-opts
-ftree-dse
-ftree-forwprop
-ftree-fre
-ftree-phiprop
-ftree-pta
-ftree-scev-cprop
-ftree-sink
-ftree-slsr
-ftree-sra
-ftree-ter
-funit-at-a-time

比较重要的优化如下

1)-fdefer-pop

-fdefer-pop: 这种优化技术与汇编语言代码在函数完成时如何进行操作有关。 一般情况下, 函数的输入值被保存在堆栈中并且被函数访问。 优化后函数返回之后, 输入值被立即弹出堆栈

2)-fif-conversion

-fif-conversion: if-then语句应该是应用程序中仅次于循环的最消耗时间的部分。简单的if-then语句可能在最终的汇编语言代码中产生众多的条件分支。 通过减少或者删除条件分支, 以及使用条件传送 设置标志和使用运算技巧来替换他们, 编译器可以减少if-then语句中花费的时间量。

3)-fif-conversion2

-fif-conversion2: 这种技术结合更加高级的数学特性, 减少实现if-then语句所需的条件分支。

4)-fdelayed-branch

-fdelayed-branch: 这种技术试图根据指令周期时间重新安排指令。 它还试图把尽可能多的指令移动到条件分支前, 以便最充分的利用处理器的治理缓存。

5)-fguess-branch-probability

-fguess-branch-probability: 就像其名称所暗示的, 这种技术试图确定条件分支最可能的结果, 并且相应的移动指令, 这和延迟分支技术类似。 因为在编译时预测代码的安排,所以使用这一选项两次编译相同的c或者c++代码很可能会产生不同的汇编语言代码, 这取决于编译时编译器认为会使用那些分支。 因为这个原因, 很多程序员不喜欢采用这个特性, 并且专门地使用-fno-guess-branch-probability选项关闭这个特性

6)-fcprop-registers

-fcprop-registers: 因为在函数中把寄存器分配给变量, 所以编译器执行第二次检查以便减少调度依赖性(两个段要求使用相同的寄存器)并且删除不必要的寄存器复制操作

7)-freorder-blocks

-freorder-blocks: 这种优化技术允许重新安排指令块以便改进分支操作和代码局部性。

8)-funit-at-a-time

-funit-at-a-time: 这种优化技术指示编译器在运行优化例程之前读取整个汇编语言代码。 这使编译器可以
重新安排不消耗大量时间的代码以便优化指令缓存。 但是, 这会在编译时花费相当多的内存, 对于小型计算机可能是一个问题。

9)其他优化

-fmerge-constans: 使用这种优化技术, 编译器试图合并相同的常量. 这一特性有时候会导致很长的编译时间, 因为编译器必须分析c或者c++程序中用到的每个常量,并且进行比较.

-fthread-jumps: 使用这种优化技术与编译器如何处理汇编代码中的条件和非条件分支有关。 在某些情况下, 一条跳转指令可能转移到另一条分支语句。 通过一连串跳转, 编译器确定多个跳转之间的最终目标并且把第一个跳转重新定向到最终目标

-floop-optimize: 通过优化如何生成汇编语言中的循环, 编译器可以在很大程序上提高应用程序的性能。 通常, 程序由很多大型且复杂的循环构成。 通过删除在循环内没有改变值的变量赋值操作, 可以减少循环内执行指令的数量, 在很大程度上提高性能。 此外优化那些确定何时离开循环的条件分支, 以便减少分支的影响。

3. O2

High optimization. If used with --debug, the debug view might be less satisfactory because the mapping of object code to source code is not always clear. This is the default optimization level.

O1的进阶,推荐的优化等级,除非有特殊的需求。-O2会比-O1启用多一些标记。设置了-O2后,编译器会试图提高代码性能,而不会增大体积和大量占用编译时间

特点:高度优化,调试信息不友好,有可能会修改代码和函数调用执行流程,自动对函数进行内联等。

优化选项
-falign-functions -falign-jumps
-falign-labels -falign-loops
-fcaller-saves
-fcode-hoisting
-fcrossjumping
-fcse-follow-jumps -fcse-skip-blocks
-fdelete-null-pointer-checks
-fdevirtualize -fdevirtualize-speculatively
-fexpensive-optimizations
-ffinite-loops
-fgcse -fgcse-lm
-fhoist-adjacent-loads
-finline-functions
-finline-small-functions
-findirect-inlining
-fipa-bit-cp -fipa-cp -fipa-icf
-fipa-ra -fipa-sra -fipa-vrp
-fisolate-erroneous-paths-dereference
-flra-remat
-foptimize-sibling-calls
-foptimize-strlen
-fpartial-inlining
-fpeephole2
-freorder-blocks-algorithm=stc
-freorder-blocks-and-partition -freorder-functions
-frerun-cse-after-loop
-fschedule-insns -fschedule-insns2
-fsched-interblock -fsched-spec
-fstore-merging
-fstrict-aliasing
-fthread-jumps
-ftree-builtin-call-dce
-ftree-pre
-ftree-switch-conversion -ftree-tail-merge
-ftree-vrp

1)-foptimize-sibling-calls

-foptimize-sibling-calls: 这种技术能处理递归函数调用。 通常, 递归的函数调用可以被展开为一系列一般的指令, 而不是使用分支。 这样处理器的指令缓存能够加载展开的指令并且处理他们, 和指令保持为需要分支操作的单独函数调用相比, 这样更快。

2)-fgcse

-fgcse: 这种技术对生成的所有汇编语言代码执行全局通用表达式消除。 这些优化操作试图分析生成的汇编语言代码并且结合通用片段, 消除冗余的代码段。如果代码使用计算性的goto, gcc指令推荐使用-fno-gcse选项。

3)-fcse-follow-jumps

-fcse-follow-jumps: 这种特别的通用子表达式消除技术扫描跳转指令, 查找程序中通过任何其他途径都不
会到达的目标代码。 这种情况最常见的例子就式if-then-else语句的else部分。

4)-frerun-cse-after-loop

-frerun-cse-after-loop: 这种技术在对任何循环已经进行过优化之后重新运行通用子表达式消除例程。
这样确保在展开循环代码之后更进一步地优化汇编代码。

5)-fdelete-null-pointer-checks

-fdelete-null-pointer-checks: 这种优化技术扫描生成的汇编语言代码, 查找检查空指针的代码。编译
器假设间接引用空指针将停止程序。 如果在间接引用之后检查指针, 它就不可能为空。

6)-fschedule-insns

-fschedule-insns: 编译器将试图重新安排指令, 以便消除等待数据的处理器。 对于在进行浮点运算时有
延迟的处理器来说, 这使处理器在等待浮点结果时可以加载其他指令。

7)-fsched-interblock

-fsched-interblock: 这种技术使编译器能够跨越指令块调度指令。 这可以非常灵活地移动指令以便等待
期间完成的工作最大化。

8)-fcaller-saves

-fcaller-saves: 这个选项指示编译器对函数调用保存和恢复寄存器, 使函数能够访问寄存器值, 而且不必
保存和恢复他们。 如果调用多个函数, 这样能够节省时间, 因为只进行一次寄存器的保存和恢复操作, 而
不是在每个函数调用中都进行。

9)-fpeephole2

-fpeephole2: 这个选项允许进行任何计算机特定的观察孔优化。

10)-fstrict-aliasing

-fstrict-aliasing: 这种技术强制实行高级语言的严格变量规则。 对于c和c++程序来说, 它确保不在数据
类型之间共享变量. 例如, 整数变量不和单精度浮点变量使用相同的内存位置。

11)-falign-functions

-falign-functions: 这个选项用于使函数对准内存中特定边界的开始位置。大多数处理器按照页面读取内存,并且确保全部函数代码位于单一内存页面内, 就不需要切换代码所需的页面。

12)-fcrossjumping

-fcrossjumping: 这是对跨越跳转的转换代码处理, 以便组合分散在程序各处的相同代码。 这样可以减少
代码的长度, 但是也许不会对程序性能有直接影响。

13)-finline-functions

-finline-functions: 这种优化技术不为函数创建单独的汇编语言代码,而是把函数代码包含在调度程序的
代码中。 对于多次被调用的函数来说, 为每次函数调用复制函数代码。 虽然这样对于减少代码长度不利, 但是通过最充分的利用指令缓存代码, 而不是在每次函数调用时进行分支操作, 可以提高性能。

14)其他优化

-fforce-mem: 这种优化在任何指令使用变量前, 强制把存放在内存位置中的所有变量都复制到寄存器
中。 对于只涉及单一指令的变量, 这样也许不会有很大的优化效果. 但是对于在很多指令(必须数学操作)
中都涉及到的变量来说, 这是很显著的优化, 因为和访问内存中的值相比 ,处理器访问寄存器中的值要
快得多。

-fstrength-reduce: 这种优化技术对循环执行优化并且删除迭代变量。 迭代变量是捆绑到循环计数器
的变量, 比如使用变量, 然后使用循环计数器变量执行数学操作的for-next循环。

-fextensive-optimizations: 这种技术执行从编译时的角度来说代价高昂的各种优化技术,但是它可能
对运行时的性能产生负面影响。

-fregmove: 编译器试图重新分配mov指令中使用的寄存器, 并且将其作为其他指令操作数, 以便最大化
捆绑的寄存器的数量。

4. O3

Maximum optimization. -O3 performs the same optimizations as -O2 however the balance between space and time optimizations in the generated code is more heavily weighted towards space or time compared with -O2.

最高最危险的优化等级。用这个选项会延长编译代码的时间,生成的代码只是比-O2快一点,但会大大增加不可预知的程序行为

特点:最大程度优化,产生极少量的调试信息。会进行更多代码优化,例如循环展开、更激进的函数内联等。

可以通过单独设置 --loop_optimization_level=option 来控制循环展开的优化等级

增加了以下选项
-fgcse-after-reload
-fipa-cp-clone -floop-interchange
-floop-unroll-and-jam
-fpeel-loops
-fpredictive-commoning
-fsplit-loops
-fsplit-paths
-ftree-loop-distribution
-ftree-loop-vectorize
-ftree-partial-pre
-ftree-slp-vectorize
-funswitch-loops
-fvect-cost-model
-fvect-cost-model=dynamic
-fversion-loops-for-strides

5. Os

Os与O2相同,在此基础上增加了对大小优化的选项
‘-Os’ enables all ‘-O2’ optimizations except those that often increase code size:
-falign-functions -falign-jumps
-falign-labels -falign-loops
-fprefetch-loop-arrays -freorder-blocks-algorithm=stc

It also enables ‘-finline-functions’, causes the compiler to tune for code
size rather than execution speed, and performs further optimizations designed
to reduce code size.

这个等级用来优化代码尺寸。其中启用了-O2中不会增加磁盘空间占用的代码生成选项。这对于磁盘空间极其紧张或者CPU缓存较小的机器非常有用。但也可能产生些许问题,一般是针对启动引导程序等有明确大小要求程序进行优化

三、参考资料

更详细的说明请参考官网的手册
https://gcc.gnu.org/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值