¿Qué archivos de encabezado proporcionan los elementos intrínsecos para las diferentes extensiones del conjunto de instrucciones SIMD x86 (MMX, SSE, AVX, ...)? Parece imposible encontrar esa lista en línea. Corrígeme si me equivoco.
¿Qué archivos de encabezado proporcionan los elementos intrínsecos para las diferentes extensiones del conjunto de instrucciones SIMD x86 (MMX, SSE, AVX, ...)? Parece imposible encontrar esa lista en línea. Corrígeme si me equivoco.
Respuestas:
En estos días, normalmente debería incluir <immintrin.h>
. Incluye todo
GCC y clang le impedirán usar intrínsecos para instrucciones que no ha habilitado en tiempo de compilación (por ejemplo, con -march=native
o-mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
o lo que sea).
MSVC e ICC le permitirán usar intrínsecos sin habilitar nada en el momento de la compilación, pero aún debe habilitar AVX antes de usar intrínsecos AVX.
Históricamente (antes de immintrin.h
extraer todo) tenía que incluir manualmente un encabezado para el nivel más alto de intrínsecos que deseaba.
Esto aún puede ser útil con MSVC e ICC para evitar el uso de conjuntos de instrucciones que no desea requerir.
<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
Incluir uno de estos tirones en todos los anteriores (excepto SSE4A solo para AMD: immintrin.h
no lo hace)
Algunos compiladores también tienen <zmmintrin.h>
para AVX512.
<zmmintrin.h>
directamente; gcc ni siquiera lo proporciona. Solo use<immintrin.h>
o el aún más completo <x86intrin.h>
. Esta respuesta es básicamente obsoleta, a menos que evite intencionalmente incluir intrínsecos para las versiones más nuevas de SSE porque su compilador no se queja cuando usa una instrucción SSE4.1 mientras compila para SSE2. (gcc / ruido metálico no se quejan, por lo que sólo debe utilizar immintrin.h para ellos IDK por los demás..)
En GCC / clang, si usa solo
#include <x86intrin.h>
incluirá todos los encabezados SSE / AVX que están habilitados de acuerdo con los conmutadores del compilador como -march=haswell
o simplemente -march=native
. Además, algunas instrucciones específicas de x86 tienen gusto bswap
o ror
están disponibles como intrínsecas.
El equivalente de MSVC de este encabezado <intrin.h>
Si solo desea SIMD portátil, use #include <immintrin.h>
MSVC, ICC y gcc / clang (y otros compiladores como Sun, creo) son compatibles con este encabezado para los intrínsecos SIMD documentados por el único buscador / herramienta de búsqueda de intrínsecos de Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide / /
<x86intrin.h>
, pero <intrin.h>
logra un efecto similar. Todavía necesita compilación condicional, por supuesto. :-(
#include <immintrin.h>
. Úselo para intrínsecos SIMD. Solo necesita el compilador aún más grande (y un poco más lento para el compilador) x86intrin.h
o intrin.h
si necesita cosas como intrínsecos de rotación de enteros / escaneo de bits (aunque Intel documenta algunos de ellos como disponibles immintrin.h
en su guía de intrínsecos ).
x86intrin.h
/ intrin.h
pero no en immintrin.h
.
El nombre del encabezado depende de su compilador y arquitectura de destino.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
spe.h
Puede manejar todos estos casos con directivas de preprocesamiento condicional:
#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
De esta página
+----------------+------------------------------------------------------------------------------------------+
| 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 |
+----------------+------------------------------------------------------------------------------------------+
Por lo tanto, en general, puede incluir immintrin.h
para obtener todas las extensiones de Intel, o x86intrin.h
si lo desea todo, incluido _bit_scan_forward
y _rdtsc
, así como todos los vectores intrínsecos incluyen solo AMD. Si está en contra de incluir más de lo que realmente necesita, puede elegir la inclusión correcta mirando la tabla.
x86intrin.h
es la forma recomendada de obtener intrínsecos para AMD XOP (solo CPU Bulldozer, ni siquiera futuras CPU AMD) , en lugar de tener su propio encabezado.
Algunos compiladores seguirán generando mensajes de error si usa intrínsecos para conjuntos de instrucciones que no ha habilitado (por ejemplo, _mm_fmadd_ps
sin habilitar fma, incluso si incluye immintrin.h
y habilita AVX2).
smmintrin
(SSE4.1) es Penryn (45nm Core2), no Nehalem ("i7"). ¿Podemos dejar de usar "i7" como nombre de arquitectura? No tiene sentido ahora que Intel ha seguido usándolo para la familia SnB .
immintrin.h
no parece incluir _popcnt32
y _popcnt64
(¡no debe confundirse con los de popcntintrin.h
!) intrínsecos en GCC 9.1.0. Entonces parece que x86intrin.h
todavía tiene un propósito.
Como han indicado muchas de las respuestas y comentarios, <x86intrin.h>
es el encabezado completo para intrínsecos SIMD x86 [-64]. También proporciona instrucciones de soporte intrínsecas para otras extensiones ISA. gcc
, clang
y icc
todos se han decidido por esto. Necesitaba investigar un poco sobre las versiones que admiten el encabezado, y pensé que podría ser útil enumerar algunos hallazgos ...
gcc : el soporte para la x86intrin.h
primera aparece en gcc-4.5.0
. La gcc-4
serie de lanzamiento ya no se mantiene, mientras gcc-6.x
que la serie de lanzamiento estable actual . gcc-5
También introdujo la __has_include
extensión presente en todos los clang-3.x
lanzamientos. gcc-7
está en prelanzamiento (prueba de regresión, etc.) y siguiendo el esquema de versiones actual, se lanzará como gcc-7.1.0
.
Clang : x86intrin.h
parece haber sido compatible con todas las clang-3.x
versiones. La última versión estable es clang (LLVM) 3.9.1
. La rama de desarrollo es clang (LLVM) 5.0.0
. No está claro qué pasó con la 4.x
serie.
Clan de Apple : molestamente, el versionado de Apple no se corresponde con el de los LLVM
proyectos. Dicho esto, el lanzamiento actual: clang-800.0.42.1
se basa en LLVM 3.9.0
. La primera LLVM 3.0
versión basada parece estar de Apple clang 2.1
vuelta Xcode 4.1
. LLVM 3.1
primero aparece con Apple clang 3.1
(una coincidencia numérica) en Xcode 4.3.3
.
Apple también define __apple_build_version__
por ejemplo, 8000042
. Este parece ser el esquema de versiones más estable y estrictamente ascendente disponible. Si no desea admitir compiladores heredados, haga que uno de estos valores sea un requisito mínimo.
Por lo tanto, cualquier versión reciente de clang
, incluidas las versiones de Apple, no debería tener problemas x86intrin.h
. Por supuesto, junto con gcc-5
, siempre puedes usar lo siguiente:
#if defined (__has_include) && (__has_include(<x86intrin.h>))
#include <x86intrin.h>
#else
#error "upgrade your compiler. it's free..."
#endif
Un truco en el que realmente no puede confiar es usar las __GNUC__
versiones clang
. La versión está, por razones históricas, estancada 4.2.1
. Una versión que precede al x86intrin.h
encabezado. De vez en cuando es útil para, por ejemplo, extensiones simples de GNU C que han seguido siendo compatibles con versiones anteriores.
icc : por lo que puedo decir, el x86intrin.h
encabezado es compatible desde al menos Intel C ++ 16.0. La prueba de la versión de puede realizarse con: #if (__INTEL_COMPILER >= 1600)
. Esta versión (y posiblemente versiones anteriores) también proporciona soporte para la __has_include
extensión.
MSVC : Parece que MSVC++ 12.0 (Visual Studio 2013)
es la primera versión que proporciona el intrin.h
encabezado, no x86intrin.h
... esto sugiere: #if (_MSC_VER >= 1800)
como una prueba de versión. Por supuesto, si está intentando escribir código que sea portátil en todos estos compiladores diferentes, el nombre del encabezado en esta plataforma será el menor de sus problemas.
#include <x86intrin.h>
que atrae todo lo que necesita.