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ę.
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ę.
Odpowiedzi:
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=native
lub -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
lub 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.h
nie przyciąga tego)
Niektóre kompilatory mają również <zmmintrin.h>
AVX512.
<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..)
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=haswell
lub tylko -march=native
. Dodatkowo niektóre instrukcje specyficzne dla x86, takie jak bswap
lub ror
stają 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 /
<x86intrin.h>
, ale <intrin.h>
osiąga podobny efekt. Oczywiście nadal potrzebujesz kompilacji warunkowej. :-(
#include <immintrin.h>
. Użyj tego do wewnętrznych elementów SIMD. Potrzebujesz tylko jeszcze większego (i nieco wolniejszego w kompilatorze) x86intrin.h
lub intrin.h
jeś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 ).
x86intrin.h
/ intrin.h
ale nie w immintrin.h
.
Nazwa nagłówka zależy od kompilatora i architektury docelowej.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
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
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.h
aby uzyskać wszystkie rozszerzenia Intel lub x86intrin.h
jeśli chcesz wszystko, w tym _bit_scan_forward
i_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.h
to 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_ps
Bez włączenia fma, nawet jeśli włączysz immintrin.h
i włączysz AVX2).
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 .
immintrin.h
nie wydaje się zawierać _popcnt32
i _popcnt64
(nie mylić z tymi w popcntintrin.h
!) funkcji wewnętrznych w GCC 9.1.0. Więc wydaje się, że x86intrin.h
nadal służy celowi.
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
, clang
i icc
wszyscy 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.h
pierwszego pojawia się w gcc-4.5.0
. Seria gcc-4
wydań nie jest już aktualizowana, podczas gdy gcc-6.x
jest to aktualna seria stabilnych wydań. gcc-5
wprowadził również __has_include
rozszerzenie obecne we wszystkich clang-3.x
wersjach. gcc-7
jest w wersji wstępnej (testy regresyjne itp.) i zgodnie z obecnym schematem wersji zostanie wydana jako gcc-7.1.0
.
clang : x86intrin.h
wydaje się być obsługiwany we wszystkich clang-3.x
wersjach. 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.x
serią.
Apple clang : irytujące, wersje Apple nie odpowiadają wersjom LLVM
projektów. To powiedziawszy, obecne wydanie: clang-800.0.42.1
jest oparte naLLVM 3.9.0
. LLVM 3.0
Wygląda na to, że pierwsza wersja bazowa Apple clang 2.1
powróciła Xcode 4.1
. LLVM 3.1
po 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-5
zawsze 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.h
nagłówek. Czasami jest przydatny, powiedzmy, w przypadku prostych rozszerzeń GNU C, które pozostały wstecznie kompatybilne.
icc : o ile wiem, x86intrin.h
nagłó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_include
rozszerzenia.
MSVC : Wygląda na MSVC++ 12.0 (Visual Studio 2013)
to, że jest to pierwsza wersja, która zawiera intrin.h
nagłó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.
#include <x86intrin.h>
wciągnąć wszystko, czego potrzebujesz.