SSE XMM寄存器向量点积求和阶段汇编代码解析求助
没问题!我来帮你拆解这段把XMM寄存器里四个累加结果求和的核心代码——这部分确实是SSE向量点积实现里的关键收尾步骤,咱们一步步来理清楚:
前提铺垫
在前面的next_four和next_one循环执行完后,xmm0寄存器里已经存储了4组独立的乘积累加和。我们可以把128位的xmm0拆成4个32位单精度浮点数,结构是:
xmm0 = [S0, S1, S2, S3]
其中S0是前4个元素的乘积累加结果,S1是接下来4个元素的结果,以此类推。我们的目标是把这四个数相加,得到最终的点积总和S0 + S1 + S2 + S3。
逐行解析求和代码段
下面是需要重点理解的收尾代码:
#**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
movhlps xmm1, xmm0
这个指令的作用是把xmm0的高64位(也就是包含S2、S3的两个浮点数),移动到xmm1的低64位。执行后:xmm0保持不变:[S0, S1, S2, S3]xmm1的低两位变为[S2, S3](高两位的旧值可以忽略,我们后续用不到)
addps xmm0, xmm1addps是逐元素向量加法,会把两个XMM寄存器对应位置的浮点数相加。执行后:xmm0的低两位变成S0+S2和S1+S3,高两位的结果无意义可以忽略- 此时
xmm0的有效内容是:[S0+S2, S1+S3, _, _]
movaps xmm1, xmm0
把xmm0的完整内容复制到xmm1,现在xmm1也持有[S0+S2, S1+S3, _, _]。shufps xmm1, xmm1, 0b01010101
这是SSE的洗牌指令,0b01010101是控制掩码。这个掩码的作用是让xmm1的所有四个位置都替换成原来的第2个元素(也就是S1+S3)。执行后:xmm1变成:[S1+S3, S1+S3, S1+S3, S1+S3]
addss xmm0, xmm1addss是单精度标量加法,只会处理两个XMM寄存器的最低32位。这里就是把xmm0里的S0+S2和xmm1里的S1+S3相加,得到最终的总点积S0+S1+S2+S3,结果存在xmm0的最低位。movss [r8], xmm0
把xmm0最低位的最终结果写入到输出指针r8指向的内存地址,完成点积计算。
补充说明
这种求和方式是SSE早期没有haddps(水平加法指令)时的经典实现——通过拆分高半部分、逐元素相加、洗牌对齐,最终完成四个数的水平求和。如果是支持SSE3的CPU,其实可以用haddps xmm0, xmm0一步完成前两步的相加,代码会更简洁,但这段代码为了兼容性用了更基础的指令。
内容的提问来源于stack exchange,提问作者monolith937

