我用gcc -O3 -S a.c
编译了以下c程序:
#include <stdio.h>
int main() {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
printf("%d", sum);
}
生成的汇编代码如下:
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15, 4
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
leaq L_.str(%rip), %rdi
movl $5050, %esi ## imm = 0x13BA
xorl %eax, %eax
callq _printf
xorl %eax, %eax
popq %rbp
retq
.cfi_endproc
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "%d"
.subsections_via_symbols
就好像GCC运行了代码,注意到循环时间已经确定,并且GCC替换了整个计算结果为5050.
movl $5050, %esi
gcc是如何做这种优化的?这种优化的学名是什么?
我试图找到特定的标志,但没有运气。我只能用-O1
复制你的结果,所以我在那之后所做的是手动添加-O1
启用的所有标志。但是当我这样做的时候,我无法复制结果。
在文档
中可以读到不是所有的优化都是由一个标志直接控制的。本节只列出带有标志的优化。
所以我认为这是由-O1
添加的没有标记的东西完成的。
这是我尝试的:
$ gcc -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-profile
-fipa-pure-const -fipa-reference -fipa-reference-addressable
-fmerge-constants -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 -S k.c
cc1: warning: this target machine does not have delayed branches
$ grep "5050" k.s
$ gcc -O1 -S k.c
$ grep "5050" k.s
movl $5050, %esi
$
参考https://gcc.gnu.org/onlinedocs/gcc-4.5.2/gcc/Optimize-Options.html,循环展开(-funroll-loops
)和RTL上的正向传播传递(-fforward-propagate
)被启用,优化级别为-O
,-O2
,-O3
,-Os
。
可以试着添加-funroll-loops
和-fforward-propagate
来确认吗?