C++ I';了解AVX shuffle intrinsic如何为8位工作时遇到一些问题

C++ I';了解AVX shuffle intrinsic如何为8位工作时遇到一些问题,c++,sse,simd,avx,avx2,C++,Sse,Simd,Avx,Avx2,我试图使用mm256 shuffle epi8将16位数据打包成8位,但结果并不是我所期望的 auto srcData = _mm256_setr_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); __m256i vperm = _

我试图使用mm256 shuffle epi8将16位数据打包成8位,但结果并不是我所期望的


auto srcData = _mm256_setr_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 
                               17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);

__m256i vperm = _mm256_setr_epi8( 0,  2,  4,  6,  8, 10, 12, 14,
                                 16, 18, 20, 22, 24, 26, 28, 30,
                                 -1, -1, -1, -1, -1, -1, -1, -1,
                                 -1, -1, -1, -1, -1, -1, -1, -1);

auto result = _mm256_shuffle_epi8(srcData, vperm);

我希望结果包含:

但我有:

我肯定误解了Shuffle的工作原理。
如果有人能启发我,我将不胜感激:)

是的,这是意料之中的事。看一下文件,看一看《洗牌》第8章。256bit avx版本仅为YMM寄存器中的两个16字节值复制128位指令的行为

因此,您可以洗牌前16个值,或最后16个值;但是,您不能跨16字节边界洗牌值。(您会注意到,所有超过16的数字都是相同的数字减去16。例如,19->3、31->15等)

您需要通过附加步骤来完成此操作

\uuuum256i vperm=\umm256\usetr\uepi8(0,2,4,6,8,10,12,14,
-1, -1, -1, -1, -1, -1, -1, -1,
0,  2,  4,  6,  8, 10, 12, 14,
-1, -1, -1, -1, -1, -1, -1, -1);

然后使用_mm256_permute2f128_si256将第0和第2个字节拉入前128位

,您的原始输入是来自内存还是来自寄存器(另外,您的输入是否超过32字节)?您是否对输入数据的范围有任何保证(即,它是否始终在
[0255]
[-128127]
范围内)?如果不是:您是否希望有环绕行为(洗牌实现就是这种情况)或饱和(这是
packuswb
packsswb
将要做的)vpshufb-ymm是两个通道内128位洗牌,而不是32字节通道交叉排列。请参见,仅用一个
\u mm256\u permute2f128\u si256
无法完成置换。如果您有AVX2(您需要它来
\u mm256\u shuffle\u epi8
),您可以使用
\u mm256\u permute4x64\u epi64
,只需使用AVX1,您就需要混合或进行位或在置换后使用。
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
1, 3, 5, 7, 9, 11, 13, 15,  1,  3,  5,  7,  9, 11, 13, 15,
0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0