Pliki nagłówkowe dla elementów wewnętrznych x86 SIMD

132

Które pliki nagłówkowe zawierają elementy wewnętrzne dla różnych rozszerzeń zestawu instrukcji x86 SIMD (MMX, SSE, AVX, ...)? Znalezienie takiej listy w Internecie wydaje się niemożliwe. Popraw mnie, jeśli się mylę.

fredoverflow
źródło

Odpowiedzi:

176

W dzisiejszych czasach zwykle należy po prostu uwzględnić <immintrin.h>. Zawiera wszystko.

GCC i brzęk zatrzyma cię z użyciem intrinsics instrukcje nie zostały włączone w czasie kompilacji (np -march=nativelub -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1lub cokolwiek).

MSVC i ICC pozwolą Ci korzystać z funkcji wewnętrznych bez włączania czegokolwiek w czasie kompilacji, ale nadal powinieneś włączyć AVX przed użyciem funkcji wewnętrznych AVX.


Historycznie (przed immintrin.hściągnięciem wszystkiego) trzeba było ręcznie dołączyć nagłówek dla najwyższego poziomu elementów wewnętrznych, jakie chciałeś.

Może to być nadal przydatne w przypadku MSVC i ICC, aby powstrzymać się od używania zestawów instrukcji, których nie chcesz wymagać.

<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

Włączanie jednego z tych ciągów do wszystkich poprzednich (z wyjątkiem SSE4A tylko dla AMD: immintrin.hnie przyciąga tego)

Niektóre kompilatory mają również <zmmintrin.h>AVX512.

fredoverflow
źródło
64
Lub możesz po prostu #include <x86intrin.h>wciągnąć wszystko, czego potrzebujesz.
Paul R
2
zmmintrin.h ma cechy wewnętrzne AVX-512.
onitake
4
Dlaczego p, t, si n dla SSE3 / SSSE3 / SSE4.1 i 4.2? Co reprezentują te postacie?
phuclv
6
@ LưuVĩnhPhúc SSE3 = Prescott nowe instrukcje, SSSE3 = Tejas nowe instrukcje. Myślę, że SSE4.2 i AES odnoszą się do rodziny procesorów, w której zostały wprowadzone (Nehalem i Westmere)
Drew McGowen
15
Nie dołączaj <zmmintrin.h>bezpośrednio; gcc nawet tego nie dostarcza. Po prostu użyj<immintrin.h> lub jeszcze bardziej kompletne <x86intrin.h>. Ta odpowiedź jest w zasadzie przestarzała, chyba że celowo unikasz włączania elementów wewnętrznych dla nowszych wersji SSE, ponieważ Twój kompilator nie narzeka, gdy używasz instrukcji SSE4.1 podczas kompilacji dla SSE2. (gcc / dzyń nie narzekają, więc należy po prostu użyć immintrin.h dla nich IDK o innych..)
Peter Cordes
76

W GCC / clang, jeśli używasz tylko

#include <x86intrin.h>

będzie zawierał wszystkie nagłówki SSE / AVX, które są włączone zgodnie z przełącznikami kompilatora, takimi jak -march=haswelllub tylko -march=native. Dodatkowo niektóre instrukcje specyficzne dla x86, takie jak bswaplub rorstają się dostępne jako wewnętrzne.


Odpowiednik MSVC tego nagłówka <intrin.h>


Jeśli chcesz tylko przenośnej karty SIMD, użyj #include <immintrin.h>

MSVC, ICC i gcc / clang (i inne kompilatory, jak myślę, Sun, jak sądzę) obsługują ten nagłówek dla funkcji SIMD udokumentowanych przez jedyne wewnętrzne narzędzie do wyszukiwania / wyszukiwania firmy Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide /

