【-O1-O2-O3-Ofast...】C/C++编译器代码优化原理方案
因代码运行时的优化需要,特在此记录 【-O1-O2-O3-Ofast…】C/C++编译器代码优化原理方案。
-
如果不指定优化标识的话,gcc 就会产生可调试代码,每条指令之间将是独立的:可以在指令之间设置断点,使用 gdb 中的 p 命令查看变量的值、改变变量的值等。并且把获取最快的编译速度作为它的目标。
-
当优化标识被启用之后,gcc 编译器将会试图改变程序的结构(当然会在保证变换之后的程序与源程序语义等价的前提之下),以满足某些目标,如:代码大小最小 或 运行速度更快(只不过通常来说,这两个目标是矛盾的,二者不可兼得)。
在不同的 gcc 配置和目标平台下,同一个标识所采用的优化种类也是不一样的。
可以使用 -Q --help =optimizers
来获取每个优化标识所启用的优化选项。
以下的每个优化标识都可以在 原网址 中找到对应的详细解释。
-O,-O1
在不影响编译速度的前提下,尽量采用一些优化算法,降低可执行代码的大小。
-O2
牺牲部分编译速度,除了执行 -O1
所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以 提高目标代码的运行速度。
-O3
除了执行 -O2
所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度,利用现代 CPU 中的流水线、Cache等。这个选项会提高执行代码的大小,而可以 提高目标代码的运行速度。
由于 -O3
是以提高执行速度为目的来扩展代码大小,如增加内联等,但过度膨胀反而可能降低执行速度,故而在两者之间取得某种平衡。
其开启的优化选项如下:
-finline-functions
-funswitch-loops
-fpredictive-commoning
-fgcse-after-reload
-ftree-loop-vectorize
-ftree-loop-distribute-patterns
-fsplit-paths
-ftree-slp-vectorize
-fvect-cost-model
-ftree-partial-pre
-fpeel-loops
-fipa-cp-clone options
-Os
该优化标识和 -O3
的目的恰好相悖。
-Os
会在 -O2
的基础上尽量降低目标代码的大小,压缩代码空间,对嵌入式设备等存储容量小的设备较为重要。
为了降低目标代码大小,会禁用下列优化选项,一般就是压缩内存中的对齐空白1(alignment padding)。
-falign-functions
-falign-jumps
-falign-loops
-falign-labels
-freorder-blocks
-freorder-blocks-algorithm=stc
-freorder-blocks-and-partition
-fprefetch-loop-arrays
-Ofast
该优化标识将不会严格遵循语言标准,除了启用所有的 -O3
优化选项之外,也会针对某些语言启用部分优化。如:-ffast-math
等。
同时 -Ofast
也会牺牲标准兼容性,以获得更快的运行速度。
-Og
该优化标识会选择部分与 -g
选项不冲突的优化选项,以提供合理的优化水平,同时产生较优秀的可调试信息。
关于这些优化选项的应用实例之一,请见:
SPN实现——限时1000ms的代换-置换网络加解密的时间优化思路
启用的优化标识为:
#pragma GCC optimize(3,"Ofast","inline")
https://www.zhihu.com/question/27090458 ↩︎