1つのドット積では、単純に垂直の乗算と水平の合計です(Fastest way to do horizontal float vector sum on x86参照)。 hadd
はシャッフル2回+ add
です。両方の入力=同じベクトルで使用すると、ほとんど常にスループットが最適以下です。
// both elements = dot(x,y)
__m128d dot1(__m256d x, __m256d y) {
__m256d xy = _mm256_mul_pd(x, y);
__m128d xylow = _mm256_castps256_pd128(xy); // (__m128d)cast isn't portable
__m128d xyhigh = _mm256_extractf128_pd(xy, 1);
__m128d sum1 = _mm_add_pd(xylow, xyhigh);
__m128d swapped = _mm_shuffle_pd(sum1, sum1, 0b01); // or unpackhi
__m128d dotproduct = _mm_add_pd(sum1, swapped);
return dotproduct;
}
あなたが唯一の内積を必要とする場合、それはに絞り込むので、これは@ hirschhornsalzのシングルベクトルインテルの1つのシャッフルUOPによって答え、およびAMDジャガー/ブルドーザーファミリー/ Ryzen上の大きな勝利よりも優れています256bのものを一杯にするのではなく、すぐに128b。 AMDは256bの操作を2つの128bのuopに分割します。
それはあなたが2つの異なる入力ベクトルとそれを使用している並列に2つのまたは4内積を行うような場合にhadd
を使用して価値があることができます。 2組のベクトルのNorbertのdot
は、結果をパックしたい場合に最適に見えます。 AVX2 vpermpd
を車線横断シャッフルとして使用しても、もっとうまくいく方法はありません。もちろん
あなたは本当に(8以上double
秒)dot
1を大きくしたい場合は、(vaddps
のレイテンシを隠蔽するために複数のアキュムレータで)垂直add
を使用し、最後に水平方向の加算を行います。利用可能であれば、fma
を使用することもできます。
haddpd
内部で2つの異なる方法をxy
とzw
をシャッフルし、垂直addpd
にそれを供給し、そしてそれは我々がとにかく手で行いたいものです。 xy
とzw
を別々にしておけば、ドットプロダクトを得るためには別々のレジスタに2シャッフル+2加算する必要があります。だから最初のステップとしてhadd
と一緒にそれらをシャッフルすることによって、シャッフルの合計数を加算し、合計のuopカウントにのみ保存します。
/* Norbert's version, for an Intel CPU:
__m256d temp = _mm256_hadd_pd(xy, zw); // 2 shuffle + 1 add
__m128d hi128 = _mm256_extractf128_pd(temp, 1); // 1 shuffle (lane crossing, higher latency)
__m128d dotproduct = _mm_add_pd((__m128d)temp, hi128); // 1 add
// 3 shuffle + 2 add
*/
しかしvextractf128
が非常に安くなって、そして256B hadd
は128B hadd
限り2倍の費用がかかる、それは別にダウン128Bにそれぞれ256Bの製品を絞り込み、その後128B HADDと組み合わせることに意味を作ることができAMD、ため。
実際には、Agner Fog's tablesによると、haddpd xmm,xmm
は、Ryzenでは4 uopsです。 (そして256b ymmバージョンは8 uopsです)。したがって、実際にRyzenで2x vshufpd
+ vaddpd
を手動で使用する方がよい場合は、そのデータが正しいとします。それはそうではないかもしれません:Piledriverのデータは3 uop haddpd xmm,xmm
で、メモリオペランドを持つのはわずか4 uopsです。 hadd
を3つ(またはymmの6つ)のuopとして実装できないということは私には意味がありません。 1 __m256d
にパックされた結果と4 dot
秒を行うための
、正確な問題がhirschhornsalzの答えは、IntelのCPUのために非常によさそうだ@私が思うに、尋ねました。私は超慎重にそれを勉強していないが、hadd
とペアで組み合わせると良いです。 vperm2f128
はIntel上では効率的です(ただし、AMDではかなり悪い:Ryzenでは8 uops、3cスループットでは1つ)。
アイデアをありがとうが、私はアプリケーションで倍精度を維持する必要があります。 –
さらに、変換+浮動小数点積は、二点積よりも時間がかかります。 – hirschhornsalz