ユーザー指示または SIMD ベクトル化は、OpenMP* 並列化が自動並列化を補足するように、自動ベクトル化を補足します。下記の図でこの関係を示します。ユーザー指示によるベクトル化は SIMD (Single-Instruction, Multiple-Data) 機能として実装され、SIMD ベクトル化と呼ばれます。
SIMD ベクトル化機能は、インテル製マイクロプロセッサーおよび互換マイクロプロセッサーの両方で利用可能です。ベクトル化により呼び出されるライブラリー・ルーチンは、互換マイクロプロセッサーよりもインテル製マイクロプロセッサーにおいてより優れたパフォーマンスが得られる可能性があります。また、ベクトル化は、/arch (Windows*)、-m (Linux* および macOS*)、[Q]x などの特定のオプションによる影響を受けます。
SIMD ベクトル化は !$OMP SIMD ディレクティブを使用してループをベクトル化します。ループにこのディレクティブを追加して、ループがベクトル化されるように -qopenmp-simd (Linux* および macOS*) または Qopenmp-simd (Windows*) オプションを指定して再コンパイルしなければなりません。
I と 2*I 間のデータ依存性の距離が不明なため、コンパイラーが自動でループをベクトル化しない Fortran の例ついて考えてみます。X が、データ A(I) と A(2*I) が合理的な反復回数内 (例えば 64) でオーバーラップしない十分な大きさであることが分かっている場合、!$OMP SIMD を使ってループのベクトル化を強制実行することができます。また、少なくとも 8 反復内でオーバーラップしないことが分かっている場合、追加で !$OMP SIMD SIMDLEN(8) を指定することで、オーバーラップにつながる可能性のある 8 反復を超えるベクトル化を回避できます
!$OMP SIMD なしの例 |
---|
|
[D:/simd] ifort example1.f -c -nologo -Qopt-report2 -Qopt-report-phase=vec -Qopt-report-file=stderr Begin optimization report for: ADD Report from: Vector optimizations [vec] LOOP BEGIN at example1.f(5,9) <Multiversioned v1> remark #15344: loop was not vectorized: vector dependence prevents vectorization.First dependence is shown below.Use level 5 report for details remark #15346: vector dependence: assumed FLOW dependence between A(I) (6:11) and A(I*2) (5:11) LOOP END LOOP BEGIN at example1.f(5,9) <Remainder, Multiversioned v1> LOOP END LOOP BEGIN at example1.f(5,9) <Multiversioned v2> remark #15304: loop was not vectorized: non-vectorizable loop instance from multiversioning LOOP END LOOP BEGIN at example1.f(5,9) <Remainder, Multiversioned v2> LOOP END =========================================================================== |
!$OMP SIMD ありの例 |
|
[D:/simd] ifort example1.f -c -nologo -Qopt-report2 -Qopt-report-phase=vec -Qopt-report-file=stderr -Qopenp-simd Begin optimization report for: ADD Report from: Vector optimizations [vec] LOOP BEGIN at example1.f(6,9) <Peeled loop for vectorization> LOOP END LOOP BEGIN at example1.f(6,9) remark #15301: OpenMP SIMD LOOP WAS VECTORIZED LOOP END LOOP BEGIN at example1.f(6,9) <Remainder loop for vectorization> LOOP END =========================================================================== |
!$OMP SIMD と自動ベクトル化ヒントの主な違いは、!$OMP SIMD では、コンパイラーはループをベクトル化できない場合に警告を発行します。自動ベクトル化ヒントでは、!DIR$ VECTOR ALWAYS ヒントを使用した場合でも、実際のベクトル化はコンパイラーの判断にまかせられます。
!$OMP SIMD にはオプション節があり、コンパイラーにベクトル化の方法を指示できます。コンパイラーが正しいベクトル化コードを生成するための十分な情報を得られるように、これらの節を適切に使用してください。節についての詳細は、!$OMP SIMD の説明を参照してください。
!$OMP SIMD ディレクティブの使用に関して、次の点に注意してください。
変数は private、linear、reduction のいずれかに属します (またはいずれにも属しません)。
ベクトルループ内では、private、linear、reduction の場合、式はベクトル値として評価されます。または、ベクトル値に評価される部分式があります。そうでない場合、スカラー値として評価されます (つまり、同じ値をすべての反復にブロードキャストします)。スカラー値は、よくループ不変として使用されますが、必ずしもループ不変であるわけではありません。
ベクトル値はスカラー型の左辺値へ割り当てられません。エラーになります。
スカラー型の左辺値はベクトル条件下では割り当てられません。エラーになります。
計算型 GOTO 文はサポートされていません。
次のユーザー定義関数 foo() を使用してシリアル計算とベクトル計算を比較するプログラムの Fortran サンプルコードについて考えてみます。
ユーザー定義関数がベクトル化しない例 |
---|
|
[49 C:/temp] ifort -nologo -qopt-report2 -qopt-report-phase=vec -qopt-report-file=stderr simdmain.f90 vecfoo.f90 Begin optimization report for: SIMDTEST Report from: Vector optimizations [vec] LOOP BEGIN at simdmain.f90(33,3) remark #15319: loop was not vectorized: novector directive used LOOP END LOOP BEGIN at simdmain.f90(54,2) remark #15541: outer loop was not auto-vectorized: consider using SIMD directive LOOP BEGIN at simdmain.f90(47,3) remark #15344: loop was not vectorized: vector dependence prevents vectorization.First dependence is shown below. Use level 5 report for details remark #15346: vector dependence: assumed OUTPUT dependence between at(50:5) and at (50:5) LOOP END LOOP END Non-optimizable loops: LOOP BEGIN at simdmain.f90(28,2) remark #15543: loop was not vectorized: loop with function call not considered an optimization candidate. LOOP BEGIN at simdmain.f90(27,3) remark #15543: loop was not vectorized: loop with function call not considered an optimization candidate. LOOP END LOOP END LOOP BEGIN at simdmain.f90(36,2) remark #15543: loop was not vectorized: loop with function call not considered an optimization candidate. LOOP END LOOP BEGIN at simdmain.f90(43,3) remark #15543: loop was not vectorized: loop with function call not considered an optimization candidate. LOOP BEGIN at simdmain.f90(42,4) remark #15543: loop was not vectorized: loop with function call not considered an optimization candidate. LOOP END LOOP END =========================================================================== |
上記のコードをコンパイルすると、この呼び出しで foo() がインライン展開されていない限り、自動ベクトル化はこの関数が何をするか分からないため、foo() 関数を含むループは自動ベクトル化されません。
関数呼び出しがインライン展開されていない場合は、!DIR$ ATTRIBUTES VECTOR::function-name-list 宣言を使用して、ループと foo() 関数をベクトル化できます。vector 宣言を関数宣言に追加して、コードを再コンパイルするだけです。これで、ループと関数はベクトル化されます。
vector 宣言のあるユーザー定義関数を持つループが自動ベクトル化する例 |
---|
|
|
ベクトル化は、ハードウェアとソースコードのスタイルという 2 つの主な要因により制約されます。vector 宣言を使用する場合、使用できない機能は次のとおりです。
ロック、バリア、atomic 構文、クリティカル・セクション (!$OMP ORDERED SIMD ブロック内で許可される)
計算型および割り当て型 GOTO/SELECT CASE 構造 (場合によっては IF 文に変換されます)
関数内/関数外への GOTO 文
ENTRY 文
非ベクトル関数呼び出しは、一般にベクトル関数内で許可されますが、そのような関数への呼び出しはレーン単位でシリアル化されるため、パフォーマンスが低下します。また、SIMD 対応関数では、引数による書き込みを除く副作用があってはなりません。非ベクトル関数は、この規則に反するため、SIMD 対応関数とサブルーチンで実行する場合には注意が必要です。
仮引数は次のデータ型でなければなりません。