0
#include <immintrin.h>

static const unsigned char LUT[16] = { 0xE4, 0x24, 0x34, 0x04, 
                                       0x38, 0x08, 0x0C, 0x00, 
                                       0x39, 0x09, 0x0D, 0x01, 
                                       0x0E, 0x02, 0x03, 0x00 };

int main( ) {
    float input[4] = { -1.0f, 2.0f, 3.0f, -4.0f };
    float output[4] = {0};

    __m128 data = _mm_loadu_ps( input );
    __m128 mmask = _mm_cmpge_ps( data, _mm_setzero_ps( ) );
    int shufctr = _mm_movemask_ps( mmask );

    __m128 res = _mm_shuffle_ps( data, data, LUT[shufctr] );
    _mm_storeu_ps( output, res );
}

我的意思是使用类似于上面的代码来左打包一个浮点数组,将比较传递给另一个,但它返回错误'最后一个参数必须是 8 位立即数。'我怎样才能做到这一点?

4

1 回答 1

2

函数_mm_shuffle_ps()需要一个无符号的 8 位立即数作为第三个参数;这意味着第三个参数必须是编译时已知的整数常量:

__m128 res = _mm_shuffle_ps(data, data, LUT[shufctr]); // WRONG
__m128 res = _mm_shuffle_ps(data, data, foo()); // WRONG
__m128 res = _mm_shuffle_ps(data, data, bar); // WRONG
__m128 res = _mm_shuffle_ps(data, data, 250); // CORRECT

解决问题的一种可能(不太好)的方法:

...
int shufctr = _mm_movemask_ps(mmask);
__m128 res;

if (shufctr == 0) {
  res = _mm_shuffle_ps(data, data, 0xE4); // LUT[0] == 0xE4
}
else if (...) {
  ...
}
...

编辑(添加用户 Peter Cordes 在评论中提供的信息):

您还可以查看 SSSE3pshufb或 AVX1 vpermilps。这两条指令都使用混洗控制向量(运行时变量)而不是必须嵌入指令流中的立即数。因此,您可以使用movemask结果从 shuffle 控制向量表中进行查找。SSE2 没有任何可变控制洗牌,只有可变计数位移。

于 2021-08-27T15:54:22.660 回答