私はコース用のコンパイラを書いています。最適に処理する方法がわからないいくつかの最適化の問題に遭遇しました。レジスタに保持する必要がある (または高速計算のために保持する必要がある) N 個のローカル変数を使用する、入力言語からの while ループがあるとします。レジスタ数 N > K と仮定します。while ループの終わり近くで条件付きレジスタが変更される可能性があります。
たとえば、x のレジスタ (i386 では %eax としましょう) が次のステートメントの前に決定されたとします。
while ( x ) { x = x - 1 ; /* more statements */ }
more ステートメント コードでは、x がスタックにスピル バックされる可能性があります。コードが x を再評価するために while ループの先頭に戻ると、%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
私が使用している 1 つの解決策は、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 などの条件文でも同様のことが発生することにも注意してください。これは、レジスタが条件のブロック内の変数に割り当てられる可能性があるため発生しますが、コード ジェネレーターは、その後の他のすべてのためにレジスタがそこに移動されたと想定します。私はその場合に対処するためのほぼ同じアプローチを持っています。