(注意,在Neon中我使用this data type来避免处理16位数据类型之间的转换)
为什么实践中“内移”中的“左移”是“向右移”?
// Values contained in a
// 141 138 145 147 144 140 147 153 154 147 149 146 155 152 147 152
b = vshlq_n_u32(a,8);
// Values contained in b
// 0 141 138 145 0 144 140 147 0 154 147 149 0 155 152 147
b = vshrq_n_u32(a,8);
// Values contained in b
// 138 145 147 0 140 147 153 0 147 149 146 0 152 147 152 0
我记得在使用_mm_slli_si128
时发现相同的情况(虽然不同但是转换后的结果如下所示:
// b = _mm_slli_si128(a,1);
// 0 141 138 145 147 144 140 147 153 154 147 149 146 155 152 147
是因为字节序吗? 它会从平台变为平台吗?
答案 0 :(得分:5)
你说“这是因为结束”,但更多的是滥用类型的情况。您正在假设跨越字节/字边界的机器位顺序以及对操作施加局部字节顺序的非字节指令(您使用的是_u32指令,该指令期望值为无符号32位值,而不是数组8位值。)
正如你所说,你要求它通过/ ask / it来移动一系列无符号字符值,以32位为单位移位值。
不幸的是,如果您希望能够对它们进行架构转换,则需要将它们置于架构顺序中。
否则您可能想要查找blit或移动指令,但是如果不支付架构成本,则无法人为地将机器类型强制转换为机器寄存器。字节序只是你的头痛之一(对齐,填充等)
---晚编辑---
从根本上说,你是在混淆字节和位移,我们认为最重要的位是“左”
bit number
87654321
hex
8421
00008421
00000001 = 0x01 (small, less significant)
10000000 = 0x80 (large, more significant)
但是你要移位的值是32位字,在一个小端机器上,这意味着对于一个32位字,每个后续地址会增加该值的一个更重要的字节:
bit numbers
1111111111111111
87654321fedcba0987654321fedcba09
表示32位值0x0001
1111111111111111
87654321fedcba0987654321fedcba09
00000001000000000000000000000000
将其左移2个位置
00000001000000000000000000000000
v<
00000100000000000000000000000000
将其向左移动另外8个位置,我们必须将其转换到下一个地址:
00000100000000000000000000000000
>>>>>>>v
00000000000001000000000000000000
如果以字节为单位考虑,这看起来像是一个正确的转变。但我们告诉这个小端CPU我们正在使用uint32,这意味着:
1111111111111111
87654321fedcba0987654321fedcba09
word01 word02 word03 word04
00000001000000000000000000000000 = 0x0001
00000100000000000000000000000000 = 0x0004
00000000000001000000000000000000 = 0x0400
问题是,这是一个与8位值的本地数组所期望的顺序不同的顺序,但是你告诉CPU这些值是_u32所以它使用了它的本机endianess来进行操作。
答案 1 :(得分:0)
这些内在函数的结果似乎依赖于系统字节序,因此如果我们将代码移植到大端系统,我已经准备好了一个标志
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#pragma GCC error "Intrinsics used with little endian systems in mind. Start by reviewing all shifts operators."
#endif