我正在为一门课程编写编译器。我遇到了一些优化问题,我不确定如何以最佳方式处理这些问题。假设输入语言中有一个使用 N 个局部变量的 while 循环,这些局部变量必须保存在寄存器中(或者应该保存在寄存器中,以便快速计算)。假设 N > K,寄存器的数量。有可能在 while 循环结束时更改条件寄存器。
例如,假设 x 的寄存器(比如 i386 上的 %eax)在以下语句之前确定:
while ( x ) { x = x - 1 ; /* more statements */ }
在 more statements 代码中,x 可能会溢出回堆栈。当代码跳回到 while 循环的开头重新计算 x 时,它会尝试使用 %eax——但这现在可能甚至没有保存 x 的值。所以我们可以有类似的东西
movl -8(%ebp), %eax # eax <- x
.... # do stuff but let x stay in %eax
_LOOP1: cmpl $0, %eax
....
movl -12(%ebp), %eax #eax now holds something else
....
jmp _LOOP1
我正在使用的一种解决方案是强制代码在 while 语句之前溢出所有已修改的寄存器(因此从代码生成器的角度来看,寄存器被视为空)。在 while 循环的标签之后,代码必须根据需要将所有内容加载到寄存器中。
我的解决方案是这样的:
movl -8(%ebp), %eax # eax <- x
.... # do stuff but let x stay in %eax
movl %eax, -8(%ebp) # spilling and clearing all registers
_LOOP1: movl -8(%ebp), %eax # get a register for x again
cmpl $0, %eax
....
movl -12(%ebp), %eax # eax now holds something else
....
movl %eax, -8(%ebp) # spill to prevent overwrite
jmp _LOOP1
似乎我的解决方案有点多余或不必要。我在这里忘记了一些一般的优化技巧吗?
编辑:我还想指出类似的情况也发生在 if 和 if else 等条件句中。这发生在他们身上,因为可以为条件块内的变量分配一个寄存器,但代码生成器假定它被移到那里用于之后的所有其他事情。我处理这种情况的方法几乎相同。