__m256
AVX 命令を使用して、ベクトルのコンポーネントを水平方向に合計したいと考えています。SSEで使用できます
_mm_hadd_ps(xmm,xmm);
_mm_hadd_ps(xmm,xmm);
ベクトルの最初のコンポーネントで結果を取得しますが、これは関数の 256 ビット バージョンではスケーリングされません ( _mm256_hadd_ps
)。
__m256
ベクトルの水平方向の合計を計算する最良の方法は何ですか?
__m256
AVX 命令を使用して、ベクトルのコンポーネントを水平方向に合計したいと考えています。SSEで使用できます
_mm_hadd_ps(xmm,xmm);
_mm_hadd_ps(xmm,xmm);
ベクトルの最初のコンポーネントで結果を取得しますが、これは関数の 256 ビット バージョンではスケーリングされません ( _mm256_hadd_ps
)。
__m256
ベクトルの水平方向の合計を計算する最良の方法は何ですか?
このバージョンは、Intel Sandy / IvyBridgeとAMDBulldozerの両方、およびそれ以降のCPUに最適です。
// x = ( x7, x6, x5, x4, x3, x2, x1, x0 )
float sum8(__m256 x) {
// hiQuad = ( x7, x6, x5, x4 )
const __m128 hiQuad = _mm256_extractf128_ps(x, 1);
// loQuad = ( x3, x2, x1, x0 )
const __m128 loQuad = _mm256_castps256_ps128(x);
// sumQuad = ( x3 + x7, x2 + x6, x1 + x5, x0 + x4 )
const __m128 sumQuad = _mm_add_ps(loQuad, hiQuad);
// loDual = ( -, -, x1 + x5, x0 + x4 )
const __m128 loDual = sumQuad;
// hiDual = ( -, -, x3 + x7, x2 + x6 )
const __m128 hiDual = _mm_movehl_ps(sumQuad, sumQuad);
// sumDual = ( -, -, x1 + x3 + x5 + x7, x0 + x2 + x4 + x6 )
const __m128 sumDual = _mm_add_ps(loDual, hiDual);
// lo = ( -, -, -, x0 + x2 + x4 + x6 )
const __m128 lo = sumDual;
// hi = ( -, -, -, x1 + x3 + x5 + x7 )
const __m128 hi = _mm_shuffle_ps(sumDual, sumDual, 0x1);
// sum = ( -, -, -, x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 )
const __m128 sum = _mm_add_ss(lo, hi);
return _mm_cvtss_f32(sum);
}
haddps
どのCPUでも効率的ではありません。最善の方法は、1回のシャッフル(上位半分を抽出するため)と1回の追加で、残りの要素が1つになるまで繰り返します。最初のステップとして128ビットに狭めることはZen2より前のAMDに利益をもたらし、どこでも悪いことではありません。
効率の詳細については、x86で水平SSEベクトル合計を実行する最速の方法を参照してください。
これは、次のコードで実行できます。
ymm2 = _mm256_permute2f128_ps(ymm , ymm , 1);
ymm = _mm256_add_ps(ymm, ymm2);
ymm = _mm256_hadd_ps(ymm, ymm);
ymm = _mm256_hadd_ps(ymm, ymm);
しかし、もっと良い解決策があるかもしれません。