我最近尝试读取代码的二进制程序集,发现很多浮点运算是使用 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。