hirschhornsalzのソリューションの変更として、i
がコンパイル時定数の場合、シャッフルを使用してユニオンパスを完全に回避できます。
template<unsigned i>
float vectorGetByIndex( __m128 V)
{
// shuffle V so that the element that you want is moved to the least-
// significant element of the vector (V[0])
V = _mm_shuffle_ps(V, V, _MM_SHUFFLE(i, i, i, i));
// return the value in V[0]
return _mm_cvtss_f32(V);
}
スカラーフロートはXMMレジスタの下部要素であり、上部要素はゼロ以外にすることができます。_mm_cvtss_f32
無料で、ゼロ命令にコンパイルされます。これは、単なるshufpsとしてインライン化されます(またはi == 0の場合は何もありません)。
コンパイラーは、シャッフルを最適化するのに十分なほど賢いi==0
ので(長く廃止されたICC13を除く)、。は必要ありませんif (i)
。 https://godbolt.org/z/K154Pe。clangのシャッフルオプティマイザは、コンパイルvectorGetByIndex<2>
しmovhlps xmm0, xmm0
て1バイト短くなりshufps
、同じ下位要素を生成します。はコンパイル時定数であるため、他のコンパイラではswitch
/を使用して手動でこれを行うことができますが、手動でベクトル化するときにこれを使用するいくつかの場所での1バイトのコードサイズは非常に簡単です。case
i
_mm_extract_epi32(V, i);
ここでは、SSE4.1は有用なシャッフルではないことに注意してください。FPextractps r/m32, xmm, imm
ビットパターンを整数レジスタまたはメモリにのみ抽出できます(https://www.felixcloutier.com/x86/extractps)。(そして、組み込み関数はそれをとして返すint
ので、C ++コードで型のパンニングを行わない限り、実際にはextractps
+にコンパイルさcvtsi2ss
れてFPビットパターンでint-> float変換を実行します。ただし、コンパイルされると予想されます。 to extractps eax, xmm0, i
/movd xmm0, eax
これはshufpsに対してひどいです。)
有用な唯一のケースextractps
は、コンパイラがこの結果を直接メモリに格納し、その格納を抽出命令に折りたたむ場合です。(i!= 0の場合、それ以外の場合はを使用しますmovss
)。結果をスカラーフロートとしてXMMレジスタに残すのshufps
は良いことです。
(SSE4.1insertps
は使用可能ですが、不要です。任意のソース要素を取得しながら、他の要素をゼロにすることができます。)