endianness如何与SIMD寄存器一起使用?

时间:2014-06-04 18:39:32

标签: x86 sse endianness simd

我正在处理整数和SSE,并且对于字节顺序如何影响数据进出寄存器感到非常困惑。

我的初步,错误,理解

最初我的理解如下。如果我有一个4字节整数的数组,那么内存将按如下方式布局,因为x86架构是小端的:

0D 0C 0B 0A 1D 1C 1B 1A 2D 2C 2B 2A .... nD nC nB nA

字母ABCD索引整数元素中的字节,数字为元素编制索引。

在XMM寄存器中,我的理解是四个整数将按如下方式排列:

0A 0B 0C 0D 1A 1B 1C 1D 2A 2B 2C 2D 3A 3B 3C 3D

然而,由于多种原因,我很确定这张照片是错误的。第一个是mm_load_si128内在函数的文档,它应该适用于任何整数数据,但在上面的图片中只能用于一个字大小。同样有这个帖子:https://software.intel.com/en-us/forums/topic/286624。最后,我看到人们编写如下代码:

__declspec(align(16)) int32_t A[N];
__m128i* As = (__m128i*)A;

可能正确的图片

维基百科关于字节序的文章说我应该想到内存地址从右到左增加。那么下面的内存图片怎么样呢?

nA nB nC nD ... 2A 2B 2C 2D 1A 1B 1C 1D 0A 0B 0C 0D

然后在寄存器中:

3A 3B 3C 3D 2A 2B 2C 2D 1A 1B 1C 1D 0A 0B 0C 0D

2 个答案:

答案 0 :(得分:5)

这只是一个解释问题。我们从左到右读取/写入数字的数字,从最高位到最低位读取/写入数字。因此,对于具有最高字节A的32位数字,然后是B,然后是C和最低字节D,我们将读/写ABCD。我们做同样的注意128位整数。

3A3B3C3D 2A2B2C2D 1A1B1C1D 0A0B0C0D

但是在一个小端系统中,它会读取和写入从最低地址到最高地址的数字,如此

0D0C0B0A 1D1C1B1A 2D2C2B2A 3D3C3B3A

对于16位整数,它是相同的逻辑。我们可以将其读/写为

7A7B 6A6B 5A5B 4A4B 3A3B 2A2B 1A1B 0A0B

并且小端计算机将其从最低到最高地址读取/存储为

0B0A 1B1A 2B2A 3B3A 4B4A 5B5A 6A6B 7B7A

这就是为什么只有一条指令在128位寄存器中读/写32位,16位和8字节整数:即movdqa和movaps(或未对齐的变量movdqu和movups)。

答案 1 :(得分:1)

Petercomment上进行详细说明时,由于存在可以执行以下操作的指令,因此SIMD实现无疑具有固有的隐式字节顺序:

  • 从内存读取或写入128位SIMD寄存器。由于必须始终通过 byte 偏移量(无论指令或存储或提取多少字节)来访问内存,并且随后可以通过其他非SIMD方式进行检查, movapsmovdqamovdqu等指令本质上隐含着字节顺序。
  • 向量的
  • Index 个元素,其指令类似于pshufd ,甚至使用pshufb使用运行时变量索引,它们都使用整数索引来选择元素。这意味着元素具有类似地址的内容,而宽元素包含多个可独立寻址的窄元素。 (当然,这不是内存地址空间的一部分,但与标量寄存器不同,我们有第二种方式来讨论宽元素中左/右移位以外的位置。这是使字节序成为内存问题的同一件事。) br /> 选择寄存器中元素的索引以匹配内存中的顺序(小尾数),但这可能有所不同。
  • pslldpsrld或整个向量的SIMD寄存器的 byte 边界内
  • 移位字节移位,例如pslldq等。请注意,跨越“字节边界”包括单个worddwordqword组成部分中的 (由于前一点中提到的相同原因),随后可以将寄存器映像到内存。整个向量的字节移位将一个单词的低字节与相邻单词的高字节组合在一起,具体方式取决于字节顺序。
  • 只需重新解释现有SIMD寄存器内容的组件大小(byteworddwordqword)。这类似于读取内存中dword的字节:它们具有顺序。使用pshufd对qword进行混排需要您在选择混洗控件时考虑字节顺序,以保持正确的高:低对的dword按正确的顺序分组。

因此,如果您从不做任何事情,这意味着您将SIMD内存映像与SIMD寄存器一起使用,且组件大小匹配,并且永远不要检查该内存,并且在这些SIMD上的操作中保持组件大小一致注册,那么您不必担心SIMD字节序。否则,请继续阅读...

由于我们知道SIMD具有字节顺序,所以它是什么?我们已经知道英特尔架构是little-endian,这意味着worddwordqword(分别是16位,32位和64位内存访问)是递归交换。例如,存储一个qword会交换其两个dwords的存储,每个存储会交换其两个words,每个存储会交换两个bytes。这样会导致CPU寄存器的存储器映像总体上具有相反的byte顺序。

为了与相同大小的非SIMD指令兼容,SIMD寄存器的每个单个组件的存储映像对于每个组件大小都应与现有位(相同, endian)格式。因此,worddwordqword访问的非SIMD指令的先前存在代表着严格的约束,并且那些SIMD组件必须表现出小端图像。

但是没有用于128位存储器访问的先前的非SIMD指令,因此(qword, qword) SIMD寄存器本身的dqword布局没有预先限制。实际上,这只剩下我们可能要问的一个问题:递归小端交换模式(worddwordqword...?)是否继续适用以及dqword的值?换句话说,在SIMD寄存器的16字节内存映像中,它的两个qword分量中的哪一个(数字上最低有效或更高有效)都存储在 -寻址的8个字节?

答案: 最低有效位qword存储在低地址8字节中。

通过扩展模式以同时包含dqword值,从而保留了“小尾数”递归交换的对称性。总而言之,[esi]处的128位SIMD寄存器的存储器映像具有:

  • 低位地址 qword上不重要的qword ptr [esi](SIMD索引0),
  • 位于 较高地址 qword上的qword ptr [esi + 8](SIMD索引1)有意义。