SSE XMM点产品说明

时间:2018-05-29 19:34:00

标签: assembly sse

我无法理解汇编中的某段代码。任务是使用SSE算法和XMM寄存器找到2个向量的点积。方法是一次读取向量4个浮点数(意味着一个xmm寄存器将在迭代中保持4个)。最终结果是xmm寄存器,每个字节保存给定向量的乘积(x1 * y1 + ...)之和。

我没有得到的是之后出现的部分。完全将这些'结束'字节相加所需的全部内容,基本上是对最终寄存器的4个字节求和。我尝试在此找到一些东西,但没有占上风。我给出的是超出我的理解,我甚至尝试在纸上书写每一个计算,没有任何意义。在突出显示的部分中,计算实际总和并将其存储在xmm0的最低字节中。对此有任何见解是值得欢迎的。

.intel_syntax noprefix

.data
two: .int 2

.text
.global dot_product

############################################################################
##
## Function:
##
## void dot_product(float *x, float *y, int n, float *r);
##
## calculates the dot product of x and y (n lengths) and stores the result 
## in r
##
## -- float * x -- rdi -- 
## -- float * y -- rsi -- 
## -- int n -- rdx -- 
## -- float * r -- rcx -- 
##
############################################################################
dot_product:

        enter   0, 0


        mov r8, rcx
        mov r9, rdx


        mov     rax, 1
        cpuid
        test    rdx, 0x2000000
        jz not_supported


        mov     rdx, rsp
        and     rsp, 0xfffffffffffffff0
        sub     rsp, 512
        fxsave  [rsp]


        mov rcx, r9

    xorps xmm0, xmm0

next_four:

        cmp     rcx, 4
        jb next_one



        movups  xmm1, [rsi]
        movups  xmm2, [rdi]
    mulps xmm1, xmm2
    addps xmm0, xmm1



        add     rsi, 16
    add     rdi, 16  
        sub     rcx, 4
        jmp next_four

next_one:

        jrcxz finish




    movss  xmm1, [rsi]
        movss  xmm2, [rdi]
    mulss xmm1, xmm2
    addss xmm0, xmm1


        add     rsi, 4
    add     rdi, 4
        dec     rcx

        jmp next_one

finish: 

    #**summing the 4 bytes giving the actual dot product**
        movhlps xmm1, xmm0
        addps   xmm0, xmm1
        movaps  xmm1, xmm0
        shufps  xmm1, xmm1, 0b01010101
        addss   xmm0, xmm1


    movss   [r8], xmm0



        fxrstor [rsp]
        mov     rsp, rdx

done:

    leave
        ret

not_supported:


        mov rax, 1
        mov rbx, 1
        int 0x80

1 个答案:

答案 0 :(得分:3)

此最终代码仅使用普通的addps / addss指令在xmm0中添加4个打包浮点数。首先,它将2个最高的压缩浮点数复制到xmm1的低浮点数,因此xmm0 + xmm1可以用一条指令进行两次加法。 2个高花车是"不关心"。使用shufps重复将剩余浮动的最高位置复制到最低位置。想想眼前的选择器' shufps作为每个目标字的数组索引。唯一重要的是低两位,等于索引1,其移动1-> 0。其他人都只是占位符。然后,只需要一次添加。

xmm0: D | C | B | A
 +
xmm1: X | X | D | C      (movhlps xmm0)
-------------------
 =    X | X | B+D | A+C


xmm0: X | X | B+D | A+C
 +
xmm1: X | X | X   | B+D   (shufps xmm0)
-----------------------
 =    X | X | X   | A + B + C + D

在这里,X表示"不关心"。最后,总和位于由movss提取的最低位置。

2个附加指令,留在XMM寄存器中。否则,你需要3,有更明确的动作。

更多shufps详情:

将0b01010101值拆分为4个二进制索引:01 | 01 | 01 | 01,十进制为1 | 1 | 1 | 1.每个索引从源中选择源(​​以字为单位)。正如文档所描述的那样,对于较高的2个单词,这会变得更加复杂,但我们并不关心这些。结果是将word1复制到word0和word1,因为两个低选择器都是1。

编辑: HADDPS是另一种可能的实现,添加了邻居。两个HADDPS依次处理最终总和。知道哪个更快的唯一方法是对目标处理器进行基准测试,而不是最终的这个部分在功能的整体速度上应该是多少。