昨日私はVC++ 2010で生成された32ビットコードを見ていましたが(おそらく、特定のオプションについてはわかりません)、興味深い繰り返しの細部に興味がありました。多くの機能で、ebx
プロローグであり、常に「ゼロレジスタ」(MIPSの$zero
と思う)のように使用しました。特に、多くの場合:なぜVC++ 2010はebxを「ゼロレジスタ」として使用するのですか?
- メモリをゼロにするために使用されます。
mov mem,imm
のエンコーディングがmov mem,reg
より大きい1から4バイトです(完全な即値のサイズは0でもエンコードする必要があります)が、通常は(gcc)必要なレジスタは「オンデマンド」からゼロになります。そうでなければより有用な目的のために保管された。 cmp reg,ebx
のように0と比較して使用します。これはちょうどtest reg,reg
と同じでなければならないので、私は本当に珍しいものとしてストロークしますが、余分なレジスタに依存します。さて、これは非リーフ関数で起こったことを覚えておいてください。ebx
は(呼び出し先で)スタックに入れたり出たりしばしばプッシュされるので、この依存関係を常に完全にフリーであるとは信じません。また、でも、は、全く同じ方法(test
/cmp
=>jg
)でtest reg,reg
を使用しています。
最も重要なのは、古典的なx86上のレジスタは希少なリソースであるため、正当な理由がなくても多くの時間を無駄にしてしまうレジスタをこぼさなければならないことです。なぜそれをゼロに保つためにすべての機能を通して1つを無駄にするのでしょうか? (それでも、それについて考えてみると、この「ゼロレジスタ」パターンを使用した関数ではレジスタリークが多く見られることは覚えていません)。
So:私は何が欠けていますか?それはコンパイラブローカーか、または2010年に特に興味深かった非常にスマートな最適化ですか?
は、ここに抜粋です:
; standard prologue: ebp/esp, SEH, overflow protection, ... then:
xor ebx, ebx
mov [ebp+4], ebx ; zero out some locals
mov [ebp], ebx
call function_1
xor ecx, ecx ; ebx _not_ used to zero registers
cmp eax, ebx ; ... but used for compares?! why not test eax,eax?
setnz cl ; what? it goes through cl to check if eax is not zero?
cmp ecx, ebx ; still, why not test ecx,ecx?
jnz function_body
push 123456
call throw_something
function_body:
mov edx, [eax]
mov ecx, eax ; it's not like it was interested in ecx anyway...
mov eax, [edx+0Ch]
call eax ; virtual method call; ebx is preserved but possibly pushed/popped
lea esi, [eax+10h]
mov [ebp+0Ch], esi
mov eax, [ebp+10h]
mov ecx, [eax-0Ch]
xor edi, edi ; ugain, registers are zeroed as usual
mov byte ptr [ebp+4], 1
mov [ebp+8], ecx
cmp ecx, ebx ; why not test ecx,ecx?
jg somewhere
label1:
lea eax, [esi-10h]
mov byte ptr [ebp+4], bl ; ok, uses bl to write a zero to memory
lea ecx, [eax+0Ch]
or edx, 0FFFFFFFFh
lock xadd [ecx], edx
dec edx
test edx, edx ; now it's using the regular test reg,reg!
jg somewhere_else
注意:この質問の以前のバージョンは、それがmov reg,ebx
代わりのxor ebx,ebx
を使用したことを言いました。これはちょうど正しく物事を覚えていない私でした。誰もがそれを理解しようと思ってあまりにも多くの考えを入れれば申し訳ありません。
私はあまりにも疲れていました。私はもう一度チェックし、関数全体(これは珍しいものとして私をストロークさせるもの)のために 'ebx'をゼロに保つのは本当ですが、' mov 'のエンコーディングは'cmp reg、ebx'(' ebx' == 0)はプレーンと同じでなければならないので'test reg、reg'です。私はそれに応じて質問を更新します。 –
xDは、私の答えを入力中にポップアップしたコメントをクリックしてクリックする必要があります:Pそしてはい、 '' test reg、reg'は '' cmp''と同じフラグをゼロに設定します(http://stackoverflow.com/ a/38032818/224132)(即時またはレジスタ)、ただしAFは未定義のままです。 Perf-Wiseの場合、より多くのCPUでより多くの場合マクロテストが可能になり、デッドレジスタの読み込みを避けることができます(P6の助けになりますので、1993年に適用されます)。 –
コンパイラは速度の代わりにサイズを最適化している可能性があります。 –