Optimization 在SSE _m128i寄存器中排列字节
我有以下问题: 在Optimization 在SSE _m128i寄存器中排列字节,optimization,sse,simd,Optimization,Sse,Simd,我有以下问题: 在\uuu m128i寄存器中,有16个8bit值,顺序如下: [ 1, 5, 9, 13 ] [ 2, 6, 10, 14] [3, 7, 11, 15] [4, 8, 12, 16] [ 1, 2, 3, 4 ] [ 5, 6, 7, 8] [9, 10, 11, 12] [13, 14, 15, 16] 我想要实现的是高效地洗牌字节以获得这种排序: [ 1, 5, 9, 13 ] [ 2, 6, 10, 14] [3, 7, 11, 15] [4, 8, 12,
\uuu m128i
寄存器中,有16个8bit值,顺序如下:
[ 1, 5, 9, 13 ] [ 2, 6, 10, 14] [3, 7, 11, 15] [4, 8, 12, 16]
[ 1, 2, 3, 4 ] [ 5, 6, 7, 8] [9, 10, 11, 12] [13, 14, 15, 16]
我想要实现的是高效地洗牌字节以获得这种排序:
[ 1, 5, 9, 13 ] [ 2, 6, 10, 14] [3, 7, 11, 15] [4, 8, 12, 16]
[ 1, 2, 3, 4 ] [ 5, 6, 7, 8] [9, 10, 11, 12] [13, 14, 15, 16]
它实际上类似于4x4矩阵转置,但在8位元素上运行
在一个寄存器内
你能告诉我什么样的SSE(最好是你真的想用SSSE3来做这个,它比试着用SSSE3做得好干净得多有
pshufb
,否则把我指给pshufb会有点麻烦!我想我可以从那里开始:)除了SSSE3的pshufb
,正如@harold所指出的,这在某种程度上是旧CPU上的英特尔独家产品,您看到的是一系列杂乱无章的SSE2PUNPCK(L/H)BW
指令。非常感谢您的解释!我将使用SSE3作为主路径,并在没有SSE3的平台上回退到SSE2版本。@user3809354:没问题!请记住,您需要在启动时调用CPUID一次,并存储确定要运行的代码版本所需的任何内容。这是一个很好的起点,可以看到那里有什么。您可以在树上导航以查看SSSE3和SSE4内部函数。我发现上面的一些东西确实可以使用示例(例如,shuffle-mask-value-meansions),但这就是它的用途。:)@user3809354:顺便说一句,我意识到在SSE2版本中可以通过调用_mm_srli_epi16而不是_mm_srli_si128来保存两条指令,因为它将为每个16位组件移位为零。这避免了后面的掩码,因为在调用pack之前,每个16位组件的高字节中都需要有零。这是因为没有一个版本的pack可以截断(即_mm_packs_epi16和_mm_packus_epi16分别执行有符号饱和和无符号饱和),因此要丢弃上面的字节,它需要包含零。我已经更新了答案代码以反映这一点。再次感谢!多亏了你的帮助,我才使它运转起来!另一方面,我必须说SSE/AVX指令集的“正交性”让我笑了好几次:)
__m128i mtrx = _mm_set_epi8(16, 12, 8, 4,
15, 11, 7, 3,
14, 10, 6, 2,
13, 9, 5, 1); // [1, 5, 9, 13] [ 2, 6, 10, 14] [ 3, 7, 11, 15] [ 4, 8, 12, 16]
__m128i mask = _mm_set_epi8(0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF);
__m128i temp = _mm_srli_epi16(mtrx, 8); // [5, 0, 13, 0] [ 6, 0, 14, 0] [ 7, 0, 15, 0] [ 8, 0, 16, 0]
mtrx = _mm_and_si128(mtrx, mask); // [1, 0, 9, 0] [ 2, 0, 10, 0] [ 3, 0, 11, 0] [ 4, 0, 12, 0]
mtrx = _mm_packus_epi16(mtrx, temp); // [1, 9, 2, 10] [ 3, 11, 4, 12] [ 5, 13, 6, 14] [ 7, 15, 8, 16]
temp = _mm_srli_epi16(mtrx, 8); // [9, 0, 10, 0] [11, 0, 12, 0] [13, 0, 14, 0] [15, 0, 16, 0]
mtrx = _mm_and_si128(mtrx, mask); // [1, 0, 2, 0] [ 3, 0, 4, 0] [ 5, 0, 6, 0] [ 7, 0, 8, 0]
mtrx = _mm_packus_epi16(mtrx, temp); // [1, 2, 3, 4] [ 5, 6, 7, 8] [ 9, 10, 11, 12] [13, 14, 15, 16]