2013-03-05 117 views
10

Optimization Compiler维基百科上,GCC进行每次优化后获取汇编代码?

编译器优化使用优化转换,其采取的程序并将其转换以产生使用较少的资源语义上等价的输出程序的算法的一个序列通常实现。

和GCC有lot的优化选项。

我想学习生成的程序集(一-S给出),每个优化GCC后,用不同的标志像编译时执行-O1-O2-O3

我怎样才能做到这一点?

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

+3

进行的优化不能施加到汇编代码,而是中间表示。 – 2013-03-05 14:46:26

+0

要回复您的瞬态评论,在优化O2应用之前刚刚应用了优化O1的程序集在任何时候都不存在。如果你想看汇编,你所能做的就是在O1之后没有进一步优化的情况下完成编译。这可能是你之后的事情,但它不是“每次优化后生成的程序集”,而这又不存在。或者,您可以学习如何解译中间表示,您将在其中确实能够看到优化生效。 – 2013-03-05 14:51:13

+0

@PascalCuoq,是的,这就是我想要的,对不起,我不清楚。我想在应用优化之后为每个IR状态获得ASM输出。 (我希望我能够正确地理解这些条款。) – Dogbert 2013-03-05 14:53:16

回答

1

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

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

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

+0

请阅读我对上述问题所作的评论。我希望在O2(例如)执行每个优化之后获得汇编代码。 – Dogbert 2013-03-05 14:55:45

+0

@Dogbert'-O2'启用一组*优化开关*。您可以通过打开和关闭每个结果来比较结果。但我担心这是你能做的最好的事情。 *每次转换后优化*都无法抑制优化。 (基本上你永远无法在这里完全定义每个*,所有这些优化的方法都是迭代调用的,因为一个优化可以启用另一个优化,所以在关闭之后,所有基于该优化的优化都将被抑制。) – phoeagon 2013-03-05 14:59:20

+0

@Dogbert例如,您可以编译不同的标志并将输出与diff进行比较。 – fuz 2013-03-05 15:23:45

1

gcc -S大写字母S

给ASM输出,但让我更愿意只让一个对象

gcc -c -o myfile.o myfile.c

然后拆卸组装可以改变的事情

objdump -D myfile.o

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

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

+0

我使用'objdump -D myfile.o',但它说'文件格式不被识别'? – Tony 2014-08-01 12:50:47

0

如果您想研究编译器优化,并且不知道编译器,那么请查看Clang/LLVM项目。 Clang是一个C编译器,可以输出LLVM 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 
7

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

还有更细致的-fdump开关awaobble。

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

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

+0

你能给我一个关于'细粒度-fdump'开关的链接吗?我搜索它,但没有找到。 – Tony 2014-08-01 14:24:45

+0

此处:https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/Debugging-Options.html#Debugging-Options。搜索fdump。 – dbrank0 2014-08-01 14:28:51

+0

非常感谢。我搜索了'-fdump'和'-fdump gcc',但没有找到。只是一个字符!再次感谢。 – Tony 2014-08-01 14:37:31

1

尽管可能需要一小段代码,但使用-S进行编译并使用各种选项,难度在于了解实际发生了什么变化。只需稍作更改就可以使代码完全不同 - 进入寄存器的一个变量意味着寄存器不再可用于某些内容,从而对函数中的所有其余代码造成连锁效应。

我今天早些时候比较了两个几乎完全相同的函数的相同代码(在C++上做了一个问题),并且源代码中有一处不同。在一个for-loop内使用哪个变量用于终止条件会导致汇编代码行改变。因为编译器决定以不同的方式安排寄存器,所以使用一个不同的寄存器作为主变量之一,然后其他所有内容都会因此而改变。

我见过在函数中添加一个小的改变将其从内联转换为内联的情况,这又对调用该代码的程序中的所有代码进行了重大更改。

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

也值得考虑的是,优化步骤经常协同工作 - 一步允许另一步工作(内联导致分支合并,注册使用等)。

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 =结构)

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