6

多くのベクトルで行列ベクトル乗算を実行する C++ で記述された関数があるとします。変換するベクトルの配列へのポインターを取ります。コンパイル時に渡されたポインターのアラインメント (SSE の場合は 16 バイトのアラインメント、AVX の場合は 32 バイトのアラインメントが必要) をコンパイラが認識しないため、コンパイラはそれを SIMD 命令に効率的に最適化できないと仮定するのは正しいですか? それとも、データのメモリ アライメントは最適な SIMD コードには関係なく、データ アライメントはキャッシュ パフォーマンスにのみ影響しますか?

生成されたコードでアラインメントが重要な場合、特定のアラインメントを持つ値のみを関数に渡すつもりであることを (Visual C++) コンパイラにどのように知らせることができますか?

4

2 に答える 2

3

元の回答が乱雑になりすぎて編集できなくなったため、ここに新しい回答を追加し、元の回答コミュニティ wiki を作成しています。

Nehalem より前のシステムと、GCC、Clang、および MSVC を備えた Haswell システムで、アライメントされたメモリとアライメントされていないメモリを使用していくつかのテストを行いました。

アセンブリは、GCC だけが配置をチェックして修正するコードを追加することを示しています。このため、__builtin_assume_alignedGCC を使用すると、はるかに単純なコードが生成されます。ただし__builtin_assume_aligned、Clang で使用すると、アラインされていない命令がアラインされた命令に変更されるだけです (命令の数は変わりません)。MSVC はアラインされていない命令のみを使用します。

パフォーマンスの結果、Nehalem ごとのシステムでは、Clang と MSVC は、メモリが整列されていない場合、自動ベクトル化を使用する GCC よりもはるかに遅くなります。

しかし、Nehalem 以来、キャッシュライン分割のペナルティは小さいです。GCC がメモリをチェックして整列するために追加する余分なコードは、キャッシュラインの分割による小さなペナルティを補う以上のものであることが判明しました。これは、Clang も MSVC もベクトル化によるキャッシュ ラインの分割を考慮しない理由を説明しています。

したがって、自動ベクトル化はアラインメントについて知る必要がないという私の最初の主張は、Nehalem 以降、多かれ少なかれ正しいものです。これは、Nehalem 以来メモリの整列が役に立たないと言っているのと同じことではありません。

于 2015-11-16T10:49:37.223 に答える