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上的英特尔独家产品,您看到的是一系列杂乱无章的SSE2
PUNPCK(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]