gcc循环构造对汇编代码的更改

hop*_*pup 2 c x86 assembly gcc

在创建汇编代码时,为什么gcc编译器将while循环转换为do-while构造?我知道任何while循环都可以重写为do-while,例如在c中

while (test) { ... }

可以改写成

if ( !test ) goto skip;
do {
. . .
} while ( test );
skip:
Run Code Online (Sandbox Code Playgroud)

zwo*_*wol 5

基于anatolyg的答案,您可能想知道为什么 do-while构造更有效,尤其是考虑到如图所示,测试已经重复(因此生成的代码更大)。答案是经常可以证明测试表达式在循环进入时总是正确的,因此

    if ( !test ) goto skip;
loop:
    . . . // loop body
    if ( test ) goto loop;
skip:
    . . . // continue the program
Run Code Online (Sandbox Code Playgroud)

可以简化为

loop:
    . . . // loop body
    if ( test ) goto loop;
    . . . // continue program
Run Code Online (Sandbox Code Playgroud)

现在,为什么不与原始转换同时进行,如果编译器无法证明循环至少循环一次,就避免原始转换?因为证明循环至少循环一次的算法实际上是通用的if条件优化器。通常的优化顺序如下所示:

  1. 将所有循环转换为“规范”形式(或多或少,如上面的第一个代码块所示)
  2. 做大量的优化工作,期望以规范的形式出现循环,例如所示的if语句消除。
  3. 在完成了所有与循环有关的事情之后,尝试取消规范化将消除冗余的位置。

要知道的另一件事是,有时会故意重复测试,因为编译器希望这样做会产生更好的运行时行为。例如,如果编译器有理由相信循环通常循环多次,但不能证明循环总是至少循环一次,则循环上方的条件分支指令几乎总是会失败,而循环下方的条件分支循环几乎总是会跳。在这种情况下,将它们分开可以使CPU的分支预测器更加准确。分支预测精度仅次于高速缓存友好性,这是现代乱序CPU速度的限制因素。