もともとMSVCで作業している人から渡されたコードがあり、Clangで動作させようとしています。これが私が問題を抱えている関数です:
float vectorGetByIndex( __m128 V, unsigned int i )
{
assert( i <= 3 );
return V.m128_f32[i];
}
私が得るエラーは次のとおりです。
Member reference has base type '__m128' is not a structure or union.
私は周りを見回して、Clang(そしておそらくGCC)が__m128を構造体または共用体として扱うことに問題があることを発見しました。しかし、私はこれらの値をどのように取り戻すことができるかについて、正直な答えを見つけることができませんでした。添え字演算子を使用しようとしましたが、それができませんでした。SSE組み込み関数の膨大なリストを一瞥しましたが、適切な関数がまだ見つかりませんでした。
ユニオンは、おそらくこれを行うための最も移植性の高い方法です。
union {
__m128 v; // SSE 4 x float vector
float a[4]; // scalar array of 4 floats
} U;
float vectorGetByIndex(__m128 V, unsigned int i)
{
U u;
assert(i <= 3);
u.v = V;
return u.a[i];
}
使用する
template<unsigned i>
float vectorGetByIndex( __m128 V) {
union {
__m128 v;
float a[4];
} converter;
converter.v = V;
return converter.a[i];
}
これは、使用可能な命令セットに関係なく機能します。
注:SSE4.1が使用可能で、i
がコンパイル時定数である場合でも、これらの命令が抽出するため、この方法でpextract
などを使用することはできません float
ではなく32ビット整数:
// broken code starts here
template<unsigned i>
float vectorGetByIndex( __m128 V) {
return _mm_extract_epi32(V, i);
}
// broken code ends here
何もしない方法を思い出させるのに役立つので、削除しません。
Hirschhornsalzのソリューションの変更として、i
がコンパイル時定数である場合、シャッフル/ストアを使用することでユニオンパスを完全に回避できます。
template<unsigned i>
float vectorGetByIndex( __m128 V)
{
#ifdef __SSE4_1__
return _mm_extract_epi32(V, i);
#else
float ret;
// 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);
#endif
}
私の使い方は
union vec { __m128 sse, float f[4] };
float accessmember(__m128 v, int index)
{
vec v.sse = v;
return v.f[index];
}
私にとってはかなりうまくいくようです。