ストリーミング SIMD 拡張命令 2 の組込み関数のプロトタイプは、ヘッダファイル emmintrin.h 内にあります。
void _mm_stream_pd(double *p, __m128d a)
(MOVNTPD を使用) a のデータを、キャッシュを介さずに、アドレス p にストアします。アドレス p は、16 バイトにアライメントが合っていなければなりません。アドレス p を含むキャッシュ・ラインが既にキャッシュ内にある場合、キャッシュは更新されます。
p[0] := a0
p[1] := a1
void _mm_stream_si128(__m128i *p, __m128i a)
a のデータを、キャッシュを介さずに、アドレス p にストアします。アドレス p を含むキャッシュ・ラインが既にキャッシュ内にある場合、キャッシュは更新されます。アドレス p は、16バイトにアライメントが合っていなければなりません。
*p := a
void _mm_stream_si32(int *p, int a)
a のデータを、キャッシュを介さずに、アドレス p にストアします。アドレス p を含むキャッシュ・ラインが既にキャッシュ内にある場合、キャッシュは更新されます。
*p := a
void _mm_clflush(void const*p)
コヒーレンシ・ドメイン内のすべてのキャッシュから、p を含むキャッシュ・ラインをフラッシュし、無効化します。
void _mm_lfence(void)
プログラムの順序でロードフェンス命令に先行するすべてのロード命令が、フェンスに続くロード命令より前に、グローバルにアクセス可能になるのを保証します。
void _mm_mfence(void)
プログラムの順序でメモリフェンス命令に先行するすべてのメモリアクセス命令が、フェンスに続くメモリアクセス命令より前に、グローバルにアクセス可能になるのを保証します。
void _mm_pause(void)
プロセッサに固有の時間の間、次の命令の実行を遅らせます。この命令を実行しても、アーキテクチャ上の状態は変化しません。この組込み関数を使用すると、パフォーマンスが大きく向上します。この組込み関数については、以降で詳しく説明します。
PAUSE 組込み関数は、ダイナミック・エグゼキューション (特に、アウトオブオーダー実行) をサポートするプロセッサ上で、spin-wait ループに使用します。spin-wait ループ内で PAUSE を使用すると、ロックの解放を検出するコードの処理速度が向上します。動的スケジューリングに PAUSE 命令を使用すると、スピンループの終了時のペナルティが軽減されます。
PAUSE 命令を使用したループの例
spin_loop:pause cmp eax, A jne spin_loop |
上の例では、メモリ・ロケーション A がレジスタ eax の値と一致するまで、プログラムはスピンします。次のコード・シーケンスは、test-and-test-and-set 操作を示しています。この例では、ロックの取得に失敗した場合にのみ、スピンが発生します。
get_lock: mov eax, 1 xchg eax, A ; Try to get lock cmp eax, 0 ; Test if successful jne spin_loop critical_section code mov A, 0 ; Release lock jmp continue spin_loop: pause ; Spin-loop hint cmp 0, A ; Check lock availability jne spin_loop jmp get_lock continue: |
この例では、ロックの取得に成功すると予測して、最初の条件分岐は分岐せずに、そのままクリティカル・セクションの処理に移ります。すべての spin-wait ループに、PAUSE 命令を使用することを強くお勧めします。PAUSE は、既存のすべての IA-32 プロセッサで使用可能なため、プロセッサのタイプをテストする (CPUID テスト) 必要はありません。すべての従来のプロセッサは、PAUSE を NOP として実行しますが、PAUSE をヒントとして使用するプロセッサでは、パフォーマンスが大きく向上する可能性があります。