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

时间:2013-03-05 14:44:36

标签: c optimization gcc assembly compiler-construction

来自维基百科上的Optimization Compiler

  

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

和GCC有lot个优化选项。

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

我该怎么做?

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

7 个答案:

答案 0 :(得分:7)

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

可以使用更细粒度的-fdump开关。

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

为了能够阅读这些表示,take a look into GCC internals manual

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

gcc -S资本S

给出了asm输出,但是汇编程序可以更改内容,所以我更喜欢只创建一个对象

gcc -c -o myfile.o myfile.c

然后反汇编

objdump -D myfile.o

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

diff不起作用,您将看到原因(寄存器分配更改)。

答案 3 :(得分:1)

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

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

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

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

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

答案 4 :(得分:1)

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.htmlhttp://llvm.org/docs/Passes.html

使用clang-llvm,您还可以列出使用命令行选项执行的优化过程(-mllvm -debug-pass = Structure)

答案 5 :(得分:0)

如果您想学习编译器优化并且与编译器无关,那么请查看Clang / LLVM项目。 Clang是一个可以输出LLVM的C编译器,IR和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

答案 6 :(得分:0)

解决方法1:

  

gcc -O1 -S test.c(首都O和大写S)

溶液2:

site也可以为您提供帮助。您可以使用-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