我有一些使用 AVX2 内在的代码 _mm256_permutevar8x32_epi32
又名 vpermd
通过索引向量从输入向量中选择整数。现在我需要同样的东西,但需要 4x32 而不是 8x32。 _mm_permutevar_ps
是为浮点数做的,但我使用的是整数。
一个想法是 _mm_shuffle_epi32
,但我首先需要将我的 4x32 索引值转换为单个整数,即:
imm[1:0] := idx[31:0]
imm[3:2] := idx[63:32]
imm[5:4] := idx[95:64]
imm[7:6] := idx[127:96]
我不确定什么是最好的方法,而且我不确定这是最好的方法。我正在寻找 Broadwell/Haswell 上最有效的方法来模拟“失踪”
_mm_permutevar_epi32(__m128i a, __m128i idx)
.如果可能的话,我宁愿使用 128 位指令而不是 256 位指令(即我不想扩大 128 位输入然后缩小结果)。
最佳答案
尽管 Peter Cordes 说 AVX 指令 vpermilps
是正确的及其内在 _mm_permutevar_ps()
如果您使用的是比 Sandy Bridge 更旧的机器(使用 pshufb
的 SSE4.1 变体),则可能会完成这项工作。效果也很好。
AVX 变体
归功于@PeterCordes
#include <stdio.h>
#include <immintrin.h>
__m128i vperm(__m128i a, __m128i idx){
return _mm_castps_si128(_mm_permutevar_ps(_mm_castsi128_ps(a), idx));
}
int main(int argc, char* argv[]){
__m128i a = _mm_set_epi32(0xDEAD, 0xBEEF, 0xCAFE, 0x0000);
__m128i idx = _mm_set_epi32(1,0,3,2);
__m128i shu = vperm(a, idx);
printf("%04x %04x %04x %04x\n", ((unsigned*)(&shu))[3],
((unsigned*)(&shu))[2],
((unsigned*)(&shu))[1],
((unsigned*)(&shu))[0]);
return 0;
}
SSE4.1 变体
#include <stdio.h>
#include <immintrin.h>
__m128i vperm(__m128i a, __m128i idx){
idx = _mm_and_si128 (idx, _mm_set1_epi32(0x00000003));
idx = _mm_mullo_epi32(idx, _mm_set1_epi32(0x04040404));
idx = _mm_or_si128 (idx, _mm_set1_epi32(0x03020100));
return _mm_shuffle_epi8(a, idx);
}
int main(int argc, char* argv[]){
__m128i a = _mm_set_epi32(0xDEAD, 0xBEEF, 0xCAFE, 0x0000);
__m128i idx = _mm_set_epi32(1,0,3,2);
__m128i shu = vperm(a, idx);
printf("%04x %04x %04x %04x\n", ((unsigned*)(&shu))[3],
((unsigned*)(&shu))[2],
((unsigned*)(&shu))[1],
((unsigned*)(&shu))[0]);
return 0;
}
这编译成清脆的
0000000000400550 <vperm>:
400550: c5 f1 db 0d b8 00 00 00 vpand 0xb8(%rip),%xmm1,%xmm1 # 400610 <_IO_stdin_used+0x20>
400558: c4 e2 71 40 0d bf 00 00 00 vpmulld 0xbf(%rip),%xmm1,%xmm1 # 400620 <_IO_stdin_used+0x30>
400561: c5 f1 eb 0d c7 00 00 00 vpor 0xc7(%rip),%xmm1,%xmm1 # 400630 <_IO_stdin_used+0x40>
400569: c4 e2 79 00 c1 vpshufb %xmm1,%xmm0,%xmm0
40056e: c3 retq
如果您可以保证控制索引始终是 32 位整数 0、1、2 或 3,则 AND 掩码是可选的。
关于SSE:shuffle (permutevar) 4x32 整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56033329/