インテル® C++ コンパイラー 17.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) は、インテル® 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* および OS X*) および /fp オプション (Windows®) で指定された設定は無効になります。

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

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

より多くのベクトル化を行う変換を無効にするには、-vec -no-simd (Linux* および OS X*) または /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 プラグマを使用してこのループのベクトル化を行うことで、ランタイムチェックにかかるオーバーヘッドを回避することができます。

関連情報