Quais arquivos de cabeçalho fornecem as intrínsecas para as diferentes extensões do conjunto de instruções x86 SIMD (MMX, SSE, AVX, ...)? Parece impossível encontrar essa lista online. Corrija-me se eu estiver errado.
Quais arquivos de cabeçalho fornecem as intrínsecas para as diferentes extensões do conjunto de instruções x86 SIMD (MMX, SSE, AVX, ...)? Parece impossível encontrar essa lista online. Corrija-me se eu estiver errado.
Respostas:
Hoje em dia você normalmente deve apenas incluir <immintrin.h>
. Inclui tudo.
O GCC e o clang impedirão você de usar intrínsecos para instruções que você não ativou no momento da compilação (por exemplo, com -march=native
ou -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
ou o que for.)
O MSVC e o ICC permitem usar intrínsecos sem ativar nada no tempo de compilação, mas você ainda deve habilitar o AVX antes de usar os intrínsecos do AVX.
Historicamente (antes de obter immintrin.h
tudo), era necessário incluir manualmente um cabeçalho para o mais alto nível de intrínsecas que você desejava.
Isso ainda pode ser útil com o MSVC e o ICC para impedir o uso de conjuntos de instruções que você não deseja exigir.
<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
Incluindo um desses puxões em todos os anteriores (exceto o SSE4A somente AMD: immintrin.h
não puxa isso)
Alguns compiladores também têm <zmmintrin.h>
para o AVX512.
<zmmintrin.h>
diretamente; O GCC nem o fornece. Basta usar<immintrin.h>
ou o ainda mais completo <x86intrin.h>
. Essa resposta é basicamente obsoleta, a menos que você intencionalmente evite incluir intrínsecos para versões mais recentes do SSE, porque seu compilador não reclama quando você usa uma instrução SSE4.1 durante a compilação do SSE2. (gcc / clang que reclamar, então você deve apenas usar immintrin.h para eles IDK sobre os outros..)
No GCC / clang, se você usar apenas
#include <x86intrin.h>
incluirá todos os cabeçalhos SSE / AVX que são ativados de acordo com as opções do compilador, como -march=haswell
apenas -march=native
. Além disso, algumas instruções específicas do x86, como bswap
ou ror
se tornam disponíveis como intrínsecas.
O equivalente MSVC deste cabeçalho <intrin.h>
Se você quiser apenas o SIMD portátil, use #include <immintrin.h>
MSVC, ICC e gcc / clang (e outros compiladores como a Sun, eu acho) suportam esse cabeçalho para as intrínsecas SIMD documentadas pela única ferramenta de busca / pesquisa intrínseca da Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide /
<x86intrin.h>
, mas <intrin.h>
alcança um efeito semelhante. Você ainda precisa de compilação condicional, é claro. :-(
#include <immintrin.h>
. Use isso para intrínsecas do SIMD. Você só precisa do tamanho ainda maior (e um pouco mais lento para o compilador) x86intrin.h
ou intrin.h
se precisar de itens como intrínsecos de rotação / varredura de bits inteiros (embora a Intel documente alguns deles como disponíveis no immintrin.h
guia de intrínsecos ).
x86intrin.h
/ intrin.h
mas não em immintrin.h
.
O nome do cabeçalho depende do seu compilador e arquitetura de destino.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
spe.h
Você pode lidar com todos esses casos com diretivas de pré-processamento 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
A partir desta 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 |
+----------------+------------------------------------------------------------------------------------------+
Portanto, em geral, você pode incluir apenas immintrin.h
para obter todas as extensões Intel, ou x86intrin.h
se quiser tudo, incluindo _bit_scan_forward
e _rdtsc
, além de todas as intrínsecas de vetores, incluindo apenas AMD. Se você for contra, incluindo mais do que realmente precisa, poderá escolher a inclusão correta olhando para a mesa.
x86intrin.h
é a maneira recomendada de obter intrínsecas para o AMD XOP (somente Bulldozer, nem mesmo os futuros processadores AMD) , em vez de ter seu próprio cabeçalho.
Alguns compiladores ainda gerarão mensagens de erro se você usar elementos intrínsecos para conjuntos de instruções que você não ativou (por exemplo, _mm_fmadd_ps
sem ativar o fma, mesmo se você incluir immintrin.h
e ativar o AVX2).
smmintrin
(SSE4.1) é Penryn (45 nm Core2), não Nehalem ("i7"). Podemos parar de usar "i7" como um nome de arquitetura? Não faz sentido agora que a Intel continuou usando-o para a família SnB .
immintrin.h
parece não incluir _popcnt32
e _popcnt64
(não deve ser confundido com os que estão dentro popcntintrin.h
!) intrínsecas no GCC 9.1.0. Então parece que x86intrin.h
ainda serve a um propósito.
Como muitas das respostas e comentários declararam, <x86intrin.h>
é o cabeçalho abrangente para intrínsecas do SIMD x86 [-64]. Ele também fornece instruções de suporte intrínsecas para outras extensões ISA. gcc
,, clang
e icc
todos decidiram isso. Eu precisava pesquisar algumas versões que suportam o cabeçalho e pensei que poderia ser útil listar algumas descobertas ...
gcc : o suporte para o x86intrin.h
primeiro aparece em gcc-4.5.0
. A gcc-4
série de lançamentos não está mais sendo mantida, enquanto gcc-6.x
a atual é a série estável. gcc-5
também introduziu a __has_include
extensão presente em todas as clang-3.x
versões. gcc-7
está em pré-lançamento (teste de regressão, etc.) e segue o esquema de versão atual, será lançado como gcc-7.1.0
.
clang : x86intrin.h
parece ter sido suportado para todos os clang-3.x
lançamentos. A última versão estável é clang (LLVM) 3.9.1
. O ramo de desenvolvimento é clang (LLVM) 5.0.0
. Não está claro o que aconteceu com a 4.x
série.
Clang da Apple : irritantemente, o versionamento da Apple não corresponde ao dos LLVM
projetos. Dito isto, a versão atual:, clang-800.0.42.1
é baseada em LLVM 3.9.0
. A primeira LLVM 3.0
versão baseada parece estar de Apple clang 2.1
volta Xcode 4.1
. LLVM 3.1
aparece pela primeira vez com Apple clang 3.1
(uma coincidência numérica) em Xcode 4.3.3
.
A Apple também define __apple_build_version__
, por exemplo 8000042
,. Esse parece ser o esquema de versão mais estável e estritamente ascendente disponível. Se você não deseja oferecer suporte a compiladores herdados, torne um desses valores um requisito mínimo.
Qualquer versão recente clang
, incluindo as versões da Apple, não deve ter nenhum problema x86intrin.h
. Obviamente, junto com gcc-5
, você sempre pode usar o seguinte:
#if defined (__has_include) && (__has_include(<x86intrin.h>))
#include <x86intrin.h>
#else
#error "upgrade your compiler. it's free..."
#endif
Um truque em que você realmente não pode confiar é usar as __GNUC__
versões clang
. O controle de versão é, por razões históricas, bloqueado 4.2.1
. Uma versão que precede o x86intrin.h
cabeçalho. Ocasionalmente, é útil para, digamos, extensões GNU C simples que permaneceram compatíveis com versões anteriores.
icc : pelo que sei, o x86intrin.h
cabeçalho é suportado desde pelo menos Intel C ++ 16.0. O teste versão pode por executada com: #if (__INTEL_COMPILER >= 1600)
. Esta versão (e possivelmente versões anteriores) também fornece suporte para a __has_include
extensão.
MSVC : Parece que MSVC++ 12.0 (Visual Studio 2013)
é a primeira versão a fornecer o intrin.h
cabeçalho - não x86intrin.h
... isso sugere: #if (_MSC_VER >= 1800)
como um teste de versão. Obviamente, se você estiver tentando escrever um código portátil em todos esses diferentes compiladores, o nome do cabeçalho nessa plataforma será o menor dos seus problemas.
#include <x86intrin.h>
que extrai tudo o que você precisa.