我最近尝试阅读我的代码的二进制汇编,发现很多浮点运算都是使用 XMM 寄存器和 SSE 指令完成的。例如,以下代码:
float square(float a) {
float b = a + (a * a);
return b;
}
将被编译成
push rbp
mov rbp, rsp
movss DWORD PTR [rbp-20], xmm0
movss xmm0, DWORD PTR [rbp-20]
mulss xmm0, xmm0
movss xmm1, DWORD PTR [rbp-20]
addss xmm0, xmm1
movss DWORD PTR [rbp-4], xmm0
movss xmm0, DWORD PTR [rbp-4]
pop rbp
ret
其他编译器的结果也类似。https ://godbolt.org/z/G988PGo6j
并带有-O3
旗帜
movaps xmm1, xmm0
mulss xmm0, xmm0
addss xmm0, xmm1
ret
这是否意味着使用 SIMD 寄存器和指令的操作通常比使用普通寄存器和 FPU 更快?
另外,我很好奇编译器决定使用 SSE 可能会失败的具体情况。
SSE 是作为 x87 FPU 的替代品而开发的,因为 x87 FPU 的设计有点特殊,很难为其生成代码。主要问题是:
fxch
、fld
和fst(p)
指令。使用基于寄存器的架构(如 SSE)更容易做到这一点。fxch
重新命名),导致 x87 和 SSE 之间的性能差距越来越大。如果代码大小是个问题或者您需要 80 位浮点格式,我建议仅使用 x87 FPU。否则请坚持使用 SSE 或(在最近的处理器上)AVX。