3

最近、暗黙の SSE/AVX ロード/ストアに出くわしました。これらは GCC の特別な拡張機能だと思っていましたが、MSVC でも機能することに気付きました。

__m128 a = *(__m128*)data    // same as __m128 a = _mm_load_ps(data)?
__m128 *b = (__m128*)result; // same as _mm_store_ps(result, a)?

これらの暗黙的なロード/ストアの適切な構文は何ですか?

私が読んだことから(非整数アドレスのアドレス指定と sse)、暗黙的なロード/ストアはアライメントされたロード/ストアを使用するため、メモリを適切にアライメントする必要があります。SSE/AVX 組み込み関数をサポートするほとんどのコンパイラ (GCC/ICC/MSVC/Clang/MinGW など) で同じように機能すると仮定するのは公平ですか? これらの暗黙的なロード/ストアを持つ動機は何ですか?

次の一連の質問は、SSE/AVX レジスタをスタックにプッシュおよびポップすることに関するものです。これはどのように実装されていますか?スタックが 16 バイトでアラインされていない場合はどうなりますか? 次に、アライメントされていないロード/ストアを使用しますか? 私が理解しているように、スタックは通常16バイトで整列されていますが、必ずしも32バイトで整列されているわけではありません(少なくとも64ビットモードでは)。アルゴリズムの AVX 占有率が高く、AVX レジスタを頻繁にスタックにプッシュする必要がある場合、パフォーマンスを向上させるためにスタックを 32 バイトに揃えることは理にかなっていますか?

4

1 に答える 1

2

ここで行うことは、メモリを __m128 変数で埋められたものとして再解釈することです。これが機能するのは、__m128 が基本的に 4 つの float (4 つの整数、または 2 つの double など) であり、メモリに連続して書き込まれるためです。したがって、float 配列として扱うことができます。唯一の違いは、__m128 が 16 バイトで整列されるのに対し、float 配列は 4 バイトのみで整列されることが保証されていることです。

この再解釈には reinterpret_cast を使用することをお勧めします。

  // sqrt calculation : b = sqrt(a)
const int N = 1000; // N%4 has to be equal 0!
float a[N] __attribute__((aligned(16))); // Input. Force 16 bytes alignment.
float b[N] __attribute__((aligned(16))); // Result.

for(int i=0; i<N; i+=4) {
  __m128 &aVec = reinterpret_cast<__m128&>(a[i]);
  __m128 &bVec = reinterpret_cast<__m128&>(c_simd[i]);
  bVec = _mm_sqrt_ps(aVec);
}
于 2013-11-02T17:13:49.470 に答える