使用 SIMD,如何将 8 位掩码扩展为 16 位掩码?
Using SIMD, how can I expand a 8-bit mask to 16-bit mask?
我正在尝试使用 simd 重写这段代码:
int16_t v;
int32_t a[16];
int8_t b[32];
...
((int16_t *)a[i])[0] = b[i]==1? -v:v;
((int16_t *)a[i])[1] = b[i]==1? -v:v;
我想用_mm256_cmpeq_epi8
生成一个mask vector,然后我可以用_mm256_and_si256
和_mm256_andnot_si256
来进行取值。
问题是b[i]是8位整数,而v是16位整数。
如果掩码向量像{0xff, 0x00, 0xff, 0x00...}
,需要扩展为{0xffff, 0x0000, 0xffff, 0x0000...}
来进行16位取值。
我该怎么做?
(对不起我的英语)
编辑:
我在 .
的启发下找到了解决方案
_mm256_shuffle_epi256
只能在 128-bit lane 内执行。
所以我将 _mm256i 掩码分成 2 个 _mm128i 寄存器。然后用 _mm256_broadcastsi128_si256
和 _mm256_shuffle_epi256
我得到了结果。
有解决办法:
int16_t v;
int32_t a[16];
int8_t b[32];
//((int16_t *)a[i])[0] = b[i]==1? -v:v;
//((int16_t *)a[i])[1] = b[i]==1? -v:v;
__m256i _1 = _mm256_set1_epi8(1);
__m256i _b = _mm256_loadu_si256((__m256i*)b);
__m256i mask8i = _mm256_cmpeq_epi8(_b, _1); // 8-bit compare mask
__m256i permutedMask8i = _mm256_permute4x64_epi64(mask8i, 0xD8);
__m256i mask16iLo = _mm256_unpacklo_epi8(permutedMask8i, permutedMask8i); // low part of 16-bit compare mask
__m256i mask16iHi = _mm256_unpackhi_epi8(permutedMask8i, permutedMask8i); // high part of 16-bit compare mask
__m256i positiveV = _mm256_set1_epi16(-v); //positive mask condition
__m256i negativeV = _mm256_set1_epi16(v); //negative mask condition
__m256i _aLo = _mm256_blendv_epi8(negativeV, positiveV, mask16iLo);
__m256i _aHi = _mm256_blendv_epi8(negativeV, positiveV, mask16iHi);
_mm256_storeu_si256((__m256i*)a + 0, _aLo);
_mm256_storeu_si256((__m256i*)a + 1, _aHi);
我正在尝试使用 simd 重写这段代码:
int16_t v;
int32_t a[16];
int8_t b[32];
...
((int16_t *)a[i])[0] = b[i]==1? -v:v;
((int16_t *)a[i])[1] = b[i]==1? -v:v;
我想用_mm256_cmpeq_epi8
生成一个mask vector,然后我可以用_mm256_and_si256
和_mm256_andnot_si256
来进行取值。
问题是b[i]是8位整数,而v是16位整数。
如果掩码向量像{0xff, 0x00, 0xff, 0x00...}
,需要扩展为{0xffff, 0x0000, 0xffff, 0x0000...}
来进行16位取值。
我该怎么做?
(对不起我的英语)
编辑:
我在
的启发下找到了解决方案
_mm256_shuffle_epi256
只能在 128-bit lane 内执行。
所以我将 _mm256i 掩码分成 2 个 _mm128i 寄存器。然后用 _mm256_broadcastsi128_si256
和 _mm256_shuffle_epi256
我得到了结果。
有解决办法:
int16_t v;
int32_t a[16];
int8_t b[32];
//((int16_t *)a[i])[0] = b[i]==1? -v:v;
//((int16_t *)a[i])[1] = b[i]==1? -v:v;
__m256i _1 = _mm256_set1_epi8(1);
__m256i _b = _mm256_loadu_si256((__m256i*)b);
__m256i mask8i = _mm256_cmpeq_epi8(_b, _1); // 8-bit compare mask
__m256i permutedMask8i = _mm256_permute4x64_epi64(mask8i, 0xD8);
__m256i mask16iLo = _mm256_unpacklo_epi8(permutedMask8i, permutedMask8i); // low part of 16-bit compare mask
__m256i mask16iHi = _mm256_unpackhi_epi8(permutedMask8i, permutedMask8i); // high part of 16-bit compare mask
__m256i positiveV = _mm256_set1_epi16(-v); //positive mask condition
__m256i negativeV = _mm256_set1_epi16(v); //negative mask condition
__m256i _aLo = _mm256_blendv_epi8(negativeV, positiveV, mask16iLo);
__m256i _aHi = _mm256_blendv_epi8(negativeV, positiveV, mask16iHi);
_mm256_storeu_si256((__m256i*)a + 0, _aLo);
_mm256_storeu_si256((__m256i*)a + 1, _aHi);