来自Wikipedia 上的优化编译器,
编译器优化通常使用一系列优化转换来实现,这些算法采用程序并对其进行转换,以生成使用较少资源的语义等效输出程序。
并且 GCC 有很多优化选项。
我想研究在使用不同标志(如, ,等-S
)编译时 GCC 执行的每次优化后生成的程序集(给出的程序集) 。-O1
-O2
-O3
我怎样才能做到这一点?
编辑:我的输入将是 C 代码。
gcc -S
(大写 S )
提供 asm 输出,但汇编器可以改变一些东西,所以我更喜欢只制作一个对象
gcc -c -o myfile.o myfile.c
然后拆卸
objdump -D myfile.o
了解这没有链接,因此外部分支目标和其他外部地址将具有占位符而不是实数。如果您想查看优化编译时没有优化 (-O0),然后使用 -O1 然后 -O2 和 -O3 编译,看看是否有任何变化。您还可以使用其他优化标志。要查看差异,您需要使用和不使用标志进行编译并自己比较差异。
diff 不起作用,您会看到原因(寄存器分配更改)。
虽然可以获取一小段代码,-S
并使用各种选项对其进行编译,但困难在于理解实际发生了什么变化。只需稍加改动即可使代码完全不同 - 一个变量进入寄存器意味着寄存器不再可用于某些东西,从而对函数中的所有剩余代码造成连锁反应。
我今天早些时候比较了两个几乎相同的函数的相同代码(关于 C++ 的一个问题),源代码有一个差异。在一个 for 循环中使用变量作为终止条件的一项更改导致了多行汇编代码更改。因为编译器决定以不同的方式排列寄存器,为一个主要变量使用不同的寄存器,然后其他所有内容都因此而改变。
我已经看到向函数添加小的更改将其从内联变为不内联的情况,这反过来又对调用该代码的程序中的所有代码进行了重大更改。
所以,是的,无论如何,用不同的优化编译非常简单的代码,并使用 -S 来检查编译器生成的代码。然后比较不同的变种,看看它有什么效果。但除非您习惯于阅读汇编代码,并了解您真正要寻找的内容,否则通常很难只见树木不见森林。
还值得考虑的是优化步骤通常协同工作——一个步骤允许另一个步骤完成它的工作(内联导致分支合并、寄存器使用等)。
gcc/clang 对中间表示 (IR) 执行优化,可以在每次优化通过后打印。
对于 gcc,它是 (-fdump-tree-all) ' http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html ',而它是 (-llvm -print-after-all)。
Clang/gcc 提供了更多选项来分析优化。从命令行打开/关闭优化很容易(http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html,http://llvm.org/docs /Passes.html )
使用 clang-llvm 您还可以列出使用命令行选项执行的优化通道 (-mllvm -debug-pass=Structure)
用 switch 编译-S
得到汇编代码。这应该适用于任何级别的优化。例如,要获取在O2
mode 中生成的汇编代码,请尝试:
g++/gcc -S -O2 input.cpp
input.s
将生成一个对应的,其中包含生成的汇编代码。对您想要的任何优化级别重复此操作。
gcc -O1 -S test.c(大写O和大写S)
这个网站也可以帮助你。您可以使用-O0
, -O1
, .. 任何合适的编译器选项来获得您想要的。
该站点的示例:(由两种解决方案测试)
void maxArray(double* x, double* y) {
for (int i = 0; i < 65536; i++) {
if (y[i] > x[i]) x[i] = y[i];
}
}
-O0
:结果:
maxArray(double*, double*):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -24(%rbp)
movq %rsi, -32(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L5:
movl -4(%rbp), %eax
cltq
leaq 0(,%rax,8), %rdx
movq -32(%rbp), %rax
addq %rdx, %rax
movsd (%rax), %xmm0
movl -4(%rbp), %eax
cltq
leaq 0(,%rax,8), %rdx
movq -24(%rbp), %rax
addq %rdx, %rax
movsd (%rax), %xmm1
ucomisd %xmm1, %xmm0
jbe .L3
movl -4(%rbp), %eax
cltq
leaq 0(,%rax,8), %rdx
movq -24(%rbp), %rax
addq %rax, %rdx
movl -4(%rbp), %eax
cltq
leaq 0(,%rax,8), %rcx
movq -32(%rbp), %rax
addq %rcx, %rax
movq (%rax), %rax
movq %rax, (%rdx)
.L3:
addl $1, -4(%rbp)
.L2:
cmpl $65535, -4(%rbp)
jle .L5
popq %rbp
ret
-O1
:结果:
maxArray(double*, double*):
movl $0, %eax
.L5:
movsd (%rsi,%rax), %xmm0
ucomisd (%rdi,%rax), %xmm0
jbe .L2
movsd %xmm0, (%rdi,%rax)
.L2:
addq $8, %rax
cmpq $524288, %rax
jne .L5
rep; ret
如果您想研究编译器优化并且对编译器不了解,请查看 Clang/LLVM 项目。Clang 是一个可以输出 LLVM IR 的 C 编译器,LLVM 命令可以单独应用特定的优化通道。
输出 LLVM IR:
clang test.c -S -emit-llvm -o test.ll
执行优化传递:
opt test.ll -<optimization_pass> -S -o test_opt.ll
编译到汇编:
llc test.ll -o test.s