この記事は、インテル® デベロッパー・ゾーンに掲載されている「Enabling SIMD in program using OpenMP 4.0」(https://software.intel.com/en-us/articles/enabling-simd-in-program-using-openmp40) の日本語参考訳です。
OpenMP 4.0 仕様で導入された主要機能の 1 つは、プログラム中でプラグマを使って明示的にベクトル化/SIMD を有効にすることです。以下は、OpenMP 4.0 が提供する明示的なベクトル化指示の例です:
1. #pragma omp simd
#pragma omp simd を使用するベクトル化は、コンパイラーにループをベクトル化するように指示します。コードのベクトル化に必要なソースコードの変更は、最小限に抑えるように設計されています。”omp simd” プラグマを使用すると、「#pragma vector always」や「#pragma ivdep」などのベクトル化のヒントを利用しても、コンパイラーが自動ベクトル化しないループをベクトル化できます。
char foo(char *A, int n){ int i; char x = 0; #ifdef SIMD #pragma omp simd reduction(+:x) #endif #ifdef IVDEP #pragma ivdep #endif for (i=0; i<n; i++){ x = x + A[i]; } return x; } >icl /c /Qvec-report2 simd.cpp -openmp simd.cpp simd.cpp(12) (列 3) リマーク: ループはベクトル化されませんでした: ベクトル依存関係が存在しています。 >icl /c /Qvec-report2 simd.cpp /DIVDEP -openmp simd.cpp simd.cpp(12) (列 3) リマーク: ループはベクトル化されませんでした: ベクトル依存関係が存在しています。 >icl /c /Qvec-report2 simd.cpp /DSIMD -openmp simd.cpp simd.cpp(12) (列 3) リマーク:OpenMP SIMD LOOP がベクトル化されました。
プラグマには、いくつかの句を指定することができますが、それらは常に関数本体の動作に関して関連する適切な句を使用することを推奨します。”omp simd” プラグマの詳細に関しては、http://www.openmp.org/mp-documents/OpenMP4.0.0.pdf の 2.8.1 節をご覧ください。
2. #pragma omp declare simd
C/C++ 言語における関数は、伝統的にスカラー引数を受け取って、スカラー値を返します。この動作は、関数呼び出しを伴うループをベクトル化する際にボトルネックとなります。ループ本体をベクトル化する過程で、それぞれスカラーオペランドを使用せずベクトルオペランドを使用するようにします。この状況で、ベクトル引数を受け入れず、ベクトル値を返さない関数呼び出しに遭遇すると、ループ本体をベクトル化する上で深刻なボトルネックを引き起こします。このような状況で、OpenMP 4.0 の新機能は、スカラー関数のベクトル処理を行うバリエーションを生成するようにコンパイラーに指示できます。次のコードは、プラグマの使い方を示す例です:
#pragma omp declare simd int vfun_add_one(int x) { return x+1; } >icl /c /Qvec-report2 elementalfunc.cpp -openmp elementalfunc.cpp elementalfunc.cpp(3) (列 1) リマーク:FUNCTION がベクトル化されました。
プラグマには、いくつかの句を指定することができますが、それらは常に関数本体の動作に関して、関連する適切な句を使用することを推奨します。”omp simd” プラグマの詳細に関しては、http://www.openmp.org/mp-documents/OpenMP4.0.0.pdf の 2.8.2 節をご覧ください。
3. スレッド化と SIMD で同じ “for” ループをターゲットにする:
OpenMP 4.0 では、SIMD モードを実行する複数の OpenMP スレッドによって “for” ループを実行するようにコンパイラーに指示できます。例:
char foo(char *A, int n){ int i; char x = 0; #pragma omp parallel for simd for(i = 0; i < n; i++) x = x + A[i]; return 0; } $ icc test.c -c -vec-report2 -c -openmp-report2 -openmp test.c(4): (列 1) リマーク: OpenMP 定義ループが並列化されました。 test.c(5): (列 1) リマーク: OpenMP SIMD LOOP がベクトル化されました。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。