2017-08-24 7 views
5

AVXレジスタの64ビットコンポーネントの上位/下位32ビットコンポーネントをSSEレジスタに再パックするための本質的な方法または別の効率的な方法はありますか? AVX2を使用したソリューションは問題ありません。効率的な(Ryzen上で)__m256の奇数要素を__m128に抽出する方法はありますか?

は、これまでのところ私は、次のコードを使用していますが、プロファイラは、それがRyzen 1800Xに遅いと言う:

インテルで
// Global constant 
const __m256i gHigh32Permute = _mm256_set_epi32(0, 0, 0, 0, 7, 5, 3, 1); 

// ... 

// function code 
__m256i x = /* computed here */; 
const __m128i high32 = _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(x), 
    gHigh32Permute); // This seems to take 3 cycles 
+1

奇数または偶数番号の32ビット要素を抽出しますか?すなわちAVX512 '_mm256_cvtepi64_epi32'(' vpmovqd')のようなものですか? 3サイクルのレイテンシを持つ1シャッフル命令を打ち負かすつもりはないと思います。なぜなら、レーンクロスシャッフルは常にIntel CPU上で3cのレイテンシを持つからです。あなたの 'vpermd'ソリューションはシングルサイクルのスループットを持っています。 –

+0

もっと速くする必要がある場合は、周囲のコードをそれほど使用しないようにする必要があるか、車線交差などを必要としないようにする必要があります。あるいは、何とか 'shufps'を使って256bの結果に2つのソースをパックすることができます(それは車線横断ではないので問題は解決しません。また、' vpackqd'命令もなく、パック命令もレーン横断しません)。 –

+0

@PeterCordes、はい、私は奇数または偶数番号の32ビット要素を256ビットレジスタから128ビットレジスタに抽出します。 AVX512への参照をありがとう!私はRyzen 1800Xでそれを持っていませんが、一度それを移行することを楽しみにしています...これらの32ビット要素は64ビットdoubleの高低部分ですので、周囲のコードを変更する方法はありません。 –

答えて

3

、あなたのコードが最適でしょう。あなたが得る最高のものは、1-uopのインストラクションです。 (入力ベクトルがロードや何かではなくpd命令で作成されている場合は、vpermpsを使用してint/FPバイパス遅延のリスクを回避することをお勧めします)FPシャッフルの結果を整数命令への入力として使用すると、通常はIntel上で問題ありませんが、FP命令の結果を整数シャッフルに与えることはあまり確実ではありません)。

Intel用にチューニングする場合、周囲のコードを変更して底面にシャッフルできます64 - 各128bレーンのビットを使用して、レーン横断シャッフルを使用しないようにします。 (2入力vshufpsが遅いので、次に、あなただけのKNL、vpermilpsためvshufps ymm場合、またはチューニングを使用することができます。)

をAVX512で、_mm256_cvtepi64_epi32 (vpmovqd)は切り捨てて、レーン間の要素をパックているがあります。 Ryzenで


、車線交差シャッフルは遅いです。 Agner Fogにはvpermdの番号はありませんが、vpermps(内部では同じハードウェアを使用している可能性があります)は、3 uop、5c待ち時間、4cスループットあたり1つの割合でリストされています。

vextractf128 xmm, ymm, 1はRyzen(1cレイテンシ、0.33cスループット)上で非常に効率的ですが、256bレジスタを2つの128b半分として既に追跡しているので驚くことではありません。 shufpsも効率的(1cレイテンシ、0.5cスループット)で、2つの128bレジスタを必要な結果にシャッフルすることができます。

これにより、もう不要なシャッフルマスク2 vpermpsの2つのレジスタが保存されます。

だから私はお勧めしたい:インテルで

__m256d x = /* computed here */; 

// Tuned for Ryzen. Sub-optimal on Intel 
__m128 hi = _mm_castpd_ps(_mm256_extractf128_pd(x, 1)); 
__m128 lo = _mm_castpd_ps(_mm256_castpd256_pd128(x)); 
__m128 odd = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(3,1,3,1)); 
__m128 even = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(2,0,2,0)); 

を、最初の結果のための1Cの余分な待ち時間で、あなたに最適なスループットの2/3rdsを与える代わりに、2の3曲のシャッフルを使用します。

+0

私は 'CONST __m128i high32 = _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(_mm256_castpd_si256(X)、gHigh32Permute))ことが測定されました;' 'CONST __m128i high32 = _mm_castps_si128(_mm256_castps256_ps128(_mm256_permutevar8x32_ps(_mm256_castpd_ps(X)、gHigh32Permute)))よりも高速です。' 。したがって、バイパスを「浮動」させるための「ダブル」に対するペナルティもあるでしょうか? –

+0

@SergeRogatch:シャッフルの可能性は低いです。おそらく 'vpermd'は' vpermps'とは異なる動作をします。 (Agnerはそれらを両方ともリストしていないので、私は推測しなければならなかった)。または整数シャフルから来ているときに結果を消費しているものが何であれ、より良い結果になることはありますか?しかし、実際のFP数学命令では、浮動小数点数と2倍の差がありますが、Agnerによると、 (ほとんど常に無関係ですが、内部実装についての手掛かりです。ベクターに格納されている余分なタグビットがあるかもしれません) –

+0

'hi'と' lo'を '__m128 odd = _mm_shuffle_ps ' 、lo、_MM_SHUFFLE(3,1,3,1)); '? –

関連する問題