gcc循环构造对汇编代码的更改
为什么gcc编译器在创建汇编代码时将while循环转换为do-while构造?我知道任何while循环都可以重写为do-while,例如在c中gcc循环构造对汇编代码的更改,c,gcc,assembly,x86,C,Gcc,Assembly,X86,为什么gcc编译器在创建汇编代码时将while循环转换为do-while构造?我知道任何while循环都可以重写为do-while,例如在c中 while(测试){ ... } 可以重写为 if ( !test ) goto skip; do { . . . } while ( test ); skip: 通常,do while循环比while循环更有效。由于编译器希望创建一个快速(而非可读)程序,因此它将大多数while循环转换为do while循环 事实上,仅使用if和goto(近似于汇编
while(测试){
...
}
可以重写为
if ( !test ) goto skip;
do {
. . .
} while ( test );
skip:
通常,
do while
循环比while
循环更有效。由于编译器希望创建一个快速(而非可读)程序,因此它将大多数while
循环转换为do while
循环
事实上,仅使用if
和goto
(近似于汇编语言)实现while
循环可以如下所示:
start:
if ( !test ) goto skip;
. . . // loop body
goto start;
skip:
; // continue the program
这相当于do-while
实现,但效率可能低于do-while实现(因为后者在循环中少了一行代码):
基于anatolyg的答案,您可能想知道为什么do-while构造更有效,特别是考虑到如图所示,测试已经重复(因此生成的代码更大)。答案是,通常可以证明测试表达式在循环进入时总是正确的,所以
if ( !test ) goto skip;
loop:
. . . // loop body
if ( test ) goto loop;
skip:
. . . // continue the program
可以简化为
loop:
. . . // loop body
if ( test ) goto loop;
. . . // continue program
现在,为什么不在原始转换的同时这样做,如果编译器不能证明循环至少循环一次,那么就避免原始转换呢?因为证明循环至少循环一次的算法实际上是一个通用的if条件优化器。通常的优化顺序如下所示:
将所有循环转换为“规范”形式(或多或少如上面的第一个代码块所示)
进行大量的优化,以期望以这种规范形式出现循环,如图所示的if语句
在处理完所有与循环相关的事情之后,尝试去规范化那些可以消除冗余的地方
要知道的另一件事是,有时故意保留重复的测试,因为编译器希望它产生更好的运行时行为。例如,如果编译器有理由相信循环通常循环多次,但不能证明它总是至少循环一次,那么循环上方的条件分支指令几乎总是失败,而循环下方的条件分支几乎总是跳转。在这种情况下,将它们分开可能会使CPU的分支预测器更加准确。分支预测精度仅次于缓存友好性,这是现代无序CPU速度的限制因素。因为汇编语言中没有for
或while
循环。如果你想谈论汇编,编译器生成的汇编后代码。每次循环也只有一个分支(只是向后的一个)而不是两个。是的,但是如果编译器确实在循环的顶部重新组合了测试表达式,那么在循环的底部就会有一个无条件分支,这在现代CPU上几乎是免费的——它占用了一个解码单元,但从未进入主管道。非常感谢您的出色响应。
loop:
. . . // loop body
if ( test ) goto loop;
. . . // continue program