Recentemente, tentei ler assemblies do binário do meu código e descobri que muitas operações de ponto flutuante são feitas usando registradores XMM e instruções SSE. Por exemplo, o código a seguir:
float square(float a) {
float b = a + (a * a);
return b;
}
será compilado em
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
e o resultado é semelhante para outros compiladores. https://godbolt.org/z/G988PGo6j
E com -O3
bandeira
movaps xmm1, xmm0
mulss xmm0, xmm0
addss xmm0, xmm1
ret
Isso significa que as operações que usam registradores e instruções SIMD são geralmente mais rápidas do que usar registradores normais e a FPU?
Também estou curioso sobre casos específicos em que a decisão do compilador de usar SSE pode falhar.
O SSE foi desenvolvido como um substituto para a FPU x87, pois o design da FPU x87 é um pouco idiossincrático e difícil de gerar código. Os principais problemas são:
fxch
,fld
, e ineficientesfst(p)
. Isso é muito mais fácil de acertar com uma arquitetura baseada em registro como SSE.fxch
uma renomeação), levando a uma lacuna cada vez maior no desempenho entre x87 e SSE.Recomendo usar somente a FPU x87 se o tamanho do código for um problema ou se você precisar do formato de ponto flutuante de 80 bits. Caso contrário, fique com SSE ou (em processadores recentes) AVX.