インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス

simd

ループのベクトル化を実行します。

構文

#pragma simd[clause[ [,]clause]...]

引数

clause

次のいずれかです。

vectorlength(n1[, n2]...)

n はベクトル長 (VL) です。2 の累乗の整数値で、2、4、8、または 16 でなければなりません。複数の n を指定すると、ベクトル化機能は指定された値から VL を選択します。

ベクトルループのそれぞれの反復は、スカラーループを n 回実行するのと同じ分の演算を実行します。複数の vectorlength 節は結合されます。

vectorlengthfor(data type)

data type はビルトインの整数型 (8、16、32、または 64 ビット)、ポインター型 (ポインターのサイズの整数として処理される)、浮動小数点型 (32 または 64 ビット)、または複素数型 (64 または 128 ビット) のいずれかでなければなりません。そうでない場合の動作は不定です。

ベクトルループのそれぞれの反復は、スカラーループを n 回実行するのと同じ分の演算を実行します。n は次のように計算されます: size_of_vector_register/sizeof(data_type)

例えば、vectorlengthfor(float) は、インテル® ストリーミング SIMD 拡張命令 2 (インテル® SSE2) からインテル® SSE4.2 対応のターゲット・プロセッサー (128 ビットの XMM レジスターでパックド浮動小数点演算に対応) では n=4、インテル® アドバンスト・ベクトル・エクステンション (インテル® AVX) 対応のターゲット・プロセッサー (256 ビットの YMM レジスターでパックド浮動小数点演算に対応) では n=8 になります。vectorlengthfor(int) は、インテル® SSE2 からインテル® AVX 対応のターゲット・プロセッサーで n=4 になります。

vectorlength() 節と vectorlengthfor() 節は互いに排他的です。つまり、同時に両方を指定することはできません。

複数の vectorlengthfor 節を指定した場合の動作は不定です。

private(var1[, var2]...)

var はスカラー変数です。

ループのそれぞれの反復に対して各変数がプライベートになります。firstprivate 節で変数が指定されている場合を除き、特定の反復における変数の初期値は未定義です。lastprivate 節で変数が指定されている場合を除き、ループ終了時の変数の値は未定義です。複数の private 節は結合されます。

firtsprivate/lastprivate 節を指定して SIMD ループを実行すると、ループがベクトル化されなかった場合でも、同じコードをシリアル実行した場合と異なります。

private 節の変数は、linearreductionfirstprivate、または lastprivate 節で指定できません。

firstprivate(var1[, var2]...)

private 節で指定される機能のスーパーセットを指定します。firstprivate 節でリストする変数には、private 節のセマンティクスが適用されます。さらに、その初期値は、SIMD ループに入る前に、各反復のすべてのプライベート・インスタンスにブロードキャストされます。

firstprivate 節の変数は、lastprivate 節で指定できます。

firstprivate 節の変数は、linearreduction、または private 節で指定できません。

lastprivate(var1[, var2]...)

private 節で指定される機能のスーパーセットを指定します。lastprivate 節でリストする変数には、private 節のセマンティクスが適用されます。さらに、SIMD ループ終了時の各変数の値は、その SIMD ループシーケンスの最後の反復の結果になります (最後の反復で値が代入されなかった場合は未定義となります)。

lastprivate 節の変数は、firstprivate 節で指定できます。

lastprivate 節の変数は、linearreduction、または private 節で指定できません。

linear(var1:step1 [,var2:step2]...)

var はスカラー変数、step はコンパイル時の正の整数定数式です。

スカラーループのそれぞれの反復で、var1step1var2step2、というように増分されます。そのため、ベクトルループの各反復は、変数を VL*step1、VL*step2、…、VL*stepN のように増分します。var に複数の step が指定されている場合は、コンパイル時にエラーが発生します。複数の linear 節は結合されます。

linear 節の変数は、reductionprivatefirstprivate、または lastprivate 節で指定できません。

reduction(oper:var1 [,var2]…)

oper はリダクション演算子、var はスカラー変数です。

oper で示されたベクトル・リダクションを var1var2、…、varN に適用します。simd プラグマには、演算子が同じまたは異なる複数の reduction 節を含めることができます。var に複数のリダクション演算子が関連付けられている場合は、コンパイル時にエラーが発生します。

reduction 節の変数は、linearprivatefirstprivate、または lastprivate 節で指定できません。

[no]assert

ベクトル化に失敗したときに、報告するかどうかをコンパイラーに指示します。デフォルトは noassert です。この節が複数指定された場合は、コンパイル時にエラーが発生します。

[no]vecremainder

オリジナルのループがベクトル化された場合に残りのループをベクトル化するかどうかをコンパイラーに指示します。詳細は、vector プラグマの説明を参照してください。

説明

より多くのループのベクトル化を行うようにコンパイラーに指示するには、simd プラグマを使用します。simd プラグマを使用したベクトル化は、完全に自動化されたアプローチを補完します (ただし、置き換えることはできません)。

simd プラグマは、cilk_for ループと併用できます。最適な併用方法については、cilk_for の説明を参照してください。

明示的に vectorlength() 節または vectorlengthfor() 節が指定されていない場合、コンパイラーは独自のコストモデルを使用して vectorlength を選択します。privatefirstprivatelastprivatelinear、および reduction で正しくない変数が指定されたり、あるいは適切な変数が指定されていない場合、ランタイムエラーや正しくない結果など、意図しない問題が発生する可能性があります。

特定の変数は、privatelinear、または reduction 節の 1 つのインスタンスでのみ指定することができます。

コンパイラーがループをベクトル化できない場合は、警告が出力されます (assert 節を使用して警告をエラーとすることができます)。

なんらかの理由でベクトル化機能がループのベクトル化を停止する必要がある場合は、SIMD ループに fast 浮動小数点モデルが使用されます。

ループを simd プラグマでベクトル化すると、-fp-model オプション (Linux* および macOS*) および /fp オプション (Windows*) で指定された設定は無効になります。

simd プラグマは、すべての自動ベクトル化が可能なループに影響するわけではありません。いくつかのループでは SIMD ベクトル・セマンティクスを表現できません。

simd プラグマには、次の制限が適用されます

より多くのベクトル化を行う変換を無効にするには、-vec -no-simd (Linux* および macOS*) または /Qvec /Qno-simd (Windows*) オプションを指定してください。

ユーザー指示によるベクトル化 (SIMD ベクトル化とも呼ぶ) では、#pragma simd アノテーション付きのループのベクトル化に失敗した場合、エラーを報告するかどうか指定できます。デフォルトでは、simd プラグマは noassert に設定されていて、ループのベクトル化に失敗すると、コンパイラーは警告を発行します。#pragma simd アノテーション付きのループのベクトル化に失敗した場合、コンパイラーにエラーを報告するように指示するには、simd プラグマに assert 節を追加します。simd アノテーション付きのループがコンパイラーによりベクトル化されなかった場合、そのループはシリアル・セマンティクスを保持します。

novector プラグマの使用例

 void add_floats(float *a, float *b, float *c, float *d, float *e, int n){
  int i; 
#pragma simd
  for (i=0; i<n; i++){
    a[i] = a[i] + b[i] + c[i] + d[i] + e[i];
  } 
}

上の例では、関数 add_floats() で不明なポインターを多く使用しているため、コンパイラーの自動ランタイム独立性チェックによる最適化が行われます。simd プラグマを使用してこのループのベクトル化を行うことで、ランタイムチェックにかかるオーバーヘッドを回避することができます。

関連情報