我写了这个简单的C程序:
int main() {
int i;
int count = 0;
for(i = 0; i < 2000000000; i++){
count = count + 1;
}
}
我想查看gcc编译器如何优化这个循环(明显地,将1加2000000000次应该是“一次加上2000000000”)。所以:
gcc test.c 然后在 a.out
上使用 time
命令会得到:
real 0m7.717s
user 0m7.710s
sys 0m0.000s
$ gcc -O2 test.c然后运行time on
a.out`会得到:
real 0m0.003s
user 0m0.000s
sys 0m0.000s
然后我使用gcc -S
对两个文件进行反汇编。第一个文件看起来非常清晰:
.file "test.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, -8(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L3:
addl $1, -8(%rbp)
addl $1, -4(%rbp)
.L2:
cmpl $1999999999, -4(%rbp)
jle .L3
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
在L3中,对-4(%rbp)
进行加法操作,将结果与1999999999
进行比较,如果i < 2000000000
则跳转回L3。
现在进行了优化:
.file "test.c"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
rep
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
我完全不理解那里正在发生什么!我对汇编语言知之甚少,但我希望看到的是这样的:
addl $2000000000, -8(%rbp)
我甚至尝试使用gcc -c -g -Wa,-a,-ad -O2 test.c查看C代码和它被转换成的汇编代码,但结果并没有比之前更清晰。
可以有人简要解释一下:
- gcc -S -O2的输出是什么。
- 如果循环像我期望的那样进行优化(一个求和而不是多个求和)。