26

もともと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組み込み関数の膨大なリストを一瞥しましたが、適切な関数がまだ見つかりませんでした。

4

5 に答える 5

22

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バイトのコードサイズは非常に簡単です。casei


_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は使用可能ですが、不要です。任意のソース要素を取得しながら、他の要素をゼロにすることができます。)

于 2012-09-27T16:46:43.717 に答える
19

ユニオンは、おそらくこれを行うための最もポータブルな方法です。

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];
}
于 2012-09-27T15:16:17.483 に答える
18

使用する

template<unsigned i>
float vectorGetByIndex( __m128 V) {
    union {
        __m128 v;    
        float a[4];  
    } converter;
    converter.v = V;
    return converter.a[i];
}

これは、使用可能な命令セットに関係なく機能します。

注:SSE4.1が使用可能でiあり、コンパイル時定数である場合でも、これらの命令は:ではなく32ビット整数を抽出するため、このようになどを使用することはできません。pextractfloat

// broken code starts here
template<unsigned i>
float vectorGetByIndex( __m128 V) {
    return _mm_extract_epi32(V, i);
}
// broken code ends here

何もしない方法を思い出させるのに役立つので、削除しません。

于 2012-09-27T15:47:12.380 に答える
3

私の使い方は

union vec { __m128 sse, float f[4] };

float accessmember(__m128 v, int index)
{
    vec v.sse = v;
    return v.f[index];
}

私にとってはかなりうまくいくようです。

于 2013-07-10T04:16:33.093 に答える
0

このパーティーに遅れましたが、zが__m128型の変数であるMSVCでこれが機能することがわかりました。

#define _mm_extract_f32(v, i)       _mm_cvtss_f32(_mm_shuffle_ps(v, v, i))

__m128 z = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);

float f = _mm_extract_f32(z, 2);

またはさらに簡単

__m128 z;

float f = z.m128_f32[2];  // to get the 3rd float value in the vector
于 2021-01-07T21:19:51.880 に答える