2015-12-14 4 views
7

MSVC prend en charge les instructions AVX/AVX2 depuis des années et selon this msdn blog post, il peut générer automatiquement des instructions fused-multiply-add (FMA).Générer automatiquement des instructions FMA dans MSVC

Cependant, aucune des fonctions suivantes à l'instruction FMA compilez:

float func1(float x, float y, float z) 
{ 
    return x * y + z; 
} 

float func2(float x, float y, float z) 
{ 
    return std::fma(x,y,z); 
} 

Pire encore, std :: fma n'est pas mis en œuvre comme une seule instruction FMA, il effectue terriblement, beaucoup plus lent qu'un x * y + z ordinaire (la une mauvaise performance de std :: fma est attendue si l'implémentation ne repose pas sur l'instruction FMA). Je compile avec /arch:AVX2 /O2 /Qvec drapeaux. Également essayé avec /fp:fast, sans succès. Donc, la question est de savoir comment MSVC peut-il forcer l'émission automatique d'instructions FMA?

MISE À JOUR

Il y a un #pragma fp_contract (on|off) qui (ressemble) ne fait rien.

+2

Vous devez probablement utiliser [fonctions intrinsèques du compilateur] (https://msdn.microsoft.com/fr-fr/library/hh977022.aspx). –

+1

Je connais ces intrinsèques mais cela ne m'intéresse pas. Je veux que le compilateur génère automatiquement les instructions, tout comme GCC et Clang. C'est 2016.De plus, il y a de nombreux cas où vous ne pouvez pas utiliser explicitement ces instrinsics, car le fusionné-multiplier-ajouter n'appartient pas à une seule opération ou fonction, il vient d'une expression optimisée en ligne multiple. – plasmacel

+2

Bonne chance. D'après mon expérience, MS ne se soucie pas de cette partie du compilateur. Même lorsque vous utilisez des intrinsèques, il génère une génération de code assez terrible pour les instructions FMA. Si vous vous intéressez aux performances des FMA sous Windows, utilisez un autre compilateur. (ICC est assez bon) – Mysticial

Répondre

3

J'ai résolu ce problème de longue date.

Comme il se trouve, drapeaux /fp:fast, /arch:AVX2 et /O1 (ou au-dessus /O1) ne suffisent pas pour le mode studio 2015 visuels pour émettre des instructions FMA en mode 32 bits. Vous avez également besoin du "Whole Program Optimization" activé avec le drapeau /GL.

Ensuite Visual Studio 2015 va générer une instruction FMA vfmadd213ss pour

float func1(float x, float y, float z) 
{ 
    return x * y + z; 
} 

En ce qui concerne std::fma, j'ai ouvert un bug at Microsoft Connect. Ils ont confirmé le comportement que std::fma ne compile pas aux instructions FMA, car le compilateur ne le traite pas comme intrinsèque. Selon leur réponse, il sera corrigé dans une future mise à jour pour obtenir le meilleur codegen possible.

+0

Je n'avais pas besoin de '/ GL'. Je pense que vous compilez en mode 32 bits. C'est bête. –

+0

La question n'a pas mentionné x64 et dans certaines circonstances, il n'est pas possible de compiler en mode 64 bits à cause des dépendances. – plasmacel

3

MSVC 2015 génère une instruction fma pour les opérations scalaires mais pas pour les opérations vectorielles (sauf si vous utilisez explicitement une fma intrinsèque).

I compilé le code suivant

//foo.cpp 
float mul_add(float a, float b, float c) { 
    return a*b + c; 
} 

//MSVC cannot handle vectors as function parameters so use const references 
__m256 mul_addv(__m256 const &a, __m256 const &b, __m256 const &c) { 
    return _mm256_add_ps(_mm256_mul_ps(a, b), c); 
} 

avec

cl /c /O2 /arch:AVX2 /fp:fast /FA foo.cpp 

dans MSVC2015 et il a produit l'ensemble suivant

;mul_add 
vmovaps xmm3, xmm1 
vfmadd213ss xmm3, xmm0, xmm2 
vmovaps xmm0, xmm3 

et

;mul_addv 
vmovups ymm0, YMMWORD PTR [rcx] 
vmulps ymm1, ymm0, YMMWORD PTR [rdx] 
vaddps ymm0, ymm1, YMMWORD PTR [r8] 
+0

pour moi, en utilisant '/ fp: fast','/arch: AVX2' et '/ O2' il compile à et' fmul' et un 'fadd' – plasmacel

+0

@plasmacel, ce sont des instructions x87. Vous devez compiler en mode 32 bits. Compiler en mode 64 bits. –