混淆XMM寄存器的位图

时间:2011-11-26 21:34:13

标签: bitmap sse

抱歉,我没有好头衔......

我正在读这个帖子:Vector Matrix Multiplication In SSE

原始海报有以下代码

// xmm0 = (v0,v1,v2,v3)
movups xmm0, [eax]

// xmm0 = (v0,v0,v0,v0)
// xmm1 = (v1,v1,v1,v1)
// xmm2 = (v2,v2,v2,v2)
// xmm3 = (v3,v3,v3,v3)
shufps xmm3, xmm0, 255
shufps xmm2, xmm0, 170
shufps xmm1, xmm0, 85
shufps xmm0, xmm0, 0

有人说如下:

  

但根据手册确实发生了什么:(a,b,c,d)表示a是位0到31,b是32到63位等等

// xmm0 = (v0,v1,v2,v3)
movups xmm0, [eax]

// xmm0 = (v0, v0, v0, v0)
shufps xmm0, xmm0, 0

这对我有意义,因为在线性数组模型[elt0,elt1,elt2,....] elt0是Array [0]。

令我困惑的是,根据手册,xmm寄存器的位图是[127 ... 0](见下图)。

我就像看着位图的原始海报,并认为[elt0,elt2,elt3,elt4]的最左边是“11”位。

所以,如果我想xmm0只包含v0

shufps xmm0, xmm0, 0xFF  // 11 11 11 11  === 0xFF

哪种解释是正确的?

enter image description here

1 个答案:

答案 0 :(得分:7)

可能存在一些混淆,因为xmm寄存器中的位(以及所有其他寄存器BTW)从右到左编号,即最低位在右侧,最高位在左侧:

xmm0 = [bit 127, bit 126, ..., bit 1, bit 0]

如果您将xmm寄存器的内容视为32位双字,它们也是从右到左排列的:

xmm0 = [dword 3, dword 2, dword 1, dword 0]

这种混乱的根源在于,如果你在内存中有一个数组

float A[4] = { 0.0f, 1.0f, 2.0f, 3.0f };

并将此数组加载到xmm寄存器中,元素以相反的顺序出现在xmm寄存器中:

; xmm0 = (A3 = 3.0f, A2 = 2.0f, A1 = 1.0f, A0 = 0.0f) after the load
movups xmm0, [A]

因此,将第一个双字复制到xmm寄存器中的所有双字的正确方法是

shufps xmm0, xmm0, 0

另外,如果你想将一个浮点数加载和广播到xmm寄存器的所有元素中,出于性能原因,最好使用

; MOVSS can be much faster than MOVUPS, and is never slower
; Load A[0] into low dword of xmm0
movss xmm0, [A]
; Copy low dword of xmm0 to all dwords of xmm0
shufps xmm0, xmm0, 0

AVX指令集(最近的Intel Sandy Bridge和AMD Bulldozer CPU支持)有一个特殊的指令vbroadcastss,它执行加载和广播:

; xmm0 = (A[0], A[0], A[0], A[0]) after execution of vbroadcastss
vbroadcastss xmm0, [A]

SSE3指令集包含一个类似的指令MOVDDUP,但是只适用于双打

const double B = 2.718281828459045;

; xmm0 = ( 2.718281828459045, 2.718281828459045 ) after execution of movddup
movddup xmm0, [B]