、あなたのコードが最適でしょう。あなたが得る最高のものは、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曲のシャッフルを使用します。
奇数または偶数番号の32ビット要素を抽出しますか?すなわちAVX512 '_mm256_cvtepi64_epi32'(' vpmovqd')のようなものですか? 3サイクルのレイテンシを持つ1シャッフル命令を打ち負かすつもりはないと思います。なぜなら、レーンクロスシャッフルは常にIntel CPU上で3cのレイテンシを持つからです。あなたの 'vpermd'ソリューションはシングルサイクルのスループットを持っています。 –
もっと速くする必要がある場合は、周囲のコードをそれほど使用しないようにする必要があるか、車線交差などを必要としないようにする必要があります。あるいは、何とか 'shufps'を使って256bの結果に2つのソースをパックすることができます(それは車線横断ではないので問題は解決しません。また、' vpackqd'命令もなく、パック命令もレーン横断しません)。 –
@PeterCordes、はい、私は奇数または偶数番号の32ビット要素を256ビットレジスタから128ビットレジスタに抽出します。 AVX512への参照をありがとう!私はRyzen 1800Xでそれを持っていませんが、一度それを移行することを楽しみにしています...これらの32ビット要素は64ビットdoubleの高低部分ですので、周囲のコードを変更する方法はありません。 –