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

ベクトル化とループ

ループの並列化との相互作用

ここでは、自動ベクトル化とループの相互作用について詳しく説明します。

[Q]parallel[Q]x オプションを組み合わせると、1 回のコンパイルで、自動並列化と自動ループベクトル化の両方を試みることができます。

このオプションを使用すると、互換マイクロプロセッサーおよびインテル製マイクロプロセッサーの両方で並列化が有効になります。実行ファイルは、互換マイクロプロセッサーよりもインテル製マイクロプロセッサーにおいてより優れたパフォーマンスが得られる可能性があります。また、並列化は、/arch (Windows*)、-m (Linux* および macOS*)、[Q]x などの特定のオプションによる影響を受けます。

このオプションを使用すると、インテル製マイクロプロセッサーおよび互換マイクロプロセッサーの両方で、デフォルトの最適化レベルのベクトル化が有効になります。ベクトル化により呼び出されるライブラリー・ルーチンは、互換マイクロプロセッサーよりもインテル製マイクロプロセッサーにおいてより優れたパフォーマンスが得られる可能性があります。また、ベクトル化は、/arch (Windows*)、-m (Linux* および macOS*)、[Q]x などの特定のオプションによる影響を受けます。

多くの場合、コンパイラーは、並列化には最外ループ、ベクトル化には最内ループを認識します。しかし、有効であると判断された場合、コンパイラーは同じループに並列化とベクトル化を適用します。

「自動並列化のプログラミング」および「ベクトル化のプログラミングにおけるガイドライン」を参照してください。

まれに、ループ並列化 (自動または OpenMP* ディレクティブのいずれかによって) が成功すると、コンパイラーにレポートされるベクトル化されなかったループのメッセージに影響することがあります。例えば、Qopt-report:2Qopt-report-phase:vec (Windows*) または qopt-report=2qopt-report-phase=vec (Linux* および macOS*) オプションでは、ループのベクトル化が成功しなかったことが示されます。

ベクトル化されるループの種類

整数ループの場合、128 ビットのインテル® ストリーミング SIMD 拡張命令 (インテル® SSE) とインテル® アドバンスト・ベクトル・エクステンション (インテル® AVX) は 32 ビット、16 ビット、8 ビット、および限定対応の 64 ビットの整数データ型を使用するほとんどの算術演算子と論理演算子に対して SIMD 命令を提供します。

整数丸め演算の最終的な精度が保持される場合は、ベクトル化が可能です。例えば、最後に格納された値が 16 ビット整数である場合には、32 ビットの右シフト演算子は 16 ビット・モードではベクトル化されません。また、インテル® SSE およびインテル® AVX 命令セットは完全に直交型ではない (例えば、バイト・オペランドのシフトはサポートされていない) ため、実際にはすべての整数演算をベクトル化ができないので注意してください。

32 ビット単精度および 64 ビット倍精度の浮動小数点数を操作するループの場合、インテル® SSE は次の算術演算子に対して SIMD 命令を提供します。

また、インテル® SSE は、MINMAX という二項演算子、および SQRT という単項演算子に SIMD 命令を提供しています。これ以外の複数の算術演算子の SIMD バージョン (三角関数 SINCOSTAN など) は、インテル® C++ コンパイラーで提供されるベクトル数値ランタイム・ライブラリー内のソフトウェアでサポートしています。

ベクトル化が可能であるためには、ループは次の条件を満たしていなければなりません。

算術組込み関数は、コンパイラーのランタイム・ライブラリーにベクトル化されたバージョン が含まれているため、利用できます。このような関数を次にリストします。多くは float と double の両方があります。

acos ceil fabs round
acosh cos floor sin
asin cosh fmax sinh
asinh erf fmin sqrt
atan erfc log tan
atan2 erfinv log10 tanh
atanh exp log2 trunc
cbrt exp2 pow  

次の例のループは、sqrtf() がベクトル化可能で、func() がインライン展開されるため、ベクトル化できます。デフォルトの最適化により、同じソースファイル内のすべての関数のインライン展開が有効になります。インライン展開レポートは Qopt-report:2Qopt-report-phase:ipo (Windows*) または qopt-report=2qopt-report-phase=ipo (Linux*) オプションを指定して取得できます。

例 3: ベクトル化が可能なループのインライン展開

float func(float x, float y, float xp, float yp) {
  float denom;
  denom = (x-xp)*(x-xp) + (y-yp)*(y-yp);
  denom = 1./sqrtf(denom);
  return denom; 
} 

float trap_int(float y, float x0, float xn, int nx, float xp, float yp) {
  float x, h, sumx;
  int i;
  h = (xn-x0) / nx;
  sumx = 0.5*( func(x0,y,xp,yp) + func(xn,y,xp,yp) );
  for (i=1;i<nx;i++) {
    x = x0 + i*h;
    sumx = sumx + func(x,y,xp,yp);
  }
  sumx = sumx * h;
  return sumx; 
} 
// コマンドライン
> icc -c -qopt-report=2 -qopt-report-phase=vec trap_integ.c 
trap_int.c(16) (列 3): リマーク: ループがベクトル化されました。

ループ本体内の文

ベクトル化可能な演算は、浮動小数点データと整数データとで異なります。

整数配列の演算

ループ本体内の文では、charunsigned charshortunsigned shortintunsigned int 型を使用できます。sqrtfabs といった関数を呼び出すこともできます。使用可能な算術演算は、加算、減算、ビット単位 AND、ビット単位 OR、ビット単位 XOR、除算 (ランタイム・ライブラリー・コール経由)、乗算、min、および max だけです。データ型は混在させられますが、効率性の低下につながる恐れがあります。例えば、乗算演算子、シフト演算子、単項演算子は混在させられます。

その他の演算

上記の浮動小数点演算と整数演算以外の文は使用できません。特に、特殊なデータ型である __m64__m128__m256 はベクトル化できないので注意してください。ループ本体に関数呼び出しを含めることはできません。インテル® SSE の組込み関数 (例: _mm_add_ps) またはインテル® AVX 組込み関数 (例: _mm256_add_ps) は使用できません。

最適化に関する注意事項

インテル® コンパイラーでは、インテル® マイクロプロセッサーに限定されない最適化に関して、他社製マイクロプロセッサー用に同等の最適化を行えないことがあります。これには、インテル® ストリーミング SIMD 拡張命令 2、インテル® ストリーミング SIMD 拡張命令 3、インテル® ストリーミング SIMD 拡張命令 3 補足命令などの最適化が該当します。インテルは、他社製マイクロプロセッサーに関して、いかなる最適化の利用、機能、または効果も保証いたしません。本製品のマイクロプロセッサー依存の最適化は、インテル® マイクロプロセッサーでの使用を前提としています。インテル® マイクロアーキテクチャーに限定されない最適化のなかにも、インテル® マイクロプロセッサー用のものがあります。この注意事項で言及した命令セットの詳細については、該当する製品のユーザー・リファレンス・ガイドを参照してください。

注意事項の改訂 #20110804

関連情報