kiy*_*iyo 4 x86 sse simd endianness
我正在使用整数和SSE,并且对于字节序如何影响数据进出寄存器变得非常困惑.
最初我的理解如下.如果我有一个4字节整数的数组,那么内存将按如下方式布局,因为x86架构是小端的:
0D 0C 0B 0A 1D 1C 1B 1A 2D 2C 2B 2A .... nD nC nB nA
Run Code Online (Sandbox Code Playgroud)
其中字母A,B,C和D索引的整数元素内的字节数,和数字索引的元素.
在XMM寄存器中,我的理解是四个整数将按如下方式排列:
0A 0B 0C 0D 1A 1B 1C 1D 2A 2B 2C 2D 3A 3B 3C 3D
Run Code Online (Sandbox Code Playgroud)
但是,由于几个原因,我很确定这张照片是错误的.第一个是mm_load_si128内在的文档,它应该适用于任何整数数据,但在上面的图片应该只适用于一个字大小.同样有这个帖子:https://software.intel.com/en-us/forums/topic/286624.最后,我看到人们编写如下代码:
__declspec(align(16)) int32_t A[N];
__m128i* As = (__m128i*)A;
Run Code Online (Sandbox Code Playgroud)
关于字节序的维基百科文章说我应该想到内存地址从右到左增加.那么内存如下图呢?
nA nB nC nD ... 2A 2B 2C 2D 1A 1B 1C 1D 0A 0B 0C 0D
Run Code Online (Sandbox Code Playgroud)
然后在寄存器中:
3A 3B 3C 3D 2A 2B 2C 2D 1A 1B 1C 1D 0A 0B 0C 0D
Run Code Online (Sandbox Code Playgroud)
详细阐述Peter的评论,SIMD 实现肯定存在固有的隐式字节顺序,因为有些指令可以:
\nmovaps等movdqa指令movdqu本质上意味着字节顺序。pshufd,甚至pshufb使用整数索引来选择元素的运行时变量索引。这意味着元素具有类似于地址的内容,而宽元素包含多个可独立寻址的窄元素。(当然,不是内存地址空间的一部分,但与标量寄存器不同,我们有第二种方式来讨论宽元素内除了左/右移位之外的位置。这与使字节序成为内存问题的原因相同。)\选择寄存器内元素的索引以匹配内存中的顺序(小端),但也可能有所不同。pslld使用、psrld或全向量字节移位等方式跨SIMD 寄存器的pslldq。请注意,跨越“字节边界”包括各个、或组件内,因为(与上一点中提到的原因相同) ,寄存器随后可以被映像到内存中。整个向量的字节移位将一个字的低字节与相邻字的高字节分组,其方式取决于字节序。worddwordqwordbyte、word、dword或qword这类似于读取dword内存中的字节:它们有一个顺序。使用 qword 进行洗牌pshufd需要您在选择洗牌控件时考虑字节顺序,以保持正确的高:低双字对按正确的顺序分组。因此,如果您从不执行任何这些操作,则意味着您专门将 SIMD 内存映像与 SIMD 寄存器一起使用,并具有匹配的组件大小,并且从不以其他方式检查该内存,并且在这些 SIMD 上的操作中保持一致的组件大小寄存器,那么您不必担心 SIMD 字节顺序。否则,请继续阅读...
\n现在知道上面列出的 SIMD 操作暴露了字节顺序,那么它是什么?好吧,我们已经知道 Intel 架构是小尾数法,这意味着word、dword、 和qword(分别是 16 位、32 位和 64 位内存访问)是递归交换的。例如,存储一个单个qword会交换其两个的存储dwords,每个交换其两个words,每个交换其两个bytes。这导致 CPU 寄存器的内存映像byte总体上顺序相反。
为了与在相同大小上运行的非 SIMD 指令兼容,SIMD 寄存器的每个单独组件的内存映像对于每个组件大小都应该是位相同的,并且具有现有(小端)格式。word因此,先前存在的用于、dword和访问的非 SIMD 指令qword代表硬约束,并且这些 SIMD 组件必须表现出小端图像。
(qword, qword)但之前没有用于 128 位内存访问的非 SIMD 指令,因此 SIMD 寄存器本身的布局没有先验约束dqword。这实际上留下了我们可能在这里问的一个可能的问题:递归小端交换模式(word, dword, qword, ...?)是否也继续适用于dqword值?换句话说,在 SIMD 寄存器的 16 字节内存映像中,其两个qword分量\xe2\x80\x94 中数值最低有效的或较高有效的\xe2\x80\x94 存储在低地址 8中。 -字节?
\n\n解答:最低有效位
\nqword存储在 l\xcc\xb2o\xcc\xb2w\xcc\xb2e\xcc\xb2r\xcc\xb2 地址 8 字节处。
通过扩展模式以包含值,这保留了“小端”递归交换的对称性dqword。总而言之,128 位 SIMD 寄存器是小尾数法,因为它的内存映像[esi]有:
qword(SIMD 索引 0), qword ptr [esi]qword(SIMD 索引 1)。 qword ptr [esi + 8]这只是一个解释问题.我们从左到右读取/写入数字的数字,从最高位到最低位读取/写入数字.因此,对于具有最高字节A的32位数字,然后是B,然后是C和最低字节D,我们将读/写ABCD.我们做同样的注意128位整数.
3A3B3C3D 2A2B2C2D 1A1B1C1D 0A0B0C0D
Run Code Online (Sandbox Code Playgroud)
但是在一个小端系统中,它会读取和写入从最低地址到最高地址的数字
0D0C0B0A 1D1C1B1A 2D2C2B2A 3D3C3B3A
Run Code Online (Sandbox Code Playgroud)
对于16位整数,它是相同的逻辑.我们可以读/写它
7A7B 6A6B 5A5B 4A4B 3A3B 2A2B 1A1B 0A0B
Run Code Online (Sandbox Code Playgroud)
并且小端计算机从最低到最高地址读取/存储它
0B0A 1B1A 2B2A 3B3A 4B4A 5B5A 6A6B 7B7A
Run Code Online (Sandbox Code Playgroud)
这就是为什么只有一条指令在128位寄存器中读/写32位,16位和8字节整数:即movdqa和movaps(或未对齐的变量movdqu和movups).