理解 GCC 优化标志的细节
在本节中,我们将介绍 GCC 所提供的一些优化标志的更多细节。GCC 提供的优化标志非常多,完整列表超出了本书的范围。首先,我们将介绍开启较高级别优化指令 -O1
、-O2
和 -O3
时 GCC 启用的内容,感兴趣的读者可参考 GCC 官方手册进一步了解。
优化级别 -O1
-O1
是第一级优化,开启以下优化标志,旨在在不显著增加编译、链接和优化时间的前提下减少代码体积和执行时间。这是最基础但非常有效的优化等级,包含了我们在本章讨论过的多种优化技术。
几个重要的标志包括:
-fdce
和-fdse
:执行 死代码消除(DCE) 和 死存储消除(DSE)。-fdelayed-branch
:在许多架构中支持,尝试重排序指令以最大化流水线的吞吐。-fguess-branch-probability
:使用启发式方法猜测分支概率(当开发者未指定时)。-fif-conversion
与-fif-conversion2
:尝试将条件分支改写为无分支的等价代码。-fmove-loop-invariants
:启用循环不变代码外提优化。
完整标志列表(部分):
-fauto-inc-dec -fshrink-wrap -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-*(多个 inter-procedural 优化) -fmove-loop-invariants -fomit-frame-pointer -freorder-blocks
优化级别 -O2
-O2
是更高一级的优化等级,启用 -O1
中的所有标志,并增加了更多优化。会显著增加编译与链接时间,但提供更强的优化能力。
关键优化标志示例:
-falign-functions
、-falign-labels
、-falign-loops
:对函数、标签、循环的起始地址进行对齐,以提升处理器访问效率。-fdelete-null-pointer-checks
:认为解引用空指针是不安全的,进行相关优化(如常量折叠、移除空指针检查)。-fdevirtualize
和-fdevirtualize-speculatively
:尝试将虚函数调用转换为直接调用,从而允许更多内联优化。-fgcse
:启用全局公共子表达式消除(GCSE)与常量传播。-finline-functions
、-finline-small-functions
、-findirect-inlining
:增强内联函数的处理能力。
完整标志列表(部分):
-falign-* -fcaller-saves -fcode-hoisting -fcse-* -fdelete-null-pointer-checks -fdevirtualize -fexpensive-optimizations -ffinite-loops -fgcse -fhoist-adjacent-loads -finline-* -fipa-* -fschedule-insns -fstore-merging -ftree-*(多个 SSA/CFG 优化) -flra-remat -fvect-cost-model=very-cheap
优化级别 -O3
-O3
是 GCC 提供的最激进的优化等级。即使会导致可执行文件变大,只要性能更好,也会进行优化。
关键优化标志示例:
-fipa-cp-clone
:创建函数克隆,以增强跨过程常量传播和其他优化(牺牲空间换时间)。-fsplit-loops
:尝试将循环拆分,以避免循环中的条件判断。-funswitch-loops
:将循环中的不变条件判断移出循环体,减少分支。
完整标志列表(部分):
-fipa-cp-clone -fsplit-loops -funswitch-loops -floop-interchange -ftree-loop-distribution -floop-unroll-and-jam -ftree-partial-pre -fpeel-loops -fpredictive-commoning -fversion-loops-for-strides -fvect-cost-model=dynamic
一些额外的优化选项
静态链接(Static linkage)
通过 -l<library>
指定要链接的库,但如果系统上同时存在静态库(如 libfoo.a
)和共享库(如 libfoo.so
),可使用 -static
强制链接静态库。在低延迟应用中,优先选择静态链接更合适,因为它减少了运行时动态链接的开销。
指定目标架构
-march=<arch>
用于指定目标架构。例如 -march=native
表示使用当前编译器所在机器的架构。指定架构可以让编译器利用特定指令集,从而进行更有针对性的优化。
编译器警告选项
-Wall
、-Wextra
、-Wpedantic
:开启各种警告,检测潜在的错误或危险代码,建议大多数项目都启用。-Werror
:将所有警告视为错误,强制开发者修复代码中的潜在问题。
这些虽然不直接影响优化本身,但有助于识别会阻碍优化的低质量代码(如隐式类型转换、歧义表达式等)。
不安全的浮点优化(Unsafe Fast Math)
这一类优化涉及浮点运算的非标准处理,可能导致精度损失或错误的结果,使用前需格外小心。
启用 -ffast-math
后,会激活以下优化:
-fno-math-errno -funsafe-math-optimizations -ffinite-math-only -fno-rounding-math -fno-signaling-nans -fcx-limited-range -fexcess-precision=fast
这些优化允许编译器对浮点表达式应用更激进的优化策略,但不会在 -O1
、-O2
或 -O3
中自动启用,只适用于对浮点精度要求不高的场景。
系统当前共有 426 篇文章