C++ 为什么在Neon和SSE中,右移实际上会向左移动(反之亦然)?
(注意,我使用Neon来避免处理16位数据类型之间的转换) 为什么内在论中的“左移”实际上是“右移” 我记得在使用C++ 为什么在Neon和SSE中,右移实际上会向左移动(反之亦然)?,c++,sse,shift,neon,intrinsics,C++,Sse,Shift,Neon,Intrinsics,(注意,我使用Neon来避免处理16位数据类型之间的转换) 为什么内在论中的“左移”实际上是“右移” 我记得在使用\u mm\u slli\u si128时发现了相同的情况(尽管情况有所不同,但换班后的结果如下所示: // b = _mm_slli_si128(a,1); // 0 141 138 145 147 144 140 147 153 154 147 149 146 155 152 147 这是因为endianness吗?它会随着平台的变化而变化吗?这些本质的结果似乎取决于系统的en
\u mm\u slli\u si128
时发现了相同的情况(尽管情况有所不同,但换班后的结果如下所示:
// b = _mm_slli_si128(a,1);
// 0 141 138 145 147 144 140 147 153 154 147 149 146 155 152 147
这是因为endianness吗?它会随着平台的变化而变化吗?这些本质的结果似乎取决于系统的endianness,因此,如果我们将代码移植到big endian系统,我已经准备好升起一个旗子
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#pragma GCC error "Intrinsics used with little endian systems in mind. Start by reviewing all shifts operators."
#endif
请参阅。这些内部函数的结果似乎取决于系统端性,因此,如果我们要将代码移植到big-endian系统,我已经做好了准备
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#pragma GCC error "Intrinsics used with little endian systems in mind. Start by reviewing all shifts operators."
#endif
请参阅。您说“这是因为endianess”,但更多的是类型滥用。您假设机器的位顺序跨越字节/字边界,并且您的非字节指令将本地endianess强加于操作(您使用的是一条32指令,该指令要求值为无符号32位值,而不是8位值的数组)
正如您所说,您要求它通过/asking/it以32位单位移位值来移位一系列无符号字符值
不幸的是,如果您想对它们进行架构转换,就需要将它们按架构顺序排列
否则,您可能需要寻找blit或move指令,但您无法在不支付体系结构成本的情况下人工将机器类型强制到机器寄存器中。Endianness将只是您最头疼的问题之一(对齐、填充等)
---后期编辑---
<>从根本上说,你混淆了字节和位的移位,我们认为最重要的位是“左”
但是您要移动的值是32位字,在一个小的endian机器上,这意味着对于一个32位字,每个后续地址都会增加一个更有效的值字节:
bit numbers
1111111111111111
87654321fedcba0987654321fedcba09
表示32位值0x0001的步骤
1111111111111111
87654321fedcba0987654321fedcba09
00000001000000000000000000000000
将其向左移动2个位置
00000001000000000000000000000000
v<
00000100000000000000000000000000
如果以字节为单位思考,这看起来像是右移。但我们告诉这个小小的endian CPU,我们正在处理uint32,这意味着:
1111111111111111
87654321fedcba0987654321fedcba09
word01 word02 word03 word04
00000001000000000000000000000000 = 0x0001
00000100000000000000000000000000 = 0x0004
00000000000001000000000000000000 = 0x0400
问题是,这与您期望的8位值的本地数组的顺序不同,但您告诉CPU这些值是_u32,因此它使用它的本机endianess进行操作。您说“这是因为endianess吗?”但这更多的是类型滥用的情况。您正在假设机器的位顺序跨越字节/字边界,并且您的非字节指令将本地endianess强加于操作(您使用的是_u32指令,它期望值为无符号32位值,而不是8位值的数组)
正如您所说,您要求它通过/asking/it以32位单位移位值来移位一系列无符号字符值
不幸的是,如果您想对它们进行架构转换,就需要将它们按架构顺序排列
否则,您可能需要寻找blit或move指令,但您无法在不支付体系结构成本的情况下人工将机器类型强制到机器寄存器中。Endianness将只是您最头疼的问题之一(对齐、填充等)
---后期编辑---
<>从根本上说,你混淆了字节和位的移位,我们认为最重要的位是“左”
但是您要移动的值是32位字,在一个小的endian机器上,这意味着对于一个32位字,每个后续地址都会增加一个更有效的值字节:
bit numbers
1111111111111111
87654321fedcba0987654321fedcba09
表示32位值0x0001的步骤
1111111111111111
87654321fedcba0987654321fedcba09
00000001000000000000000000000000
将其向左移动2个位置
00000001000000000000000000000000
v<
00000100000000000000000000000000
如果以字节为单位思考,这看起来像是右移。但我们告诉这个小小的endian CPU,我们正在处理uint32,这意味着:
1111111111111111
87654321fedcba0987654321fedcba09
word01 word02 word03 word04
00000001000000000000000000000000 = 0x0001
00000100000000000000000000000000 = 0x0004
00000000000001000000000000000000 = 0x0400
问题是,这是一个与8个值的本地数组不同的顺序,但是你告诉CPU值是u32,所以它使用了本机的二进制数来运行。在C++中,联合不能绕过转换。@ Beoviigt也许我用的是“旁路”这个词。以错误的方式。如果我使用链接中描述的数据类型,我可以使用它作为函数的输入和输出,如
vshlq\u n\u u32
,vget\u low\u u8
,vuzp\u u8
…也许你可以将手写顺序改为小尾端:在右边写较低的地址字,这样更明显。是的,这是endianness.如果您将其打印为四个无符号32位值的集合,您将看到指令将它们乘以256,并删除高位字节(感谢更正)。@user3528438问题是,实际上我正在处理像素(无符号字符值)并且它们是按顺序存储的。在C++中,联合不能绕过转换。@ Booigigt也许我用的是“旁路”这个词。以错误的方式。如果我使用链接中描述的数据类型,我可以使用它作为函数的输入和输出,如vshlq\u n\u u32
,vget\u low\u u8
,vuzp\u u8
…也许你可以将手写顺序改为小尾端:在右边写较低的地址字,这样更明显。是的,这是endianness.如果您将其打印为四个无符号32位值的集合,您将看到指令将它们乘以256,并删除高位字节(感谢更正)。@user3528438问题是,实际上我正在处理像素(无符号字符值),并按该顺序存储。Endianness不会影响移位指令:右移位始终从MSB移动到LSB,左移位始终从LSB移动到MSB。但是Endianness确实会影响将数据加载到寄存器的方式:在大端模式下,vector load将LSB中较低的地址字节放入寄存器,而在小端模式下,vector load将低位地址字节放入向量寄存器的LSB中