抱歉,我没有好头衔......
我正在读这个帖子: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
哪种解释是正确的?
答案 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]