-O3 フラグが設定されたときに gcc によって実行される最適化の種類を理解しようとしています。この2行が何なのか、かなり混乱しています。
xor %esi, %esi
lea 0x0(%esi), %esi
私には冗長に思えます。ここで lea 命令を使用するポイントは何ですか?
その命令は、位置合わせのためにスペースを埋めるために使用されます。プロセッサがメモリをチャンクでデコーダにロードするため、アラインされたアドレスでループを開始すると、ループが高速になる可能性があります。ループと関数の先頭を揃えることで、それらがこれらのチャンクのいずれかの先頭にある可能性が高くなります。これにより、使用されない以前の命令がロードされるのを防ぎ、将来使用される命令の数を最大化します。おそらく最も重要なこととして、最初の命令が完全に最初のチャンクにあることが保証されるため、実行に 2 回のロードが必要ありません。 .
コンパイラは、ループをアラインすることが最善であることを認識しており、アラインするための 2 つのオプションがあります。ループの先頭にジャンプするか、ギャップをノーオペレーションで埋めて、プロセッサがそれらを通過できるようにすることができます。ジャンプ命令は命令の流れを壊し、最近のプロセッサでは無駄なサイクルを引き起こすことが多いため、それらを不必要に追加することはお勧めできません。このような短距離の場合、ノーオペレーションの方が優れています。
x86 アーキテクチャには、特に何もしないことを目的とした命令が含まれていnop
ます。ただし、これは 1 バイトの長さであるため、ループを整列させるには 1 バイト以上かかります。それぞれをデコードして何もしないと判断するには時間がかかるため、副作用のない別の長い命令を単純に挿入する方が高速です。したがって、コンパイラはlea
表示されている命令を挿入しました。まったく影響はなく、必要な正確な長さを持つようにコンパイラーによって選択されます。実際、最近のプロセッサには標準のマルチバイト no-op 命令があるため、これはデコード中に認識され、実行されることさえありません。
ughoavgfhw で説明されているように、これらはコードの配置を改善するためのパディングです。lea
これは次のリンクで見つけることができます-
http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2010-September/003881.html
見積もり:
1-byte: XCHG EAX, EAX
2-byte: 66 NOP
3-byte: LEA REG, 0 (REG) (8-bit displacement)
4-byte: NOP DWORD PTR [EAX + 0] (8-bit displacement)
5-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (8-bit displacement)
**6-byte: LEA REG, 0 (REG) (32-bit displacement)**
7-byte: NOP DWORD PTR [EAX + 0] (32-bit displacement)
8-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
9-byte: NOP WORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
また、詳細を説明しているこの SO の質問にも注意してください - What does NOPL do in x86 system?
xor 自体は nop ではない (reg の値を変更する) ことに注意してください。ただし、ゼロイディオムであるため、実行するのも非常に安価です。レジスタをそれ自体と XOR する目的は何ですか?