#pragma SIMD を使用してループをベクトル化するための条件

インテル® DPC++/C++ コンパイラーインテル® Fortran コンパイラーインテル® Parallel Studio XE

この記事は、インテル® デベロッパー・ゾーンに公開されている「Requirements for Vectorizing Loops with #pragma SIMD」(https://software.intel.com/en-us/articles/requirements-for-vectorizing-loops-with-pragma-simd) の日本語参考訳です。


インテル® アーキテクチャー上でパフォーマンスを向上するにはループのベクトル化が重要であり、SIMD ベクトル長が増えるにしたがってその重要性は増しつつあります。インテル® C/C++ コンパイラーおよびインテル® Fortran コンパイラーにより自動ベクトル化されるループの種類は、「ループをベクトル化するための条件」で説明されています。『インテル® コンパイラー・ユーザー・リファレンス・ガイド』および「インテル® C++ コンパイラーのベクトル化ガイド」で説明されているように、コンパイラーによるベクトル化を支援するため、さまざまなコーディング手法、プラグマ、コマンドライン・オプションを利用できます。この選択肢に、最近新たにインテル® Cilk™ Plus のコンポーネントである simd プラグマ/指示句が追加されました。このプラグマは、バージョン 12 以降の 『インテル® コンパイラー・ユーザー・リファレンス・ガイド』で説明されているように、コンパイラーにループをベクトル化するための条件の一部を緩和させ、できる限りループをベクトル化させます。ASSERT 節を指定すると、ループをベクトル化できなかった場合コンパイルに失敗します。そのため、このプラグマには「ベクトル化しなければ死ぬ (vectorize or die)」プラグマというニックネームが付いています。

#pragma simd (Fortran の場合は !DIR$ SIMD) は、#pragma vector always と #pragma ivdep を組み合わせたような機能がありますが、より強力です。SIMD プラグマ/宣言子が指定されると、コンパイラーはベクトル化によるパフォーマンスの向上を評価しません。また、ベクトル化することで不正な結果を引き起こす可能性のあるエイリアシングや依存関係をチェックしないだけでなく、不正なメモリー参照も防ぎません。#pragma ivdep では、可能性のある依存関係は無視されますが、コンパイラーは依存性の解析を行い、結果に影響することが判明した依存関係はベクトル化しません。#pragma simd では、コンパイラーは依存性の解析を行わず、依存関係の有無に関係なくベクトル化を試みます。結果の正当性に影響する後方依存関係がないことを保証するのは開発者の責任です。#pragma simd のセマンティクスは、どちらかといえば OpenMP* プラグマ #pragma omp parallel for 構文に似ています。OpenMPにおける for ワークシェアには、REDUCTION、PRIVATE、FIRSTPRIVATE、LASTPRIVATE などのオプション指示節がありますが、SIMD プラグマ固有の節には、VECTORLENGTH (ループのアンロールの因数を指定する) と LINEAR (変数ごとに異なるストライドを指定する) があります。SIMD プラグマ/宣言子は、複数の分岐や関数呼び出しを含むループなど、より多様なループをベクトル化します。これは、インテル Cilk Plus のベクトル関数と組み合わせると、特に強力です。

ただし、SIMD プラグマ/指示句の基となる技術はコンパイラーのベクトライザーと同じものなので、ベクトル化可能なループの種類には制限があります。

  • ループは可算ループでなければいけません。つまり、コンパイル時に判明している必要はありませんが、ループに入る前に反復回数が判明していなければなりません。このため、break 文 (C/C++) や EXIT 文 (Fortran) のようなデータ依存性を持つ出口条件があってはいけません。また、ほとんどの「while」ループが除外されます。以下に、一般的な診断メッセージを示します。

        error: 無効な simd プラグマです。
        warning #8410: SIMD 宣言子の後にはカウントされる DO ループを記述しなければなりま
        せん。

  • 特定の特殊非算術演算子、特定の演算子またはデータ型の組み合わせはサポートされていません。「演算はサポートされていません」、「サポートされていないリダクション」、「サポートされていないデータ型です」などの診断メッセージが出力されます。
  • 複雑な配列インデックスやポインター計算は、ベクトル化されない可能性があります。一般的な診断メッセージは「逆参照が複雑すぎます。」です。
  • トリップカウントが低すぎるループはベクトル化されない可能性があります。以下に、一般的な診断メッセージを示します。

        リマーク: ループはベクトル化されませんでした: トリップカウントが低すぎます。

  • ループ本体が非常に大きい場合 (多くの行とシンボルが含まれる場合)、ベクトル化されない可能性があります。コンパイラーは、多数のスピルやメモリーの復元を伴う、多くのベクトルレジスターを必要とするループのベクトル化に対して制限があります。
  • SIMD 指示句は、Fortran 90 の配列代入やインテル® Cilk™ Plus の配列表記 (アレイ・ノーテーション) には適用できない可能性があります。
  • SIMD プラグマは、C++ 例外処理コードを含むループには適用できない可能性があります。

上記の依存性とパフォーマンス評価に関連するものに加えて、#pragma simd では、「ループをベクトル化するための条件」で説明されているいくつかの条件が緩和されています。条件によっては最内ループ以外のベクトル化が可能であったり、より多くの異なるデータ型の組み合わせや関数呼び出しも可能で、複雑な制御フローがサポートされています。ただし、できる限り「ループをベクトル化するための条件」のアドバイスに従ったほうが、パフォーマンスが向上するでしょう。

影響: #pragma simd を使用すると、ループは /fp:fast (-fp-model=fast) に相当する「fast」浮動小数点モデルでベクトル化されます。#pragma simd によりベクトル化されたループでは、コマンドライン・オプション /fp:precise (-fp-model precise) は無視され、#pragma simd を指定しない場合と結果が異なることがあります。浮動少数モデルの詳細については、「インテル® コンパイラーの浮動小数点演算における結果の一貫性」をご覧ください。

SIMD プラグマ/宣言子とインテル® Cilk™ Plus については、『インテル® コンパイラー・ユーザー・リファレンス・ガイド』を参照してください。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください

タイトルとURLをコピーしました