使用AVX2指令向左移128位数字

时间:2019-12-01 06:36:06

标签: c++ simd intrinsics avx avx2

我正在尝试在AVX2中向左旋转128位数字。由于没有这样做的直接方法,因此我尝试使用左移和右移来完成任务。

这是我的代码的一小段。

        l = 4;
        r = 4;
        targetrotate = _mm_set_epi64x (l, r);
        targetleftrotate = _mm_sllv_epi64 (target, targetrotate);

上面的code代码片段将目标向左旋转4。
当我使用示例输入测试上述代码时,我可以看到结果没有正确旋转。

这是示例输入和输出

          input: 01 23 45 67 89 ab cd ef   fe dc ba 98 76 54 32 10
obtained output: 10 30 52 74 96 b8 da fc   e0 cf ad 8b 69 47 25 03

但是,我期望的输出是

                 12 34 56 78 9a bc de f0   ed cb a9 87 65 43 21 00

我知道我做错了什么。我想知道我的预期输出是否正确,如果是,我想知道我在这里做错了什么。

任何帮助将不胜感激,并在此先感谢。

1 个答案:

答案 0 :(得分:2)

我认为您在打印输入和输出方式方面有一个字节序问题。

每个64位半部分中最左边的字节是实际输出中最低有效的字节,因此0xfe << 4变为0xe0,而{{1 }}移到更高的字节。

有关此内容的更多讨论,请参见Convention for displaying vector registers

您的“预期”输出与您首先打印高元素(存储时的最高地址)的值匹配。但这不是你在做什么;您将按升序分别打印每个字节。 x86是Little-endian。这与我们在英语中使用的数字系统相冲突,在英语中,我们从左到右读取阿拉伯数字,在左侧是最高的位数值,实际上是人类的大端数字。有趣的事实:阿拉伯语从右到左阅读,因此对于他们来说,书面数字是“人类小尾数”。

(并且在元素之间,较高的元素位于较高的地址;首先打印较高的 elements 会使整个向量移位,如f_mm_bslli_si128那样有意义元素之间还剩字节。)

如果使用调试器,则可能在其中进行打印。如果您使用的是调试打印,请参见print a __m128i variable


顺便说一句,您可以使用pslldq将相同的值放入向量的两个元素中,而不是使用具有相同值的单独的_mm_set1_epi64x(4)l变量。

r内在函数中,高位元素排在第一位,与英特尔的asm手册中的图匹配,并且与“左”的语义匹配(向左移动)。 (例如,参见英特尔图解,pshufd, _mm_shuffle_epi32的元素编号)


顺便说一句,AVX512旋转了vprolvq。但是,是的,要模拟旋转,您需要SIMD版本_mm_set。请注意,x86 SIMD将移位计数饱和,与标量移位屏蔽的计数不同。因此(x << n) | x >> (64-n)将移出所有位。如果要支持63以上的轮换计数,则可能需要屏蔽。

({Best practices for circular shift (rotate) operations in C++,但您使用的是内部函数,因此您不必担心C移位计数UB,而不必担心实际的已知硬件行为。)