29

Intel Advanced Vector Extensions (AVX) は、倍精度浮動小数点変数の 256 ビット バージョン (YMM レジスタ) で内積を提供しません。「なんで?」質問は、別のフォーラム (ここ) とスタック オーバーフロー (ここ) で非常に簡単に扱われています。しかし、私が直面している問題は、この不足している命令を他の AVX 命令に効率的に置き換える方法です。

256 ビット バージョンの内積は、単精度浮動小数点変数用に存在します (ここを参照)。

 __m256 _mm256_dp_ps(__m256 m1, __m256 m2, const int mask);

アイデアは、この不足している命令に相当する効率的なものを見つけることです。

 __m256d _mm256_dp_pd(__m256d m1, __m256d m2, const int mask);

__m128より具体的には、 (4 つの float) から(4 つの double)に変換したいコードでは__m256d、次の命令を使用します。

   __m128 val0 = ...; // Four float values
   __m128 val1 = ...; //
   __m128 val2 = ...; //
   __m128 val3 = ...; //
   __m128 val4 = ...; //

   __m128 res = _mm_or_ps( _mm_dp_ps(val1,  val0,   0xF1),
                _mm_or_ps( _mm_dp_ps(val2,  val0,   0xF2),
                _mm_or_ps( _mm_dp_ps(val3,  val0,   0xF4),
                           _mm_dp_ps(val4,  val0,   0xF8) )));

このコードの結果は、と、 、 、、との間_m128の内積の結果を含む 4 つの float のベクトルです。val1val0val2val0val3val0val4val0

多分これは提案のためのヒントを与えることができますか?

4

3 に答える 3

26

私は4*二重乗算を使用し、次にa hadd(残念ながら上半分と下半分に2 * 2フロートしか追加しません)、上半分を抽出し(シャッフルは同じように機能するはずです、おそらくより速くなります)、それを下半分に追加します。

結果は、の下位64ビットになりdotproductます。

__m256d xy = _mm256_mul_pd( x, y );
__m256d temp = _mm256_hadd_pd( xy, xy );
__m128d hi128 = _mm256_extractf128_pd( temp, 1 );
__m128d dotproduct = _mm_add_pd( (__m128d)temp, hi128 );

編集:
Norbert Pのアイデアの後、私はこのバージョンを拡張して、一度に4つのドット積を実行しました。

__m256d xy0 = _mm256_mul_pd( x[0], y[0] );
__m256d xy1 = _mm256_mul_pd( x[1], y[1] );
__m256d xy2 = _mm256_mul_pd( x[2], y[2] );
__m256d xy3 = _mm256_mul_pd( x[3], y[3] );

// low to high: xy00+xy01 xy10+xy11 xy02+xy03 xy12+xy13
__m256d temp01 = _mm256_hadd_pd( xy0, xy1 );   

// low to high: xy20+xy21 xy30+xy31 xy22+xy23 xy32+xy33
__m256d temp23 = _mm256_hadd_pd( xy2, xy3 );

// low to high: xy02+xy03 xy12+xy13 xy20+xy21 xy30+xy31
__m256d swapped = _mm256_permute2f128_pd( temp01, temp23, 0x21 );

// low to high: xy00+xy01 xy10+xy11 xy22+xy23 xy32+xy33
__m256d blended = _mm256_blend_pd(temp01, temp23, 0b1100);

__m256d dotproduct = _mm256_add_pd( swapped, blended );
于 2012-05-04T18:42:44.320 に答える
12

drhirschの答えを拡張して、2つの内積を同時に実行し、作業を節約します。

__m256d xy = _mm256_mul_pd( x, y );
__m256d zw = _mm256_mul_pd( z, w );
__m256d temp = _mm256_hadd_pd( xy, zw );
__m128d hi128 = _mm256_extractf128_pd( temp, 1 );
__m128d dotproduct = _mm_add_pd( (__m128d)temp, hi128 );

次にdot(x,y)は の下位ダブルdot(z,w)で、 の上位ダブルですdotproduct

于 2012-05-05T05:06:35.720 に答える