我正在尝试在 AVX2 中对 128 位数进行左旋转。由于没有直接的方法,我尝试使用左移和右移来完成我的任务。
这是我执行相同操作的代码片段。
l = 4;
r = 4;
targetrotate = _mm_set_epi64x (l, r);
targetleftrotate = _mm_sllv_epi64 (target, targetrotate);
上面的代码片段将目标向左旋转 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
我知道我做错了什么。我想知道我的预期输出是否正确,如果正确,我想知道我在这里做错了什么。
我们将不胜感激并提前致谢。
我认为您在打印输入和输出的方式方面存在字节序问题。
每个 64 位半中最左边的字节是实际输出中的最低有效字节,因此 0xfe << 4
trở nên 0xe0
, 与 f
转移到更高的字节。
Nhìn thấy Convention for displaying vector registers对此进行更多讨论。
如果您先打印值高元素(存储时的最高地址),您的“预期”输出与您得到的结果相匹配。但这不是你在做的;您正在按升序内存顺序分别打印每个字节。 x86 是小端。这与我们在英语中使用的数字系统冲突,在英语中我们从左到右阅读阿拉伯数字,左边的最高位值,实际上是人类的 big-endian。有趣的事实:阿拉伯语是从右到左阅读的,因此对他们来说,书写数字是“人类小端”。
(并且跨元素,更高的元素位于更高的地址;首先打印高yếu tố使得像_mm_bslli_si128
又名pslldq
这样的全 vector 移位在元素之间向左移动字节的方式上有意义.)
如果您正在使用调试器,您可能正在其中进行打印。如果您正在使用调试打印,请参阅 print a __m128i variable .
顺便说一句,你可以使用_mm_set1_epi64x(4)
在 vector 的两个元素中放置相同的值,而不是使用单独的 l
Và r
具有相同值的变量。
hiện hữu_mm_set
内在函数,高位元素在前,与Intel的asm手册中的图表相匹配,并与“左”的语义相匹配移动位/字节向左移动。 (例如,参见英特尔图表 pshufd, _mm_shuffle_epi32
的元素编号)
顺便说一句,AVX512 有 vprolvq
旋转。但是,是的,要模拟旋转,您需要 (x << n) | x >> (64-n)
的 SIMD 版本.请注意,x86 SIMD 移位饱和移位计数,这与屏蔽计数的标量移位不同。所以x >> 64
将移出所有位。如果您想支持 63 以上的旋转计数,您可能需要屏蔽。
(Best practices for circular shift (rotate) operations in C++ 但您使用的是内部函数,因此您不必担心 C 移位计数 UB,只需担心实际已知的硬件行为。)
Tôi là một lập trình viên xuất sắc, rất giỏi!