J'utilise les intrinsèques SSE/AVX/FMA d'Intel pour réaliser un inlining parfait des instructions SSE/AVX pour certaines fonctions mathématiques.
Étant donné le code suivant
#include <cmath>
#include <immintrin.h>
auto std_fma(float x, float y, float z)
{
return std::fma(x, y, z);
}
float _fma(float x, float y, float z)
{
_mm_store_ss(&x,
_mm_fmadd_ss(_mm_load_ss(&x), _mm_load_ss(&y), _mm_load_ss(&z))
);
return x;
}
float _sqrt(float x)
{
_mm_store_ss(&x,
_mm_sqrt_ss(_mm_load_ss(&x))
);
return x;
}
l'assemblage généré par clang 3.9 avec -march=x86-64 -mfma -O3
std_fma(float, float, float): # @std_fma(float, float, float)
vfmadd213ss xmm0, xmm1, xmm2
ret
_fma(float, float, float): # @_fma(float, float, float)
vxorps xmm3, xmm3, xmm3
vmovss xmm0, xmm3, xmm0 # xmm0 = xmm0[0],xmm3[1,2,3]
vmovss xmm1, xmm3, xmm1 # xmm1 = xmm1[0],xmm3[1,2,3]
vmovss xmm2, xmm3, xmm2 # xmm2 = xmm2[0],xmm3[1,2,3]
vfmadd213ss xmm0, xmm1, xmm2
ret
_sqrt(float): # @_sqrt(float)
vsqrtss xmm0, xmm0, xmm0
ret
tandis que le code généré pour _sqrt
est bien, il y a des inutiles vxorps
(qui met à zéro le registre xmm3 absolument inutilisé) et movss
instructions dans _fma
par rapport à std_fma
(qui reposent sur le compilateur intrinsèque std::fma)
l'assemblage généré par GCC 6.2 avec -march=x86-64 -mfma -O3
std_fma(float, float, float):
vfmadd132ss xmm0, xmm2, xmm1
ret
_fma(float, float, float):
vinsertps xmm1, xmm1, xmm1, 0xe
vinsertps xmm2, xmm2, xmm2, 0xe
vinsertps xmm0, xmm0, xmm0, 0xe
vfmadd132ss xmm0, xmm2, xmm1
ret
_sqrt(float):
vinsertps xmm0, xmm0, xmm0, 0xe
vsqrtss xmm0, xmm0, xmm0
ret
et voici beaucoup de choses inutiles vinsertps
instructions
Exemple de travail : https://godbolt.org/g/q1BQym
La convention d'appel x64 par défaut transmet les arguments des fonctions à virgule flottante dans les registres XMM, de sorte que ces vmovss
y vinsertps
devraient être éliminées. Pourquoi les compilateurs mentionnés les émettent-ils encore ? Est-il possible de s'en débarrasser sans assemblage en ligne ?
J'ai également essayé d'utiliser _mm_cvtss_f32
au lieu de _mm_store_ss
et de multiples conventions d'appel, mais rien n'a changé.