【问题标题】:Get Assembly code after every optimization GCC makes?每次 GCC 进行优化后获取汇编代码?
【发布时间】:2013-02-20 00:33:35
【问题描述】:

来自维基百科上的Optimization Compiler

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

而且 GCC 有一个 lot 的优化选项。

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

我该怎么做?

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

【问题讨论】:

  • 优化不适用于汇编代码,但适用于中间表示。
  • 为了回复您的临时评论,在应用优化 O2 之前刚刚应用优化 O1 的程序集在任何时候都不存在。如果你想看汇编,你所能做的就是在 O1 之后完成编译而不做进一步的优化。这可能是您所追求的,但它不是“每次优化后生成的程序集 [...]”,同样,它不存在。或者,您可以学习如何破译中间表示,您将确实能够看到优化生效。
  • @PascalCuoq,是的,这就是我想要的,抱歉我不清楚。我想在应用优化后获得 IR 的每个状态的 ASM 输出。 (我希望我的条款是正确的。)
  • 实际上,窥孔优化器确实会在该级别(程序集/指令)进行优化,以实现在通用(非目标特定)IR 级别上无法进行的优化。
  • -fdump-tree-all 应该转储中间表示。

标签: c optimization gcc assembly compiler-construction


【解决方案1】:

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

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

详见 gcc 手册。

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

【讨论】:

  • 你能给我一个关于“细粒度-fdump”开关的链接吗?我搜索它但没有找到。
  • 这里:gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/…。搜索 fdump。
  • 非常感谢。我搜索了“-fdump”和“-fdump gcc”,但没有找到。只是一个字符!再次感谢。
  • 如果您在 google.com 中搜索编译器选项,请确保省略前导连字符...
【解决方案2】:

gcc -S大写S

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

gcc -c -o myfile.o myfile.c

然后拆机

objdump -D myfile.o

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

diff 不起作用,你会明白为什么(寄存器分配改变)。

【讨论】:

  • 我使用objdump -D myfile.o,但它说'文件格式无法识别'?
【解决方案3】:

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

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

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

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

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

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

    • 请阅读我上面对这个问题的评论。我想在每个优化 O2(例如)执行后获取汇编代码。
    • @Dogbert -O2 启用一组优化开关。您可以通过打开和关闭每个来比较结果。但恐怕这是你能做的最好的了。您不能在每个要优化的转换 之后抑制优化。 (基本上你永远不能在这里完全定义 each。所有这些优化方法都是迭代调用的。因为一个优化可能会启用另一个优化。所以在关闭一个之后,所有基于该优化的后续优化都将被抑制为.)
    • @Dogbert 例如,您可以使用不同的标志进行编译并将输出与差异进行比较。
    • 我相信你的意思是-S,而不是-s
    【解决方案5】:

    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) 执行的优化过程

    【讨论】:

      【解决方案6】:

      如果您想研究编译器优化并且对编译器不了解,请查看 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
      

      【讨论】:

        【解决方案7】:

        解决方案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];
            }
         }
        
        • 编译器选项-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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-25
          • 1970-01-01
          • 2013-07-24
          • 2013-01-22
          • 1970-01-01
          • 2013-04-11
          • 2011-12-16
          • 1970-01-01
          相关资源
          最近更新 更多