我在理解 AVX shuffle 内在函数如何为 8 位工作时遇到了一些问题

Posted

技术标签:

【中文标题】我在理解 AVX shuffle 内在函数如何为 8 位工作时遇到了一些问题【英文标题】:I've some problems understanding how AVX shuffle intrinsics are working for 8 bits 【发布时间】:2019-09-12 02:22:15 【问题描述】:

我正在尝试使用 _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);

我希望结果包含:

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

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

【问题讨论】:

software.intel.com/sites/landingpage/IntrinsicsGuide/… , scc.ustc.edu.cn/zlsc/sugon/intel/compiler_c/main_cls/intref_cls/… 您的原始输入是来自内存还是来自寄存器(另外,您的输入是否超过 32 字节)?您对输入数据的范围是否有任何保证(即,它是否始终在[0,255][-128,127] 范围内)?如果不是:你喜欢环绕行为(你的 shuffle 实现就是这种情况)还是饱和(这就是 packuswbpacksswb 会做的)? vpshufb ymm 是两个通道内 128 位随机播放,而不是 32 字节通道交叉置换。见Where is VPERMB in AVX2? 【参考方案1】:

是的,意料之中。查看 _mm_shuffle_epi8 的文档。 256 位 avx 版本只是复制了 YMM 寄存器中两个 16 字节值的 128 位指令的行为。

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

您需要通过一个额外的步骤来执行此操作。

__m256i vperm = _mm256_setr_epi8( 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 位。

【讨论】:

没有办法只用一个_mm256_permute2f128_si256来完成排列。如果你有 AVX2(_mm256_shuffle_epi8 需要它),你可以使用_mm256_permute4x64_epi64,只有 AVX1,你需要在置换后混合或做一点。

以上是关于我在理解 AVX shuffle 内在函数如何为 8 位工作时遇到了一些问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 sse 和 avx 内在函数将一组打包的单曲添加到一个值中

缺少掩码的 AVX-512 内在函数?

发行版将 GCC 升级到 5.5.0 后,AVX512 内在函数头会产生许多错误

给定一个 int 偏移向量,如何使用 AVX512 内在函数收集单个字节?

使用 AVX512 或 SVML 内在函数将压缩的 16 位整数与掩码相除

防止 gcc 将我的 AVX2 内在函数复制到 REP MOVS