2

我希望以编译器在指令重新调度后生成的相同顺序查看反汇编代码。顺便说一句,我正在使用 GDB,当我给出一个命令时,disas /m FunctionName它会按照源代码的顺序给我反汇编代码。我正在尝试查看我的编译器(GCC 4.1)重新调度指令的有效性,并希望了解如何重新调度指令。谢谢!///////////////编辑////////////////////////// /////////查看反汇编代码后的一行代码:

double w_n =  (A_n[2] * x[0] + A_n[5] * y + A_n[8] * z + A_n[11])  ;

我可以看到它的 83 字节指令。但是在通过 2 次迭代展开后:

double w_n[2] = { (A_n[2] * x[0] + A_n[5] * y + A_n[8] * z + A_n[11]), (A_n_2[2] * x[0] + A_n_2[5] * y + A_n_2[8] * z + A_n_2[11]) };

代码块为 226 字节。并且指令数量大幅增加。谁能告诉我为什么会这样?我还可以从 VTune 中看到,展开后退出的指令增加了。我能想到的可能原因:编译器通过增加块大小获得了足够的机会来生成简单的指令,从而最大限度地提高指令预取和解码器单元的吞吐量。

任何帮助是极大的赞赏。谢谢!!

4

2 回答 2

4

如果编译器已经完成了重新调度,那么在 gdb 中反汇编时您确实应该看到这一点。

否则,您也许可以objdump直接在命令行上使用,这是我在 ELF 中查看代码的首选方式:

$ objdump --disassemble a.out | less

它根本不引用源代码,所以它应该真正显示二进制文件本身的内容。

于 2014-04-15T09:53:56.450 回答
4

在将代码编译成目标文件的步骤中,您还可以简单地告诉 GCC 驱动程序 ( gcc) 您想要获取汇编代码:

gcc -S -c file.c
gcc -O2 -S -c file.c
gcc -S -masm=intel -c file.c

(后者生成 Intel 而不是 AT&T 语法汇编)

您甚至可以稍后将该汇编代码扔给汇编器(例如gasm)以获取可以链接的目标文件。


至于为什么代码更大,有很多原因。我们人类用来手动优化装配的启发式方法已经有一段时间不再适用了。一个大目标是流水线,另一个矢量化。总而言之,它是关于尽可能多地并行化,并且必须在任何给定时间尽可能少地从(已读取)缓存中无效以加快执行速度。

尽管这看起来违反直觉,但这可能会导致更大但更快的代码。

于 2014-04-15T10:34:08.297 回答