Quali file di intestazione forniscono le informazioni intrinseche per le diverse estensioni del set di istruzioni SIMD x86 (MMX, SSE, AVX, ...)? Sembra impossibile trovare un simile elenco online. Correggimi se sbaglio.
Quali file di intestazione forniscono le informazioni intrinseche per le diverse estensioni del set di istruzioni SIMD x86 (MMX, SSE, AVX, ...)? Sembra impossibile trovare un simile elenco online. Correggimi se sbaglio.
Risposte:
In questi giorni dovresti normalmente includere solo <immintrin.h>
. Include tutto.
GCC e clang ti impediranno di usare intrinseci per istruzioni che non hai abilitato in fase di compilazione (ad es. Con -march=native
o -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
o altro).
MSVC e ICC consentono di utilizzare intrinseche senza attivare nulla in fase di compilazione, ma è comunque dovrebbe consentire AVX prima di utilizzare intrinseche AVX.
Storicamente (prima immintrin.h
di inserire tutto), è stato necessario includere manualmente un'intestazione per il livello più elevato di elementi intrinseci desiderati.
Questo può essere ancora utile con MSVC e ICC per impedirti di usare le istruzioni che non desideri richiedere.
<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
Incluso uno di questi pull in tutti i precedenti (tranne SSE4A solo AMD: immintrin.h
non lo inserisce )
Alcuni compilatori hanno anche <zmmintrin.h>
per AVX512.
<zmmintrin.h>
direttamente; gcc non lo fornisce nemmeno. Basta usare<immintrin.h>
o anche il più completo <x86intrin.h>
. Questa risposta è sostanzialmente obsoleta, a meno che tu non stia evitando intenzionalmente di includere elementi intrinseci per le nuove versioni di SSE perché il compilatore non si lamenta quando usi un'istruzione SSE4.1 durante la compilazione per SSE2. (gcc / clang si lamentano, quindi dovresti semplicemente usare immintrin.h per loro. IDK sugli altri.)
Su GCC / clang, se usi solo
#include <x86intrin.h>
includerà tutte le intestazioni SSE / AVX che sono abilitate in base agli switch del compilatore come -march=haswell
o solo -march=native
. Inoltre, alcune istruzioni specifiche x86 gradiscono bswap
o ror
diventano disponibili come intrinseche.
L'equivalente MSVC di questa intestazione <intrin.h>
Se vuoi solo un SIMD portatile, usa #include <immintrin.h>
MSVC, ICC e gcc / clang (e altri compilatori come Sun penso) supportano tutti questa intestazione per i intrinseci SIMD documentati dall'unico strumento di ricerca / ricerca di intrinseci di Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide /
<x86intrin.h>
, ma <intrin.h>
ottiene un effetto simile. Hai ancora bisogno di compilazione condizionale, ovviamente. :-(
#include <immintrin.h>
. Usalo per intrinseci SIMD. Hai solo bisogno di un formato ancora più grande (e leggermente più lento per il compilatore) x86intrin.h
o intrin.h
se hai bisogno di cose come i valori intrinseci di rotazione / scansione a bit (anche se Intel documenta alcuni di quelli disponibili immintrin.h
nella loro guida ai valori intrinseci ).
x86intrin.h
/ intrin.h
ma non in immintrin.h
.
Il nome dell'intestazione dipende dal compilatore e dall'architettura di destinazione.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
spe.h
È possibile gestire tutti questi casi con direttive di preelaborazione condizionali:
#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
Da questa pagina
+----------------+------------------------------------------------------------------------------------------+
| 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 |
+----------------+------------------------------------------------------------------------------------------+
Quindi, in generale, puoi semplicemente includere immintrin.h
per ottenere tutte le estensioni Intel, o x86intrin.h
se vuoi tutto, inclusi _bit_scan_forward
e _rdtsc
, così come tutti gli intrinseci vettoriali includono solo AMD. Se sei contrario a includere più cose di cui hai effettivamente bisogno, puoi scegliere l'inclusione giusta guardando il tavolo.
x86intrin.h
è il modo consigliato per ottenere elementi intrinseci per AMD XOP (solo Bulldozer, nemmeno future CPU AMD) , piuttosto che avere una propria intestazione.
Alcuni compilatori genereranno comunque messaggi di errore se si utilizzano intrinseci per i set di istruzioni non abilitati (ad esempio _mm_fmadd_ps
senza abilitare fma, anche se si include immintrin.h
e si abilita AVX2).
smmintrin
(SSE4.1) è Penryn (45nm Core2), non Nehalem ("i7"). Possiamo smettere di usare "i7" come nome di architettura? Non ha senso ora che Intel abbia continuato a usarlo per la famiglia SnB .
immintrin.h
non sembra includere _popcnt32
e _popcnt64
(da non confondere con quelli in popcntintrin.h
!) intrinseci su GCC 9.1.0. Quindi sembra x86intrin.h
ancora servire a uno scopo.
Come molte delle risposte e dei commenti hanno affermato, <x86intrin.h>
è l' intestazione completa per intrinseci x86 [-64] SIMD. Fornisce inoltre istruzioni di supporto intrinseco per altre estensioni ISA. gcc
, clang
e icc
tutti si sono stabiliti su questo. Avevo bisogno di scavare sulle versioni che supportano l'intestazione e ho pensato che potesse essere utile elencare alcuni risultati ...
gcc : il supporto per il x86intrin.h
primo appare in gcc-4.5.0
. La gcc-4
serie di versioni non viene più mantenuta, mentre gcc-6.x
è l' attuale serie di versioni stabili. gcc-5
ha inoltre introdotto l' __has_include
estensione presente in tutte le clang-3.x
versioni. gcc-7
è in pre-release (test di regressione, ecc.) e seguendo l'attuale schema di versione, verrà rilasciato come gcc-7.1.0
.
clang : x86intrin.h
sembra essere stato supportato per tutte le clang-3.x
versioni. L'ultima versione stabile è clang (LLVM) 3.9.1
. Il ramo di sviluppo è clang (LLVM) 5.0.0
. Non è chiaro cosa sia successo alla 4.x
serie.
Clang di Apple : fastidiosamente, il versioning di Apple non corrisponde a quello dei LLVM
progetti. Detto questo, l'attuale versione:, clang-800.0.42.1
si basa su LLVM 3.9.0
. La prima LLVM 3.0
versione basata sembra essere Apple clang 2.1
tornata Xcode 4.1
. LLVM 3.1
appare per la prima volta Apple clang 3.1
(una coincidenza numerica) in Xcode 4.3.3
.
Apple definisce anche __apple_build_version__
ad es 8000042
. Questo sembra lo schema di versione più stabile e rigorosamente crescente disponibile. Se non si desidera supportare compilatori legacy, impostare uno di questi valori come requisito minimo.
Qualsiasi versione recente di clang
, comprese le versioni di Apple, non dovrebbe quindi avere problemi x86intrin.h
. Naturalmente, insieme a gcc-5
, puoi sempre usare quanto segue:
#if defined (__has_include) && (__has_include(<x86intrin.h>))
#include <x86intrin.h>
#else
#error "upgrade your compiler. it's free..."
#endif
Un trucco su cui non puoi davvero fare affidamento è usare le __GNUC__
versioni in clang
. Il versioning è, per ragioni storiche, bloccato 4.2.1
. Una versione che precede l' x86intrin.h
intestazione. Occasionalmente è utile, diciamo, per semplici estensioni GNU C che sono rimaste compatibili con le versioni precedenti.
icc : per quanto ne so, l' x86intrin.h
intestazione è supportata almeno da Intel C ++ 16.0. Il test versione può da eseguita con: #if (__INTEL_COMPILER >= 1600)
. Questa versione (e possibilmente versioni precedenti) fornisce anche supporto per l' __has_include
estensione.
MSVC : Sembra che MSVC++ 12.0 (Visual Studio 2013)
sia la prima versione a fornire l' intrin.h
intestazione, non x86intrin.h
... questo suggerisce: #if (_MSC_VER >= 1800)
come test di versione. Naturalmente, se stai cercando di scrivere un codice portatile su tutti questi diversi compilatori, il nome dell'intestazione su questa piattaforma sarà l'ultimo dei tuoi problemi.
#include <x86intrin.h>
che ti attira in tutto ciò che ti serve.