2016-09-21 5 views
1

私はApressのModern x86 Assembly言語の本を読んでいます。 64ビットSSEの例をプログラミングするために、著者はを16のアラインメントをコードの特定のポイントに置きます。例えば説明のためにSSEアラインメントに16を使用する理由と場所は?

.code 
ImageUint8ToFloat_ proc frame 
_CreateFrame U2F_,0,64    ; helper macros to create prolog 
_SaveXmmRegs xmm10,xmm11,xmm12,xmm13 ; helper macros to create prolog 

_EndProlog ; helper macros to create prolog 

... 

shrd r8d, 
pxor xmm5,xmm5 

align 16 ; Why this is here ? 
@@: 
movdqa xmm0,xmmword ptr [rdx] 
movdqa xmm10,xmmword ptr [rdx+16] 

movdqa xmm2,xmm0 
punpcklbw xmm0,xmm5 
punpckhbw xmm2,xmm5 
movdqa xmm1,xmm0 
movdqa xmm3,xmm2 

... 

著者は指示自体が整列するように、私たちはSSEを使用しているので、ALIGN 16を置くことが必要である説明しています。それはいいです。私の質問は、著者がを16とその特定の場所に配置することを選択した理由です。プログラマとして、正しい場所をどのように決定する必要がありますかを整列させますか?なぜ、早くも遅くもないのですか?

+1

実際にはあまり意味がありません.SSE *データ*は、通常、16バイト境界に合わせる必要がありますが、指示はありません。 –

+1

おそらくあなたは正しいです。私は間違っているかもしれません。私はこのセクションを再度読んで、「パフォーマンスクリティカルなループ内のブランチターゲットを16バイトの境界に整列させます。\t境界です。」SSEではないというのは本当の理由だと思います。それはジャンプターゲットです。 –

答えて

4

必要ありません。時には有益です。

現代のプロセッサは、16(または多分32、一種のAMDは奇妙なことをするバイト)のブロックでコードをフェッチします。もちろん、整列しています。そのようなブロックの終わり近くにジャンプすると、そのフェッチのほとんどを無駄にし、そのサイクルでは、1つまたは多くの0の命令だけをデコードします。それは巨大な廃棄物なので、ブロックの先頭にジャンプする方がいいです。

ループバッファまたはμopキャッシュ(存在する場合)にコードが含まれている場合など、必ずしも問題ではありません。典型的には、ループ全体がμopsキャッシュに収まります.SandyBridgeより古いプロセッサでは、ループバッファに収まらないループを作成するのはかなり簡単で、フェッチスループットが重要になりました。ループがループバッファに収まる場合でも、アライメントのずれが効果的にループバッファを小さくするため、アライメントはCore2で助けになりました(プリデコード後にキャッシュされた16バイトのコードブロックに基づいています)。もっと奇妙な詳細がいくつかありますが、それは古代のユダヤ人のことですので、私はそれをスキップします。要点は、Nehalemやそれより古いようなμarchでは、しばしばループを整列させるべきです。

フラグメントから非常に明確ではありませんが、ループバックするラベルを整列したように見えます。それで、ループを整列させています。現代のユダヤ人にとってはそれは重要ではありません。

+0

ええ、私はそれを誤解したと思います。それはまさにあなたが述べたものです。ジャンプのパフォーマンスを向上させる。作者は次のように述べています:パフォーマンスクリティカルなループ内の分岐ターゲットを16バイトの境界に揃えてください。 –

+0

SnBファミリのuop-cacheは32Bのマシンコードのチャンクで動作します。 32B x86コード境界は、常にuopキャッシュラインを終了します。 (また、x86ブロックの32Bブロックには、最大3つのuopキャッシュラインを持つことができ、それぞれのキャッシュラインは理想的な状況では最大6つのuopsを保持できます)。 –

関連する問題