在GCC进行的每次优化后获取汇编代码?

来自维基百科上的优化编译器 ,

编译器优化通常使用一系列优化转换来实现 ,这些算法采用程序并对其进行转换以生成使用较少资源的语义上等效的输出程序。

和GCC有很多优化选择。

我想在使用不同的标志(如-O1-O2-O3等)进行编译时执行每次优化后,研究生成的程序集(一个-S给出)。

我怎样才能做到这一点?

编辑:我的输入将是C代码。

可以使用-fdump-tree-all开关将中间表示保存到文件中。

有更多细粒度的-fdump开关可用。

有关详细信息,请参阅gcc手册

为了能够阅读这些表示, 请查看GCC内部手册 。

虽然可以使用一小段代码,使用-S和各种选项进行编译,但难以理解实际改变的内容。 只需要进行一些小改动就可以使代码完全不同 – 一个变量进入寄存器意味着寄存器不再可用于某些东西,从而对函数中的所有剩余代码造成连锁效应。

我正在比较今天早些时候两个几乎相同的函数中的相同代码(与C ++上的问题有关),并且源代码中存在一个区别。 在一个for循环中使用哪个变量用于终止条件的一个变化导致过多的汇编代码行改变。 因为编译器决定以不同的方式排列寄存器,对其中一个主变量使用不同的寄存器,然后其他所有内容都会发生变化。

我见过这样的情况:在函数中添加一个小的更改会将其从内联移动到不内联,这反过来会对调用该代码的程序中的所有代码进行大的更改。

所以,是的,无论如何,编译具有不同优化的非常简单的代码,并使用-S来检查编译器生成的代码。 然后比较不同的变体,看看它有什么效果。 但是,除非您习惯于阅读汇编代码,并了解您实际需要的内容,否则通常很难看到森林中的树木。

同样值得考虑的是,优化步骤通常协同工作 – 一步允许另一步骤完成其工作(内联导致分支合并,寄存器使用等)。

使用开关-S编译以获取汇编代码。 这适用于任何级别的优化。 例如,要获取在O2模式下生成的汇编代码,请尝试:

  g++/gcc -S -O2 input.cpp 

将生成相应的input.s ,其中包含生成的汇编代码。 对所需的任何优化级别重复此操作。

gcc / clang对中间表示(IR)执行优化,可以在每次优化传递后打印。

对于gcc它是(-fdump-tree-all)’ http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html ‘与clang它是(-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)

gcc -SCapital S

给出了asm输出,但汇编程序可以改变一些东西,所以我更喜欢只创建一个对象

gcc -c -o myfile.o myfile.c

然后拆卸

objdump -D myfile.o

了解这没有链接,因此外部分支目的地和其他外部地址将具有占位符而不是实数。 如果你想看到没有优化的编译优化(-O0),那么用-O1然后-O2和-O3编译,看看有什么变化。 您还可以使用其他优化标志。 要查看使用和不使用标志进行编译所需的差异,并自己比较差异。

diff将无法正常工作,您将看到原因(寄存器分配更改)。

如果您想学习编译器优化并且与编译器无关,那么请查看Clang / LLVM项目。 Clang是一个可以输出LLVM的C编译器IR和LLVM命令可以单独应用特定的优化传递。

输出LLVM IR:

 clang test.c -S -emit-llvm -o test.ll 

执行优化传递:

 opt test.ll - -S -o test_opt.ll 

编译到汇编:

 llc test.ll -o test.s 

解决方法1:

gcc -O1 -S test.c(首都O和资本S)

溶液2:

这个网站也可以帮到你。 您可以使用-O0-O1 ,..任何合适的编译器选项来获得您想要的。

该站点的示例:(由两个解决方案测试)

  void maxArray(double* x, double* y) { for (int i = 0; i < 65536; i++) { if (y[i] > x[i]) x[i] = y[i]; } } 
  • Compier选项-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