Welche Header-Dateien liefern die Grundlagen für die verschiedenen x86-SIMD-Befehlssatzerweiterungen (MMX, SSE, AVX, ...)? Es scheint unmöglich, eine solche Liste online zu finden. Korrigiere mich, wenn ich falsch liege.
Welche Header-Dateien liefern die Grundlagen für die verschiedenen x86-SIMD-Befehlssatzerweiterungen (MMX, SSE, AVX, ...)? Es scheint unmöglich, eine solche Liste online zu finden. Korrigiere mich, wenn ich falsch liege.
Antworten:
Heutzutage sollten Sie normalerweise nur einschließen <immintrin.h>
. Es beinhaltet alles.
GCC und clang hindern Sie daran, Intrinsics für Anweisungen zu verwenden, die Sie zum Zeitpunkt der Kompilierung nicht aktiviert haben (z. B. mit -march=native
oder -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
oder was auch immer).
Mit MSVC und ICC können Sie Intrinsics verwenden, ohne zur Kompilierungszeit etwas zu aktivieren. Sie sollten jedoch AVX aktivieren, bevor Sie AVX Intrinsics verwenden.
In der Vergangenheit (bevor immintrin.h
alles eingezogen wurde) mussten Sie manuell einen Header für die höchste gewünschte Eigenschaftsstufe einfügen.
Dies kann bei MSVC und ICC weiterhin nützlich sein, um zu verhindern, dass Sie Befehlssätze verwenden, die Sie nicht benötigen.
<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
Einschließlich eines dieser Pulls in allen vorherigen (außer AMD-only SSE4A: immintrin.h
zieht das nicht rein )
Einige Compiler haben auch <zmmintrin.h>
für AVX512.
<zmmintrin.h>
direkt einschließen ; gcc bietet es nicht einmal an. Einfach verwenden<immintrin.h>
oder noch vollständiger <x86intrin.h>
. Diese Antwort ist grundsätzlich veraltet, es sei denn, Sie vermeiden absichtlich das Einfügen von Intrinsics für neuere Versionen von SSE, da sich Ihr Compiler nicht beschwert, wenn Sie beim Kompilieren für SSE2 eine SSE4.1-Anweisung verwenden. (gcc / Klirren Sie beklagen, so dass Sie nur für sie verwenden immintrin.h sollte IDK über andere..)
Auf GCC / Clang, wenn Sie nur verwenden
#include <x86intrin.h>
Es enthält alle SSE / AVX-Header, die gemäß Compiler-Switches wie -march=haswell
oder nur aktiviert werden -march=native
. Zusätzlich mögen bswap
oder ror
werden einige x86-spezifische Anweisungen als Intrinsics verfügbar.
Das MSVC-Äquivalent dieses Headers <intrin.h>
Wenn Sie nur eine tragbare SIMD möchten, verwenden Sie #include <immintrin.h>
MSVC, ICC und gcc / clang (und andere Compiler wie Sun, glaube ich) unterstützen diesen Header für die SIMD-Intrinsics, die von Intels einzigem Intrinsics-Finder / Suchwerkzeug dokumentiert wurden: https://software.intel.com/sites/landingpage/IntrinsicsGuide /.
<x86intrin.h>
, <intrin.h>
erzielt aber einen ähnlichen Effekt. Sie benötigen natürlich noch eine bedingte Kompilierung. :-(
#include <immintrin.h>
. Verwenden Sie dies für SIMD-Intrinsics. Sie benötigen nur den noch größeren (und etwas langsamer für den Compiler) x86intrin.h
oder intrin.h
wenn Sie Dinge wie Integer-Rotation / Bit-Scan-Intrinsics benötigen (obwohl Intel einige davon als immintrin.h
in ihrem Intrinsics-Handbuch verfügbar dokumentiert ).
x86intrin.h
/ intrin.h
aber nicht in haben immintrin.h
.
Der Headername hängt von Ihrem Compiler und Ihrer Zielarchitektur ab.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
spe.h
Sie können alle diese Fälle mit Anweisungen zur bedingten Vorverarbeitung behandeln:
#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
Von dieser Seite
+----------------+------------------------------------------------------------------------------------------+
| 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 |
+----------------+------------------------------------------------------------------------------------------+
Im Allgemeinen können Sie also einfach immintrin.h
alle Intel-Erweiterungen x86intrin.h
einschließen , oder wenn Sie alles möchten, einschließlich _bit_scan_forward
und _rdtsc
, sowie alle Vektor-Intrinsics enthalten nur AMD- Erweiterungen . Wenn Sie dagegen sind, mehr einzuschließen, als Sie tatsächlich benötigen, können Sie das richtige Einschließen auswählen, indem Sie sich die Tabelle ansehen.
x86intrin.h
ist der empfohlene Weg, um Intrinsics für AMD XOP zu erhalten (nur Bulldozer, nicht einmal zukünftige AMD-CPUs) , anstatt einen eigenen Header zu haben.
Einige Compiler generieren weiterhin Fehlermeldungen, wenn Sie Intrinsics für Befehlssätze verwenden, die Sie nicht aktiviert haben (z. B. _mm_fmadd_ps
ohne fma zu aktivieren, selbst wenn Sie immintrin.h
AVX2 einschließen und aktivieren).
smmintrin
(SSE4.1) ist Penryn (45 nm Core2), nicht Nehalem ("i7"). Können wir aufhören, "i7" als Architekturnamen zu verwenden? Es ist jetzt bedeutungslos, dass Intel es weiterhin für die SnB-Familie verwendet .
immintrin.h
scheint keine Intrinsics in GCC 9.1.0 zu enthalten _popcnt32
und _popcnt64
(nicht zu verwechseln mit denen in popcntintrin.h
!). Es scheint also x86intrin.h
immer noch einen Zweck zu erfüllen.
Wie in vielen Antworten und Kommentaren angegeben, <x86intrin.h>
handelt es sich um den umfassenden Header für x86 [-64] SIMD-Intrinsics. Es enthält auch intrinsische unterstützende Anweisungen für andere ISA-Erweiterungen. gcc
,, clang
und icc
haben sich alle darauf geeinigt. Ich musste ein wenig nach Versionen suchen, die den Header unterstützen, und dachte, es könnte nützlich sein, einige Ergebnisse aufzulisten ...
gcc : Unterstützung für x86intrin.h
first erscheint in gcc-4.5.0
. Die gcc-4
Release-Serie wird nicht mehr beibehalten, während gcc-6.x
es sich um die aktuelle stabile Release-Serie handelt. gcc-5
Außerdem wurde die __has_include
in allen clang-3.x
Releases vorhandene Erweiterung eingeführt . gcc-7
befindet sich in der Vorabversion (Regressionstests usw.) und wird nach dem aktuellen Versionsschema als veröffentlicht gcc-7.1.0
.
clang : x86intrin.h
scheint für alle clang-3.x
Releases unterstützt worden zu sein . Die neueste stabile Version ist clang (LLVM) 3.9.1
. Der Entwicklungszweig ist clang (LLVM) 5.0.0
. Es ist nicht klar, was mit der 4.x
Serie passiert ist .
Apple klirrt : Ärgerlicherweise entspricht die Versionierung von Apple nicht der der LLVM
Projekte. Das heißt, die aktuelle Version: clang-800.0.42.1
basiert auf LLVM 3.9.0
. Die erste LLVM 3.0
basierte Version scheint Apple clang 2.1
wieder in zu sein Xcode 4.1
. LLVM 3.1
erscheint zuerst mit Apple clang 3.1
(einem numerischen Zufall) in Xcode 4.3.3
.
Apple definiert auch __apple_build_version__
zB 8000042
. Dies scheint das stabilste, streng aufsteigende verfügbare Versionsschema zu sein. Wenn Sie ältere Compiler nicht unterstützen möchten, müssen Sie einen dieser Werte als Mindestanforderung festlegen.
Jede neuere Version von clang
, einschließlich Apple-Versionen, sollte daher kein Problem haben x86intrin.h
. Natürlich können Sie zusammen mit gcc-5
immer Folgendes verwenden:
#if defined (__has_include) && (__has_include(<x86intrin.h>))
#include <x86intrin.h>
#else
#error "upgrade your compiler. it's free..."
#endif
Ein Trick, auf den Sie sich nicht wirklich verlassen können, ist die Verwendung der __GNUC__
Versionen in clang
. Die Versionierung bleibt aus historischen Gründen hängen 4.2.1
. Eine Version vor dem x86intrin.h
Header. Dies ist gelegentlich nützlich, beispielsweise für einfache GNU C-Erweiterungen, die abwärtskompatibel geblieben sind.
icc : Soweit ich das beurteilen kann, wird der x86intrin.h
Header seit mindestens Intel C ++ 16.0 unterstützt. Der Versionstest kann durchgeführt werden mit : #if (__INTEL_COMPILER >= 1600)
. Diese Version (und möglicherweise frühere Versionen) bietet auch Unterstützung für die __has_include
Erweiterung.
MSVC : Es scheint, dass dies MSVC++ 12.0 (Visual Studio 2013)
die erste Version ist, die den intrin.h
Header bereitstellt - nicht x86intrin.h
... dies legt nahe: #if (_MSC_VER >= 1800)
als Versionstest. Wenn Sie versuchen, Code zu schreiben, der auf all diese verschiedenen Compiler portierbar ist, ist der Headername auf dieser Plattform natürlich das geringste Ihrer Probleme.
#include <x86intrin.h>
alles in sich aufnehmen, was Sie brauchen.