File header untuk intrinsik SIMD x86

131

File header mana yang menyediakan intrinsik untuk ekstensi set instruksi x86 SIMD yang berbeda (MMX, SSE, AVX, ...)? Tampaknya tidak mungkin menemukan daftar online seperti itu. Koreksi saya jika saya salah.

fredoverflow
sumber

Jawaban:

174

Hari-hari ini Anda biasanya hanya perlu memasukkan <immintrin.h>. Itu termasuk semuanya.

GCC dan dentang akan menghentikan Anda dari menggunakan intrinsik untuk instruksi yang belum Anda aktifkan pada waktu kompilasi (misalnya dengan -march=nativeatau -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1atau apa pun.)

MSVC dan ICC akan memungkinkan Anda menggunakan intrinsik tanpa mengaktifkan apa pun pada waktu kompilasi, tetapi Anda tetap harus mengaktifkan AVX sebelum menggunakan AVX intrinsics.


Secara historis (sebelum immintrin.hmenarik semuanya) Anda harus memasukkan header secara manual untuk level intrinsik tertinggi yang Anda inginkan.

Ini mungkin masih berguna dengan MSVC dan ICC untuk menghentikan diri Anda dari menggunakan set instruksi yang tidak Anda inginkan.

<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

Termasuk salah satu dari tarikan ini di semua yang sebelumnya (kecuali SSE4A khusus AMD: immintrin.htidak menarik itu)

Beberapa kompiler juga ada <zmmintrin.h>untuk AVX512.

fredoverflow
sumber
62
Atau Anda bisa saja #include <x86intrin.h>yang menarik semua yang Anda butuhkan.
Paul R
2
zmmintrin.h memiliki intrinsik AVX-512.
onitake
3
Mengapa p, t, s dan n untuk SSE3 / SSSE3 / SSE4.1 dan 4.2? Apa yang mewakili karakter-karakter itu?
phuclv
5
@ LưuVĩnhPhúc SSE3 = Prescott instruksi baru, SSSE3 = Tejas instruksi baru. Saya pikir SSE4.2 dan AES merujuk pada keluarga prosesor yang mereka perkenalkan (Nehalem dan Westmere)
Drew McGowen
14
Jangan sertakan <zmmintrin.h>secara langsung; gcc bahkan tidak menyediakannya. Cukup gunakan<immintrin.h> atau bahkan lebih lengkap <x86intrin.h>. Jawaban ini pada dasarnya sudah usang, kecuali jika Anda secara sengaja menghindari memasukkan intrinsik untuk versi SSE yang lebih baru karena kompiler Anda tidak mengeluh ketika Anda menggunakan instruksi SSE4.1 saat menyusun untuk SSE2. (Gcc / dentang memang mengeluh, jadi Anda harus menggunakan immintrin.h untuk mereka. IDK tentang orang lain.)
Peter Cordes
76

Pada GCC / dentang, jika Anda gunakan saja

#include <x86intrin.h>

itu akan mencakup semua header SSE / AVX yang diaktifkan sesuai dengan sakelar kompiler suka -march=haswellatau adil -march=native. Selain itu beberapa instruksi spesifik x86 suka bswapatau rortersedia sebagai intrinsik.


Setara MSVC dari header ini <intrin.h>


Jika Anda hanya ingin SIMD portabel, gunakan #include <immintrin.h>

MSVC, ICC, dan gcc / dentang (dan kompiler lain seperti Sun, saya pikir) semuanya mendukung tajuk ini untuk intrinsik SIMD yang didokumentasikan oleh satu-satunya alat pencari / penelusuran intrinsik Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide /

