Quels fichiers d'en-tête fournissent les éléments intrinsèques des différentes extensions de jeu d'instructions x86 SIMD (MMX, SSE, AVX, ...)? Il semble impossible de trouver une telle liste en ligne. Corrige moi si je me trompe.
Quels fichiers d'en-tête fournissent les éléments intrinsèques des différentes extensions de jeu d'instructions x86 SIMD (MMX, SSE, AVX, ...)? Il semble impossible de trouver une telle liste en ligne. Corrige moi si je me trompe.
Réponses:
Ces jours-ci, vous devriez normalement simplement inclure <immintrin.h>
. Cela comprend tout.
GCC et clang vous empêcheront d'utiliser les intrinsèques pour les instructions que vous n'avez pas activées au moment de la compilation (par exemple avec -march=native
ou-mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
ou autre).
MSVC et ICC vous permettra d' utiliser sans activer quoi que ce soit intrinsics au moment de la compilation, mais vous encore devraient permettre AVX avant d' utiliser intrinsics AVX.
Historiquement (avant immintrin.h
de tout insérer), vous deviez inclure manuellement un en-tête pour le plus haut niveau d'intrinsèque que vous vouliez.
Cela peut toujours être utile avec MSVC et ICC pour vous empêcher d'utiliser des jeux d'instructions dont vous ne voulez pas avoir besoin.
<mmintrin.h> MMX
<xmmintrin.h> SSE
<emmintrin.h> SSE2
<pmmintrin.h> SSE3
<tmmintrin.h> SSSE3
<smmintrin.h> SSE4.1
<nmmintrin.h> SSE4.2
<ammintrin.h> SSE4A
<wmmintrin.h> AES
<immintrin.h> AVX, AVX2, FMA
Y compris l'un de ces pulls dans tous les précédents (sauf SSE4A uniquement AMD: immintrin.h
ne tire pas cela)
Certains compilateurs ont également <zmmintrin.h>
pour AVX512.
<zmmintrin.h>
directement; gcc ne le fournit même pas. Utilisez simplement<immintrin.h>
ou le plus complet <x86intrin.h>
. Cette réponse est fondamentalement obsolète, sauf si vous évitez intentionnellement d'inclure des éléments intrinsèques pour les versions plus récentes de SSE car votre compilateur ne se plaint pas lorsque vous utilisez une instruction SSE4.1 lors de la compilation pour SSE2. (gcc / clang ne se plaignent, vous devriez simplement utiliser immintrin.h pour les IDK sur les autres..)
Sur GCC / clang, si vous utilisez uniquement
#include <x86intrin.h>
il inclura tous les en-têtes SSE / AVX qui sont activés selon les commutateurs du compilateur comme -march=haswell
ou juste -march=native
. De plus, certaines instructions spécifiques à x86 aiment bswap
ou ror
deviennent disponibles en tant qu'intrinsèques.
L'équivalent MSVC de cet en-tête <intrin.h>
Si vous voulez juste un SIMD portable, utilisez #include <immintrin.h>
MSVC, ICC et gcc / clang (et d'autres compilateurs comme Sun je pense) prennent tous en charge cet en-tête pour les intrinsèques SIMD documentés par le seul outil de recherche / recherche intrinsèques d'Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide /
<x86intrin.h>
, mais <intrin.h>
réalise un effet similaire. Vous avez toujours besoin d'une compilation conditionnelle, bien sûr. :-(
#include <immintrin.h>
. Utilisez-le pour les intrinsèques SIMD. Vous n'avez besoin que du plus grand (et légèrement plus lent à compilateur) x86intrin.h
ou intrin.h
si vous avez besoin de trucs comme les intrinsèques de rotation d'entiers / d'analyse de bits (bien qu'Intel documente certains de ceux-ci comme étant disponibles immintrin.h
dans leur guide des intrinsèques ).
x86intrin.h
/ intrin.h
mais pas dans immintrin.h
.
Le nom de l'en-tête dépend de votre compilateur et de l'architecture cible.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
spe.h
Vous pouvez gérer tous ces cas avec des directives de prétraitement conditionnel:
#if defined(_MSC_VER)
/* Microsoft C/C++-compatible compiler */
#include <intrin.h>
#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
/* GCC-compatible compiler, targeting x86/x86-64 */
#include <x86intrin.h>
#elif defined(__GNUC__) && defined(__ARM_NEON__)
/* GCC-compatible compiler, targeting ARM with NEON */
#include <arm_neon.h>
#elif defined(__GNUC__) && defined(__IWMMXT__)
/* GCC-compatible compiler, targeting ARM with WMMX */
#include <mmintrin.h>
#elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__))
/* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */
#include <altivec.h>
#elif defined(__GNUC__) && defined(__SPE__)
/* GCC-compatible compiler, targeting PowerPC with SPE */
#include <spe.h>
#endif
De cette page
+----------------+------------------------------------------------------------------------------------------+
| Header | Purpose |
+----------------+------------------------------------------------------------------------------------------+
| x86intrin.h | Everything, including non-vector x86 instructions like _rdtsc(). |
| mmintrin.h | MMX (Pentium MMX!) |
| mm3dnow.h | 3dnow! (K6-2) (deprecated) |
| xmmintrin.h | SSE + MMX (Pentium 3, Athlon XP) |
| emmintrin.h | SSE2 + SSE + MMX (Pentium 4, Athlon 64) |
| pmmintrin.h | SSE3 + SSE2 + SSE + MMX (Pentium 4 Prescott, Athlon 64 San Diego) |
| tmmintrin.h | SSSE3 + SSE3 + SSE2 + SSE + MMX (Core 2, Bulldozer) |
| popcntintrin.h | POPCNT (Nehalem (Core i7), Phenom) |
| ammintrin.h | SSE4A + SSE3 + SSE2 + SSE + MMX (AMD-only, starting with Phenom) |
| smmintrin.h | SSE4_1 + SSSE3 + SSE3 + SSE2 + SSE + MMX (Penryn, Bulldozer) |
| nmmintrin.h | SSE4_2 + SSE4_1 + SSSE3 + SSE3 + SSE2 + SSE + MMX (Nehalem (aka Core i7), Bulldozer) |
| wmmintrin.h | AES (Core i7 Westmere, Bulldozer) |
| immintrin.h | AVX, AVX2, AVX512, all SSE+MMX (except SSE4A and XOP), popcnt, BMI/BMI2, FMA |
+----------------+------------------------------------------------------------------------------------------+
Donc, en général, vous pouvez simplement inclure immintrin.h
pour obtenir toutes les extensions Intel, ou x86intrin.h
si vous voulez tout, y compris_bit_scan_forward
et_rdtsc
, ainsi que toutes les intrinsèques vectorielles incluent celles uniquement AMD. Si vous êtes contre l'inclusion de plus dont vous avez réellement besoin, vous pouvez choisir la bonne inclusion en regardant le tableau.
x86intrin.h
est la méthode recommandée pour obtenir des éléments intrinsèques pour AMD XOP (Bulldozer uniquement, pas même les futurs processeurs AMD) , plutôt que d'avoir son propre en-tête.
Certains compilateurs généreront toujours des messages d'erreur si vous utilisez des éléments intrinsèques pour des jeux d'instructions que vous n'avez pas activés (par exemple _mm_fmadd_ps
sans activer fma, même si vous incluez immintrin.h
et activez AVX2).
smmintrin
(SSE4.1) est Penryn (45nm Core2), pas Nehalem ("i7"). Pouvons-nous arrêter d'utiliser «i7» comme nom d'architecture? Cela n'a plus de sens maintenant qu'Intel continue de l'utiliser pour la famille SnB .
immintrin.h
ne semble pas inclure _popcnt32
et _popcnt64
(à ne pas confondre avec ceux de popcntintrin.h
!) intrinsèques sur GCC 9.1.0. Il semble donc que cela x86intrin.h
sert toujours un objectif.
Comme beaucoup de réponses et de commentaires l'ont indiqué, <x86intrin.h>
est l' en-tête complet pour x86 [-64] SIMD intrinsèques. Il fournit également des instructions de prise en charge intrinsèques pour d'autres extensions ISA. gcc
,, clang
et icc
ont tous réglé sur ce point. J'avais besoin de fouiller sur les versions qui prennent en charge l'en-tête, et j'ai pensé qu'il pourrait être utile d'énumérer quelques résultats ...
gcc : le support pour x86intrin.h
apparaît en premier dans gcc-4.5.0
. La gcc-4
série de versions n'est plus maintenue, tandis que gcc-6.x
la série de versions stables actuelle . gcc-5
a également introduit l' __has_include
extension présente dans toutes les clang-3.x
versions. gcc-7
est en pré-version (test de régression, etc.) et suivant le schéma de version actuel, sera publié sous la forme gcc-7.1.0
.
clang : x86intrin.h
semble avoir été pris en charge pour toutes les clang-3.x
versions. La dernière version stable est clang (LLVM) 3.9.1
. La branche de développement est clang (LLVM) 5.0.0
. On ne sait pas ce qui est arrivé à la 4.x
série.
Apple retentit : ennuyeux, le versionnage d'Apple ne correspond pas à celui des LLVM
projets. Cela dit, la version actuelle:, clang-800.0.42.1
est basée sur LLVM 3.9.0
. La première LLVM 3.0
version basée semble être de Apple clang 2.1
retour Xcode 4.1
. LLVM 3.1
apparaît d'abord avec Apple clang 3.1
(une coïncidence numérique) dans Xcode 4.3.3
.
Apple définit également __apple_build_version__
par exemple 8000042
. Cela semble être le schéma de version le plus stable et strictement ascendant disponible. Si vous ne souhaitez pas prendre en charge les compilateurs hérités, définissez l'une de ces valeurs comme une exigence minimale.
Toute version récente de clang
, y compris les versions Apple, ne devrait donc avoir aucun problème avec x86intrin.h
. Bien sûr, gcc-5
vous pouvez toujours utiliser les éléments suivants:
#if defined (__has_include) && (__has_include(<x86intrin.h>))
#include <x86intrin.h>
#else
#error "upgrade your compiler. it's free..."
#endif
Une astuce sur laquelle vous ne pouvez pas vraiment compter consiste à utiliser les __GNUC__
versions dans clang
. La gestion des versions est, pour des raisons historiques, bloquée 4.2.1
. Une version qui précède l'en- x86intrin.h
tête. C'est parfois utile pour, par exemple, des extensions GNU C simples qui sont restées rétrocompatibles.
icc : pour autant que je sache, l'en- x86intrin.h
tête est pris en charge depuis au moins Intel C ++ 16.0. Le test de version peut par réalisée avec: #if (__INTEL_COMPILER >= 1600)
. Cette version (et peut-être des versions antérieures) fournit également un support pour l' __has_include
extension.
MSVC : Il semble que ce MSVC++ 12.0 (Visual Studio 2013)
soit la première version à fournir l'en- intrin.h
tête - pas x86intrin.h
... cela suggère: #if (_MSC_VER >= 1800)
comme test de version. Bien sûr, si vous essayez d'écrire du code portable sur tous ces différents compilateurs, le nom de l'en-tête sur cette plate-forme sera le moindre de vos problèmes.
#include <x86intrin.h>
ce qui rassemble tout ce dont vous avez besoin.