インテル® Fortran コンパイラー 19.0 デベロッパー・ガイドおよびリファレンス
ユーザー指示または 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 最適化レポート開始: ADD レポート: ベクトルの最適化 [vec] ループの開始 example1.f(5,9) <マルチバージョン v1> リマーク #15344: ループはベクトル化されませんでした: ベクトル依存関係がベクトル化を妨げています。最初の依存関係を以下に示します。詳細については、レベル 5 のレポートを使用してください。 リマーク #15346: ベクトル依存関係: FLOW の依存関係が A(I) (6:11) と A(I*2) (5:11) の間に仮定されました。 ループの終了 ループの開始 example1.f(5,9) <剰余, マルチバージョン v1> ループの終了 ループの開始 example1.f(5,9) <マルチバージョン v2> リマーク #15304: ループはベクトル化されませんでした: マルチバージョンのベクトル化できないループ・インスタンスです。 ループの終了 ループの開始 example1.f(5,9) <剰余, マルチバージョン v2> ループの終了 =========================================================================== |
!$OMP SIMD ありの例 |
|
[D:/simd] ifort example1.f -c -nologo -Qopt-report2 -Qopt-report-phase=vec -Qopt-report-file=stderr -Qopenp-simd 最適化レポート開始: ADD レポート: ベクトルの最適化 [vec] ループの開始 example1.f(6,9) <ベクトル化のピールループ> ループの終了 ループの開始 example1.f(6,9) リマーク #15301: OpenMP* SIMD ループがベクトル化されました。 ループの終了 ループの開始 example1.f(6,9) <ベクトル化の剰余ループ> ループの終了 =========================================================================== |
!$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 最適化レポート開始: SIMDTEST レポート: ベクトルの最適化 [vec] ループの開始 simdmain.f90(33,3) リマーク #15319: ループはベクトル化されませんでした: novector ディレクティブが使用されています。 ループの終了 ループの開始 simdmain.f90(54,2) リマーク #15541: 外部ループは自動ベクトル化されませんでした: SIMD ディレクティブの使用を検討してください。 ループの開始 simdmain.f90(47,3) リマーク #15344: ループはベクトル化されませんでした: ベクトル依存関係がベクトル化を妨げています。最初の依存関係を以下に示します。 詳細については、レベル 5 のレポートを使用してください。 リマーク #15346: ベクトル依存関係: OUTPUT の依存関係が (50:5) と (50:5) の間に仮定されました。 ループの終了 ループの終了 最適化できないループ: ループの開始 simdmain.f90(28,2) リマーク #15543: ループはベクトル化されませんでした: 関数の呼び出しを持つループは最適化の候補と見なされません。 ループの開始 simdmain.f90(27,3) リマーク #15543: ループはベクトル化されませんでした: 関数の呼び出しを持つループは最適化の候補と見なされません。 ループの終了 ループの終了 ループの開始 simdmain.f90(36,2) リマーク #15543: ループはベクトル化されませんでした: 関数の呼び出しを持つループは最適化の候補と見なされません。 ループの終了 ループの開始 simdmain.f90(43,3) リマーク #15543: ループはベクトル化されませんでした: 関数の呼び出しを持つループは最適化の候補と見なされません。 ループの開始 simdmain.f90(42,4) リマーク #15543: ループはベクトル化されませんでした: 関数の呼び出しを持つループは最適化の候補と見なされません。 ループの終了 ループの終了 =========================================================================== |
上記のコードをコンパイルすると、この呼び出しで 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 対応関数とサブルーチンで実行する場合には注意が必要です。
仮引数は次のデータ型でなければなりません。