12

来自Wikipedia 上的优化编译器,

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

并且 GCC 有很多优化选项。

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

我怎样才能做到这一点?

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

4

7 回答 7

9

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

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

详见 gcc 手册。

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

于 2013-03-05T15:25:43.337 回答
2

gcc -S(大写 S )

提供 asm 输出,但汇编器可以改变一些东西,所以我更喜欢只制作一个对象

gcc -c -o myfile.o myfile.c

然后拆卸

objdump -D myfile.o

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

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

于 2013-03-05T15:05:06.757 回答
1

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

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

我已经看到向函数添加小的更改将其从内联变为不内联的情况,这反过来又对调用该代码的程序中的所有代码进行了重大更改。

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

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

于 2013-03-05T16:24:09.043 回答
1

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

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

于 2013-03-07T08:34:24.933 回答
1

用 switch 编译-S得到汇编代码。这应该适用于任何级别的优化。例如,要获取在O2mode 中生成的汇编代码,请尝试:

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

input.s将生成一个对应的,其中包含生成的汇编代码。对您想要的任何优化级别重复此操作。

于 2013-03-05T14:49:26.623 回答
0

解决方案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];
    }
 }
  • 编译器选项 -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
于 2014-08-03T01:50:10.043 回答
0

如果您想研究编译器优化并且对编译器不了解,请查看 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
于 2013-03-05T15:22:09.843 回答