gcc优化技术
GCC优化技术简析
gcc优化等级从O0-O3(Os约为O2.5),每个等级都是在之前的优化基础上再进行优化
GCC O0
不做任何优化
GCC O1
defer-pop
这个优化应用在汇编层面上(后端优化),一般情况下, 函数的输入值被保存在堆栈中并且被函数访问,函数返回之后,输入值被立即弹出堆栈。这个选项允许函数返回时, 输入值还在堆栈中。等到多个函数调用后,一起弹出
merge-constans
合并相同的常量(即常量折叠)
thread-jumps
合并连续的jump为一个jump
loop-optimize
循环不变量外提
if-conversion
通过减少或者删除条件分支, 以及使用条件传送,设置标志和使用运算技巧来替换他们, 编译
器可以减少if-then语句中花费的时间量。
if-conversion2
if-conversion的基础上结合更高的数学特性
delayed-branch
试图根据指令周期时间重新安排指令。 它还试图把尽可能多的指令移动到条件分支前, 以便最充分的利用处理器的延迟槽。
guess-branch-probability
试图确定条件分支最可能的结果, 并且相应的移动指令, 这和延迟分支技术类似。
cprop-registers(没太看懂)
因为在函数中把寄存器分配给变量, 所以编译器执行第二次检查以便减少调度依赖性(两个段要求使用相同的寄存器)并且删除不必要的寄存器复制操作。
GCC O2
force-mem(没太看懂)
在做算术操作前,强制将内存数据copy到寄存器中以后再执行。这会使所有的内存引用潜在的共同表达式,进而产出更高效的代码。
optimize-sibling-calls
递归函数展开
strength-reduce
这种优化技术对循环执行优化并且删除迭代变量。 迭代变量是捆绑到循环计数器的变量, 比如使用变量, 然后使用循环计数器变量执行数学操作的for-next循环。
cse-follow-jumps+cse-skip-blocks
感觉可以大致理解为SVN(比LVN强,比GVN弱)
rerun-cse-after-loop
循环优化后再跑公共子表达式消除
rerun-loop-opt
再跑一遍循环优化
gcse
全局公共子表达式删除
gcse-lm
全局子表达式+试图将循环内部的load移至循环外,在循环内使用move/store
gcse-sm
试图将循环内部的store移到循环外
gcse-las
试图消除store后面不必要的load(同一块内存区域)
delete-null-pointer-checks
通过数据流分析,删除无用的对空指针的检查
expensive-optimizations
具体不是很清楚()
regmove
编译器试图重新分配move指令或者其他类似操作数等简单指令的寄存器数目,以便最大化的捆绑寄存器的数目。这种优化尤其对双操作数指令的机器帮助较大。
schedule-insns
编译器尝试重新排列指令,用以消除由于等待未准备好的数据而产生的延迟。这种优化将对慢浮点运算的机器以及需要load memory的指令的执行有所帮助,因为此时允许其他指令执行,直到load memory的指令完成,或浮点运算的指令再次需要cpu。
schedule-insns2
与-fschedule-insns相似。但是当寄存器分配完成后,会请求一个附加的指令计划pass。这种优化对寄存器较小,并且load memory操作时间大于一个时钟周期的机器有非常好的效果。
sched-interblock
编译器能够跨越指令块调度指令。 这可以非常灵活地移动指令以便等待期间完成的工作最大化。
sched-spec-load
允许一些load指令进行一些投机性的动作。(具体不详)相同功能的还有-fsched-spec-load-dangerous,允许更多的load指令进行投机性操作。这两个选项在选中-fschedule-insns时默认打开。
peephole2
这个选项允许进行任何计算机特定的窥孔优化。
caller-saves
这个选项指示编译器对函数调用保存和恢复寄存器, 使函数能够访问寄存器值, 而且不必保存和恢复他们。 如果调用多个函数, 这样能够节省时间, 因为只进行一次寄存器的保存和恢复操作, 而不是在每个函数调用中都进行。
reorder-blocks
这种优化技术允许重新安排指令块以便改进分支操作和代码局部性。
crossjumping
这是对跨越跳转的转换代码处理, 以便组合分散在程序各处的相同代码。 这样可以减少代码的长度, 但是也许不会对程序性能有直接影响。
unit-at-a-time
这种优化技术指示编译器在运行优化例程之前读取整个汇编语言代码。 这使编译器可以
重新安排不消耗大量时间的代码以便优化指令缓存。 但是, 这会在编译时花费相当多的内存, 对于小型计算机可能
是一个问题。
GCC O3
inline-functions
函数内联
rename-registers
在寄存器分配后,通过使用registers left over来避免预定代码中的虚假依赖。这会使调试变得非常困难,因为变量不再存放于原本的寄存器中了。
align-functions
这个选项用于使函数对准内存中特定边界的开始位置。 大多数处理器按照页面读取内存,并且确保全部函数代码位于单一内存页面内, 就不需要叫化代码所需的页面。
align-jumps
对齐分支代码到2的n次方边界。在这种情况下,无需执行傀儡指令(dummy operations)
align-loops
对齐循环到2的n次幂边界。期望可以对循环执行多次,用以补偿运行dummy operations所花费的时间。
align-labels
对齐分支到2的n次幂边界。这种选项容易使代码速度变慢,原因是需要插入一些dummy operations当分支抵达usual flow of the code.