web-dev-qa-db-fra.com

Comment détecter la disponibilité SSE / SSE2 / AVX / AVX2 / AVX-512 / AVX-128-FMA / KCVI au moment de la compilation?

J'essaie d'optimiser certains calculs matriciels et je me demandais s'il était possible de détecter au moment de la compilation si SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI[1] est activé par le compilateur? Idéalement pour GCC et Clang, mais je ne peux gérer qu'avec un seul d'entre eux.

Je ne suis pas sûr que ce soit possible et j'utiliserai peut-être ma propre macro, mais je préférerais plutôt la détecter et demander à l'utilisateur de la sélectionner.


[1] "KCVI" signifie optimisations de l'instruction vectorielle de Knights Corner. Des bibliothèques comme FFTW détectent/utilisent ces nouvelles optimisations d'instructions.

49
Baptiste Wicht

La plupart des compilateurs définiront automatiquement:

__SSE__
__SSE2__
__SSE3__
__AVX__
__AVX2__

etc, selon les commutateurs de ligne de commande que vous passez. Vous pouvez facilement vérifier cela avec gcc (ou des compilateurs compatibles gcc tels que clang), comme ceci:

$ gcc -msse3 -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE_MATH__ 1

ou:

$ gcc -mavx2 -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __AVX__ 1
#define __AVX2__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1

ou pour simplement vérifier les macros prédéfinies pour une version par défaut sur votre plate-forme particulière:

$ gcc -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __SSE2_MATH__ 1
#define __SSE2__ 1
#define __SSE3__ 1
#define __SSE_MATH__ 1
#define __SSE__ 1
#define __SSSE3__ 1

Les processeurs Intel plus récents prennent en charge AVX-512, qui n'est pas un jeu d'instructions monolithique. On peut voir le support disponible à partir de GCC (version 6.2) pour deux exemples ci-dessous.

Voici Knights Landing:

$ gcc -march=knl -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __AVX__ 1
#define __AVX2__ 1
#define __AVX512CD__ 1
#define __AVX512ER__ 1
#define __AVX512F__ 1
#define __AVX512PF__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1

Voici Skylake AVX-512:

$ gcc -march=skylake-avx512 -dM -E - < /dev/null | egrep "SSE|AVX" | sort
#define __AVX__ 1
#define __AVX2__ 1
#define __AVX512BW__ 1
#define __AVX512CD__ 1
#define __AVX512DQ__ 1
#define __AVX512F__ 1
#define __AVX512VL__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1

Intel a divulgué des sous-ensembles AVX-512 supplémentaires (voir extensions ISA ). GCC (version 7) prend en charge les drapeaux du compilateur et les symboles de préprocesseur associés aux sous-ensembles 4FMAPS, 4VNNIW, IFMA, VBMI et VPOPCNTDQ d'AVX-512:

for i in 4fmaps 4vnniw ifma vbmi vpopcntdq ; do echo "==== $i ====" ; gcc -mavx512$i -dM -E - < /dev/null | egrep "AVX512" | sort ; done
==== 4fmaps ====
#define __AVX5124FMAPS__ 1
#define __AVX512F__ 1
==== 4vnniw ====
#define __AVX5124VNNIW__ 1
#define __AVX512F__ 1
==== ifma ====
#define __AVX512F__ 1
#define __AVX512IFMA__ 1
==== vbmi ====
#define __AVX512BW__ 1
#define __AVX512F__ 1
#define __AVX512VBMI__ 1
==== vpopcntdq ====
#define __AVX512F__ 1
#define __AVX512VPOPCNTDQ__ 1
80
Paul R