我加载了两个具有16位值的SSE 128位寄存器。值按以下顺序排列:
src[0] = [E_3, O_3, E_2, O_2, E_1, O_1, E_0, O_0]
src[1] = [E_7, O_7, E_6, O_6, E_5, O_5, E_4, O_4]
我想要实现的是这样的订单:
src[0] = [E_7, E_6, E_5, E_4, E_3, E_2, E_1, E_0]
src[1] = [O_7, O_6, O_5, O_4, O_3, O_2, O_1, O_0]
你知道是否有一个很好的方法(使用SSE内在函数直到SSE 4.2)?
我现在卡住了,因为我无法在128位寄存器的上半部分和下半部分之间混洗16位值。我发现只有_mm_shufflelo_epi16
和_mm_shufflehi_epi16
内在函数。
更新
感谢Paul,我曾考虑将epi8内在函数用于16位值。
我的解决方案如下:
shuffle_split = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0);
xtmp[0] = _mm_load_si128(src_vec);
xtmp[1] = _mm_load_si128(src_vec+1);
xtmp[0] = _mm_shuffle_epi8(xtmp[0], shuffle_split);
xtmp[1] = _mm_shuffle_epi8(xtmp[1], shuffle_split);
xsrc[0] = _mm_unpacklo_epi16(xtmp[0], xtmp[1]);
xsrc[0] = _mm_shuffle_epi8(xsrc[0], shuffle_split);
xsrc[1] = _mm_unpackhi_epi16(xtmp[0], xtmp[1]);
xsrc[1] = _mm_shuffle_epi8(xsrc[1], shuffle_split);
还有更好的解决方案吗?
答案 0 :(得分:2)
SSE的排列并不容易。有许多方法可以通过各种指令组合实现相同的结果。不同的组合可能需要不同数量的指令,寄存器或存储器访问。而不是努力手动解决这样的谜题,我更喜欢看看LLVM编译器的作用,所以我在LLVM的中间语言中编写了一个简单版本的所需排列,它利用了极其灵活的向量shuffle指令:
define void @shuffle_even_odd(<8 x i16>* %src0) {
%src1 = getelementptr <8 x i16>* %src0, i64 1
%a = load <8 x i16>* %src0, align 16
%b = load <8 x i16>* %src1, align 16
%x = shufflevector <8 x i16> %a, <8 x i16> %b, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
%y = shufflevector <8 x i16> %a, <8 x i16> %b, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
store <8 x i16> %x, <8 x i16>* %src0, align 16
store <8 x i16> %y, <8 x i16>* %src1, align 16
ret void
}
使用LLVM IR-to-ASM编译器对此进行编译:{{1}},您将获得类似以下x86程序集的内容:
llc shuffle_even_odd.ll -o shuffle_even_odd.s
我排除了上面LCPIO_ *引用的常量数据部分,但这大致转换为以下C代码:
movdqa (%rdi), %xmm0
movdqa 16(%rdi), %xmm1
movdqa %xmm1, %xmm2
pshufb LCPI0_0(%rip), %xmm2
movdqa %xmm0, %xmm3
pshufb LCPI0_1(%rip), %xmm3
por %xmm2, %xmm3
movdqa %xmm3, (%rdi)
pshufb LCPI0_2(%rip), %xmm1
pshufb LCPI0_3(%rip), %xmm0
por %xmm1, %xmm0
movdqa %xmm0, 16(%rdi)
这只是4个shuffle和2个bitwise或者指令。我怀疑这些按位指令可以在CPU管道中比你提出的解包指令更有效地安排。
您可以在LLVM的下载页面的“Clang Binaries”包中找到“llc”编译器:http://www.llvm.org/releases/download.html