Gunther Piez
źródło
Nie byłem pewien, czy nowsze wersje mogą ... W każdym razie tak długo, jak mają gcc, icc i clang, myślę, że można go używać :-)
Gunther Piez
5
MSVC nie ma <x86intrin.h>, ale <intrin.h>osiąga podobny efekt. Oczywiście nadal potrzebujesz kompilacji warunkowej. :-(
Cody Grey
Wszystkie główne kompilatory x86 mają #include <immintrin.h>. Użyj tego do wewnętrznych elementów SIMD. Potrzebujesz tylko jeszcze większego (i nieco wolniejszego w kompilatorze) x86intrin.hlub intrin.hjeśli potrzebujesz takich elementów, jak wewnętrzne funkcje rotacji liczb całkowitych / skanowania bitowego (chociaż Intel dokumentuje niektóre z nich jako dostępne immintrin.h w ich przewodniku wewnętrznym ).
Peter Cordes
IIRC, istnieją pewne elementy nie-SIMD, które Intel dokumentuje jako znajdujące się w immintrin.h, ale które gcc, clang i / lub MSVC mają tylko w x86intrin.h/ intrin.hale nie w immintrin.h.
Peter Cordes
56

Nazwa nagłówka zależy od kompilatora i architektury docelowej.

  • Dla Microsoft C ++ (ukierunkowany na x86, x86-64 lub ARM) i kompilator Intel C / C ++ do użytku w systemie Windows intrin.h
  • W przypadku gcc / clang / icc używaj x86 / x86-64 x86intrin.h
  • Do gcc / clang / armcc celującego ARM z użyciem NEON arm_neon.h
  • Do gcc / clang / armcc celującego ARM z użyciem WMMX mmintrin.h
  • Do gcc / clang / xlcc kierowanych na PowerPC z VMX (aka Altivec) i / lub VSX altivec.h
  • Do gcc / clang kierowania PowerPC z użyciem SPE spe.h

Możesz obsłużyć wszystkie te przypadki za pomocą dyrektyw warunkowego przetwarzania wstępnego:

#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
źródło
Oto kilka rzeczy do dodania do swojej listy: Na UltraSPARC + VIS z gcc użyj visintrin.h; jeśli masz VSDK firmy Sun, vis.h oferuje inny zestaw funkcji wewnętrznych. Dokumentację można znaleźć tutaj: wbudowane GCC VIS , podręcznik użytkownika Sun VIS .
onitake
45

Z tej strony

+----------------+------------------------------------------------------------------------------------------+
|     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             |
+----------------+------------------------------------------------------------------------------------------+

Więc ogólnie możesz po prostu dołączyć, immintrin.haby uzyskać wszystkie rozszerzenia Intel lub x86intrin.hjeśli chcesz wszystko, w tym _bit_scan_forwardi_rdtsc , a także wszystkie wewnętrzne elementy wektorowe obejmują tylko te AMD. Jeśli sprzeciwiasz się dodawaniu więcej, których faktycznie potrzebujesz, możesz wybrać odpowiednie uwzględnienie, patrząc na tabelę.

x86intrin.hto zalecany sposób na zdobycie elementów wewnętrznych dla AMD XOP (tylko Bulldozer, nawet przyszłych procesorów AMD) , zamiast posiadania własnego nagłówka.

Niektóre kompilatory nadal będą generować komunikaty o błędach, jeśli użyjesz funkcji wewnętrznych dla zestawów instrukcji, których nie włączyłeś (np. _mm_fmadd_psBez włączenia fma, nawet jeśli włączysz immintrin.hi włączysz AVX2).

RubenLaguna
źródło
1
smmintrin(SSE4.1) to Penryn (45 nm Core2), a nie Nehalem („i7”). Czy możemy przestać używać „i7” jako nazwy architektury? Nie ma to znaczenia teraz, gdy Intel nadal używa go w rodzinie SnB .
Peter Cordes,
immintrin.hnie wydaje się zawierać _popcnt32i _popcnt64(nie mylić z tymi w popcntintrin.h!) funkcji wewnętrznych w GCC 9.1.0. Więc wydaje się, że x86intrin.hnadal służy celowi.
Thom Wiggers
13

20200914: najnowsze najlepsze praktyki: <immintrin.h>(obsługiwane również przez MSVC )

Resztę odpowiedzi pozostawię dla celów historycznych; może być przydatny w przypadku starszych kombinacji kompilator / platforma ...


Jak stwierdzono w wielu odpowiedziach i komentarzach, <x86intrin.h>znajduje się obszerny nagłówek dotyczący funkcji wewnętrznych x86 [-64] SIMD. Zawiera również wewnętrzne instrukcje wspierające inne rozszerzenia ISA. gcc, clangi iccwszyscy się na tym zdecydowali. Musiałem trochę poszperać w wersjach obsługujących nagłówek i pomyślałem, że warto byłoby wymienić niektóre ustalenia ...

  • gcc : obsługa x86intrin.hpierwszego pojawia się w gcc-4.5.0. Seria gcc-4wydań nie jest już aktualizowana, podczas gdy gcc-6.xjest to aktualna seria stabilnych wydań. gcc-5wprowadził również __has_includerozszerzenie obecne we wszystkich clang-3.xwersjach. gcc-7jest w wersji wstępnej (testy regresyjne itp.) i zgodnie z obecnym schematem wersji zostanie wydana jako gcc-7.1.0.

  • clang : x86intrin.hwydaje się być obsługiwany we wszystkich clang-3.xwersjach. Najnowsza stabilna wersja to clang (LLVM) 3.9.1. Gałąź rozwoju to clang (LLVM) 5.0.0. Nie jest jasne, co stało się z 4.xserią.

  • Apple clang : irytujące, wersje Apple nie odpowiadają wersjom LLVMprojektów. To powiedziawszy, obecne wydanie: clang-800.0.42.1jest oparte naLLVM 3.9.0 . LLVM 3.0Wygląda na to, że pierwsza wersja bazowa Apple clang 2.1powróciła Xcode 4.1. LLVM 3.1po raz pierwszy pojawia się z Apple clang 3.1(liczbowym zbiegiem okoliczności) w Xcode 4.3.3.

    Apple definiuje również __apple_build_version__np 8000042. Wydaje się, że jest to najbardziej stabilny, ściśle rosnący schemat wersjonowania. Jeśli nie chcesz obsługiwać starszych kompilatorów, ustaw jedną z tych wartości jako minimalne wymaganie.

Każda najnowsza wersja clang, w tym wersje Apple, nie powinna zatem mieć problemu z x86intrin.h. Oczywiście wraz z gcc-5zawsze możesz użyć:

#if defined (__has_include) && (__has_include(<x86intrin.h>))
#include <x86intrin.h>
#else
#error "upgrade your compiler. it's free..."
#endif

Jedną sztuczką, na której nie możesz naprawdę polegać, jest używanie __GNUC__wersji w clang. Wersjonowanie utknęło ze względów historycznych 4.2.1. Wersja poprzedzająca x86intrin.hnagłówek. Czasami jest przydatny, powiedzmy, w przypadku prostych rozszerzeń GNU C, które pozostały wstecznie kompatybilne.

  • icc : o ile wiem, x86intrin.hnagłówek jest obsługiwany od co najmniej Intel C ++ 16.0. Test wersji może być wykonywane z: #if (__INTEL_COMPILER >= 1600). Ta wersja (i prawdopodobnie wcześniejsze wersje) zapewnia również obsługę __has_includerozszerzenia.

  • MSVC : Wygląda na MSVC++ 12.0 (Visual Studio 2013)to, że jest to pierwsza wersja, która zawiera intrin.hnagłówek - nie x86intrin.h ... to sugeruje: #if (_MSC_VER >= 1800)jako test wersji. Oczywiście, jeśli próbujesz napisać kod, który jest przenośny we wszystkich tych różnych kompilatorach, nazwa nagłówka na tej platformie będzie najmniejszym z twoich problemów.

Brett Hale
źródło