Piez Gunther
sumber
Saya tidak yakin, jika versi yang lebih baru mungkin ... Pokoknya selama gcc, icc dan dentang memilikinya, ok untuk digunakan saya pikir :-)
Gunther Piez
5
MSVC tidak memiliki <x86intrin.h>, tetapi <intrin.h>mencapai efek yang serupa. Anda masih membutuhkan kompilasi bersyarat, tentu saja. :-(
Cody Grey
Semua kompiler x86 utama miliki #include <immintrin.h>. Gunakan itu untuk SIMD intrinsik. Anda hanya memerlukan kompiler yang bahkan lebih besar (dan sedikit lebih lambat) x86intrin.hatau intrin.hjika Anda memerlukan hal-hal seperti integer rotate / bit-scan intrinsik (walaupun Intel mendokumentasikan beberapa dari mereka yang tersedia di immintrin.h dalam panduan intrinsik mereka ).
Peter Cordes
IIRC, ada beberapa intrinsik non-SIMD yang didokumentasikan Intel sebagai immintrin.h, tetapi yang gcc, clang, dan / atau MSVC hanya memiliki di x86intrin.h/ intrin.htetapi tidak di immintrin.h.
Peter Cordes
56

Nama header tergantung pada kompiler dan arsitektur target Anda.

  • Untuk Microsoft C ++ (penargetan x86, x86-64 atau ARM) dan Intel C / C ++ Compiler untuk penggunaan Windows intrin.h
  • Untuk penargetan gcc / clang / icc x86 / x86-64 x86intrin.h
  • Untuk penargetan ARM gcc / clang / armcc dengan penggunaan NEON arm_neon.h
  • Untuk penargetan ARM gcc / dentang / armcc dengan penggunaan WMMX mmintrin.h
  • Untuk penargetan PowerPC gcc / clang / xlcc dengan VMX (alias Altivec) dan / atau penggunaan VSX altivec.h
  • Untuk gcc / dentang penargetan PowerPC dengan penggunaan SPE spe.h

Anda dapat menangani semua kasus ini dengan arahan preprocessing bersyarat:

#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
sumber
Berikut ini beberapa tambahan untuk ditambahkan ke daftar Anda: Pada UltraSPARC + VIS dengan gcc, gunakan visintrin.h; jika Anda memiliki VSDK milik Sun, vis.h menawarkan serangkaian intrinsik yang berbeda. Dokumentasi dapat ditemukan di sini: GCC VIS builtins , panduan pengguna Sun VIS .
onitake
44

Dari halaman ini

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

Jadi secara umum Anda bisa memasukkan immintrin.huntuk mendapatkan semua ekstensi Intel, atau x86intrin.hjika Anda menginginkan semuanya, termasuk _bit_scan_forwarddan _rdtsc, serta semua vektor intrinsik termasuk yang hanya AMD. Jika Anda menentang memasukkan lebih banyak yang sebenarnya Anda butuhkan, maka Anda dapat memilih yang benar termasuk dengan melihat tabel.

x86intrin.hadalah cara yang disarankan untuk mendapatkan intrinsik untuk AMD XOP (hanya Bulldozer, bahkan untuk CPU AMD yang akan datang) , daripada memiliki header sendiri.

Beberapa kompiler masih akan menghasilkan pesan kesalahan jika Anda menggunakan intrinsik untuk set instruksi yang belum Anda aktifkan (mis. _mm_fmadd_psTanpa mengaktifkan fma, bahkan jika Anda memasukkan immintrin.hdan mengaktifkan AVX2).

RubenLaguna
sumber
1
smmintrin(SSE4.1) adalah Penryn (45nm Core2), bukan Nehalem ("i7"). Bisakah kita berhenti menggunakan "i7" sebagai nama arsitektur? Tidak ada artinya sekarang karena Intel terus menggunakannya untuk keluarga SnB .
Peter Cordes
immintrin.htampaknya tidak termasuk _popcnt32dan _popcnt64(jangan disamakan dengan yang ada di popcntintrin.hdalamnya!) intrinsik pada GCC 9.1.0. Jadi tampaknya x86intrin.hmasih memiliki tujuan.
Thom Wiggers
12

Seperti banyak dari jawaban dan komentar telah menyatakan, <x86intrin.h>adalah yang sundulan komprehensif untuk x86 [-64] SIMD intrinsik. Ini juga menyediakan instruksi pendukung intrinsik untuk ekstensi ISA lainnya. gcc,, clangdan iccsemuanya sudah sepakat. Saya perlu melakukan penggalian pada versi yang mendukung tajuk, dan saya pikir mungkin berguna untuk membuat daftar beberapa temuan ...

  • gcc : dukungan untuk x86intrin.hpertama kali muncul di gcc-4.5.0. The gcc-4seri rilis tidak lagi dipertahankan, sedangkan gcc-6.xadalah saat rilis stabil seri. gcc-5juga memperkenalkan __has_includehadiah ekstensi di semua clang-3.xrilis. gcc-7dalam pra-rilis (pengujian regresi, dll.) dan mengikuti skema versi saat ini, akan dirilis sebagai gcc-7.1.0.

  • dentang : x86intrin.htampaknya telah didukung untuk semua clang-3.xrilis. Rilis stabil terbaru adalah clang (LLVM) 3.9.1. Cabang pengembangan adalah clang (LLVM) 5.0.0. Tidak jelas apa yang terjadi pada 4.xseri ini.

  • Dentang Apple : mengganggu, versi Apple tidak sesuai dengan LLVMproyek. Yang mengatakan, rilis saat ini:, clang-800.0.42.1didasarkan pada LLVM 3.9.0. Versi LLVM 3.0berbasis pertama tampaknya Apple clang 2.1kembali Xcode 4.1. LLVM 3.1pertama kali muncul dengan Apple clang 3.1(kebetulan numerik) di Xcode 4.3.3.

    Apple juga mendefinisikan __apple_build_version__misalnya 8000042,. Tampaknya ini tentang skema versi yang paling stabil dan ketat yang tersedia. Jika Anda tidak ingin mendukung kompiler lawas, jadikan salah satu dari nilai ini persyaratan minimum.

clangOleh karena itu, setiap versi terbaru , termasuk versi Apple, tidak akan memiliki masalah dengan x86intrin.h. Tentu saja, bersama dengan gcc-5, Anda selalu dapat menggunakan yang berikut:

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

Satu trik yang tidak bisa Anda andalkan adalah menggunakan __GNUC__versi di clang. Versi ini, karena alasan historis, terjebak di 4.2.1. Versi yang mendahului x86intrin.hheader. Ini kadang-kadang berguna untuk, katakanlah, ekstensi GNU C sederhana yang tetap kompatibel ke belakang.

  • icc : sejauh yang saya tahu, x86intrin.hheader didukung sejak setidaknya Intel C ++ 16.0. Tes Versi oleh dapat dilakukan dengan: #if (__INTEL_COMPILER >= 1600). Versi ini (dan mungkin versi sebelumnya) juga memberikan dukungan untuk __has_includeekstensi.

  • MSVC : Tampaknya MSVC++ 12.0 (Visual Studio 2013)ini adalah versi pertama yang menyediakan intrin.hheader - bukan x86intrin.h ... ini menyarankan: #if (_MSC_VER >= 1800)sebagai tes versi. Tentu saja, jika Anda mencoba untuk menulis kode yang portabel di semua kompiler berbeda ini, nama header pada platform ini akan menjadi yang paling sedikit masalah Anda.

Brett Hale
sumber