通过索引获取__m128的成员?

ben*_*wad 25 c++ sse simd clang intrinsics

我有一些代码,最初是由MSVC工作人员给我的,我正试图让它在Clang上工作.这是我遇到麻烦的功能:

float vectorGetByIndex( __m128 V, unsigned int i )
{
    assert( i <= 3 );
    return V.m128_f32[i];
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误如下:

Member reference has base type '__m128' is not a structure or union.
Run Code Online (Sandbox Code Playgroud)

我环顾四周,发现Clang(也许是GCC)在将__m128视为结构或联合时遇到了问题.但是我还没有找到一个直接的答案,我怎么能得到这些价值.我已经尝试过使用下标运算符而无法做到这一点,我已经浏览了大量的SSE内在函数列表并且尚未找到合适的函数.

Gun*_*iez 18

即使SSE4.1可用并且i是编译时常量,也不能pextract这种方式使用等:

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

我不删除它,因为它是一个有用的提醒,如何不做事情,让它作为公众羞辱.

更好用

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

无论可用的指令集如何,它都可以工作.

  • 这是错的.1)`_mm_extract_epi32`将__m128i作为其第一个参数,您传递__m128 - 代码将无法编译.2)如果你用`_mm_castps_si128`解决了这个问题,那么`_mm_extract_epi32`会将原始浮点值作为通用寄存器(例如eax)中的整数返回.3)该值将是`int`转换为float:1.0f == 0x3F800000 = 1,065,353,216.对于`1.0f`,您的代码将在SSE4上返回`1.06535e + 09`.4)即使你用强制转换和重新解释的解引用解决了这个问题,它也会效率低下.您的代码使用了错误的内在函数.使用`_mm_shuffle_ps`和`_mm_cvtss_f32`. (2认同)

Pau*_*l R 17

联盟可能是最便携的方式:

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];
}
Run Code Online (Sandbox Code Playgroud)

  • 我还要补充一点,gcc通常会省略使用联合进行类型惩罚,因此在联合的两个视图都适合寄存器的情况下,隐含的存储和加载都没有完成.所以这使它成为许多类型双关语(除了最安全)之外最有效的技术.但是在这个特定的例子中,由于没有操作码可以从sse寄存器中提取元素[i],所以不会发生这种情况. (3认同)
  • [MSDN](http://msdn.microsoft.com/en-us/library/ayeb3ayc(v = vs.71).aspx)说你不应该这样做,通过[load and set]离开访问(http:/ /msdn.microsoft.com/en-us/library/0hey67c0(v=vs.71).aspx)运营商. (2认同)
  • @ Steve-o:gcc否则表示:http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Optimize-Options.html#index-fstrict_002daliasing-849 (2认同)

Jas*_*n R 16

作为对hirschhornsalz解决方案的修改,如果i是编译时常量,则可以通过使用shuffle/store完全避免union路径:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该使用`_mm_cvtss_f32`而不是`_mm_store_ss`. (2认同)