Header-Dateien für x86 SIMD Intrinsics

131

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.

Fredoverflow
quelle

Antworten:

174

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=nativeoder -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1oder 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.halles 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.hzieht das nicht rein )

Einige Compiler haben auch <zmmintrin.h>für AVX512.

Fredoverflow
quelle
62
Oder Sie können einfach #include <x86intrin.h>alles in sich aufnehmen, was Sie brauchen.
Paul R
2
zmmintrin.h verfügt über die Eigenschaften des AVX-512.
Onitake
3
Warum sind p, t, s und n für SSE3 / SSSE3 / SSE4.1 und 4.2? Was repräsentieren diese Charaktere?
Phuclv
5
@ LưuVĩnhPhúc SSE3 = Prescott neue Anweisungen, SSSE3 = Tejas neue Anweisungen. Ich denke, SSE4.2 und AES beziehen sich auf die Prozessorfamilie, auf der sie eingeführt wurden (Nehalem und Westmere)
Drew McGowen
14
Nicht <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..)
Peter Cordes
76

Auf GCC / Clang, wenn Sie nur verwenden

#include <x86intrin.h>

Es enthält alle SSE / AVX-Header, die gemäß Compiler-Switches wie -march=haswelloder nur aktiviert werden -march=native. Zusätzlich mögen bswapoder rorwerden 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 /.

Gunther Piez
quelle
Ich war mir nicht sicher, ob die neueren Versionen ... Wie auch immer, solange gcc, icc und clang es haben, ist es
Gunther Piez
5
MSVC hat keine <x86intrin.h>, <intrin.h>erzielt aber einen ähnlichen Effekt. Sie benötigen natürlich noch eine bedingte Kompilierung. :-(
Cody Gray
Alle wichtigen x86-Compiler haben #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.hoder intrin.hwenn Sie Dinge wie Integer-Rotation / Bit-Scan-Intrinsics benötigen (obwohl Intel einige davon als immintrin.h in ihrem Intrinsics-Handbuch verfügbar dokumentiert ).
Peter Cordes
IIRC, es gibt einige Nicht-SIMD-Eigenschaften, die Intel als in immintrin.h dokumentiert, die aber gcc, clang und / oder MSVC nur in x86intrin.h/ intrin.haber nicht in haben immintrin.h.
Peter Cordes
56

Der Headername hängt von Ihrem Compiler und Ihrer Zielarchitektur ab.

  • Für Microsoft C ++ (für x86, x86-64 oder ARM) und Intel C / C ++ Compiler für Windows intrin.h
  • Für gcc / clang / icc-Targeting verwenden Sie x86 / x86-64 x86intrin.h
  • Für gcc / clang / armcc Targeting ARM mit NEON verwenden arm_neon.h
  • Für gcc / clang / armcc Targeting ARM mit WMMX verwenden mmintrin.h
  • Für gcc / clang / xlcc-Targeting von PowerPC mit VMX (auch bekannt als Altivec) und / oder VSX verwenden altivec.h
  • Für gcc / clang Targeting PowerPC mit SPE verwenden 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
Marat Dukhan
quelle
Folgendes können Sie Ihrer Liste hinzufügen: Verwenden Sie unter UltraSPARC + VIS mit gcc visintrin.h; Wenn Sie über das VSDK von Sun verfügen, bietet vis.h eine andere Reihe von Eigenschaften. Die Dokumentation finden Sie hier: GCC VIS-integrierte Funktionen , Sun VIS-Benutzerhandbuch .
Onitake
44

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.halle Intel-Erweiterungen x86intrin.heinschließen , oder wenn Sie alles möchten, einschließlich _bit_scan_forwardund _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.hist 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_psohne fma zu aktivieren, selbst wenn Sie immintrin.hAVX2 einschließen und aktivieren).

RubenLaguna
quelle
1
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 .
Peter Cordes
immintrin.hscheint keine Intrinsics in GCC 9.1.0 zu enthalten _popcnt32und _popcnt64(nicht zu verwechseln mit denen in popcntintrin.h!). Es scheint also x86intrin.himmer noch einen Zweck zu erfüllen.
Thom Wiggers
12

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,, clangund icchaben 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.hfirst erscheint in gcc-4.5.0. Die gcc-4Release-Serie wird nicht mehr beibehalten, während gcc-6.xes sich um die aktuelle stabile Release-Serie handelt. gcc-5Außerdem wurde die __has_includein allen clang-3.xReleases vorhandene Erweiterung eingeführt . gcc-7befindet sich in der Vorabversion (Regressionstests usw.) und wird nach dem aktuellen Versionsschema als veröffentlicht gcc-7.1.0.

  • clang : x86intrin.hscheint für alle clang-3.xReleases 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.xSerie passiert ist .

  • Apple klirrt : Ärgerlicherweise entspricht die Versionierung von Apple nicht der der LLVMProjekte. Das heißt, die aktuelle Version: clang-800.0.42.1basiert auf LLVM 3.9.0. Die erste LLVM 3.0basierte Version scheint Apple clang 2.1wieder in zu sein Xcode 4.1. LLVM 3.1erscheint 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-5immer 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.hHeader. 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.hHeader 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_includeErweiterung.

  • MSVC : Es scheint, dass dies MSVC++ 12.0 (Visual Studio 2013)die erste Version ist, die den intrin.hHeader 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.

Brett Hale
quelle