Заголовочные файлы для x86 SIMD intrinsics

Какие файлы заголовков предоставляют встроенные функции для разных наборов инструкций для SIM-карт x86 (MMX, SSE, AVX,...)? Невозможно найти такой список в Интернете. Исправьте меня, если я ошибаюсь.

Ответ 1

<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

<zmmintrin.h> AVX512

Ответ 2

Если вы используете только

#include <x86intrin.h>

он будет включать в себя все заголовки SSE/AVX, которые активируются в соответствии с коммутаторами компилятора типа -march=corei7 или просто -march=native. Кроме того, некоторые х86 конкретные инструкции, такие как bswap или ror, становятся доступными как встроенные.

Ответ 3

Название заголовка зависит от вашей компиляции и целевой архитектуры.

  • Для Microsoft С++ (таргетинг на x86, x86-64 или ARM) и компилятор Intel C/С++ для Windows используйте intrin.h
  • Для gcc/clang/icc таргетинга x86/x86-64 используйте x86intrin.h
  • Для gcc/clang/armcc таргетинга ARM с использованием NEON arm_neon.h
  • Для gcc/clang/armcc таргетинга ARM с использованием WMMX mmintrin.h
  • Для gcc/clang/xlcc-таргетинга PowerPC с VMX (aka Altivec) и/или VSX используйте altivec.h
  • Для gcc/clang-таргетинга PowerPC с использованием SPE spe.h

Вы можете обрабатывать все эти случаи с помощью условных предпроцессорных директив:

#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

Ответ 4

Из этого страница

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

Таким образом, вы можете просто включить immintrin.h, чтобы получить все расширения Intel, или x86intrin.h, если вы хотите, чтобы все, включая _bit_scan_forward и _rdtsc, а также все векторные свойства, включали только AMD. Если вы против включения большего количества, которое вам действительно нужно, вы можете выбрать правильное включение, посмотрев на таблицу.

x86intrin.h - рекомендуемый способ получить intrinsics для AMD XOP (только для Bulldozer, даже для будущих процессоров AMD), вместо того, чтобы его собственный заголовок.

Некоторые компиляторы все равно будут генерировать сообщения об ошибках, если вы используете встроенные средства для наборов инструкций, которые вы не включили (например, _mm_fmadd_ps без включения fma, даже если вы включили immintrin.h и включили AVX2).

Ответ 5

Как было сказано в большинстве ответов и комментариев, <x86intrin.h> является полным заголовком для x86 [-64] SIMD-функций. Он также предоставляет встроенные инструкции для других расширений ISA. gcc, clang, и icc все это решило. Мне нужно было кое-что сделать на версиях, поддерживающих заголовок, и подумал, что было бы полезно перечислить некоторые результаты...

  • gcc: поддержка x86intrin.h сначала появляется в gcc-4.5.0. Серия релизов gcc-4 больше не поддерживается, а gcc-6.x - это текущая стабильная серия выпусков. gcc-5 также представил расширение __has_include, присутствующее во всех выпусках clang-3.x. gcc-7 находится в предварительном выпуске (регрессионное тестирование и т.д.) и после текущей схемы управления версиями будет выпущен как gcc-7.1.0.

  • clang: x86intrin.h, похоже, поддерживается для всех выпусков clang-3.x. Последний стабильный релиз - clang (LLVM) 3.9.1. Область разработки clang (LLVM) 5.0.0. Не понятно, что случилось с серией 4.x.

  • Apple clang: досадно, Apple, версия не соответствует тем, что в проектах LLVM. Тем не менее, текущий релиз: clang-800.0.42.1 основан на LLVM 3.9.0. Первая версия LLVM 3.0 выглядит как Apple clang 2.1 назад в Xcode 4.1. LLVM 3.1 сначала появляется с Apple clang 3.1 (числовое совпадение) в Xcode 4.3.3.

    Apple также определяет __apple_build_version__, например, 8000042. Это похоже на самую стабильную, строго восходящую схему управления версиями. Если вы не хотите поддерживать устаревшие компиляторы, сделайте одно из этих значений минимальным.

Любая недавняя версия clang, включая версии Apple, не должна иметь проблем с x86intrin.h. Конечно, наряду с gcc-5 вы всегда можете использовать следующее:

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

Один трюк, на который вы не можете положиться, - это использовать версии __GNUC__ в clang. Версии по историческим причинам застревают в 4.2.1. Версия, предшествующая заголовку x86intrin.h. Это иногда полезно, например, для простых расширений GNU C, которые остались обратно совместимыми.

  • icc: насколько я могу судить, заголовок x86intrin.h поддерживается, по крайней мере, с Intel С++ 16.0. Тест версии может быть выполнен с помощью: #if (__INTEL_COMPILER >= 1600). Эта версия (и, возможно, более ранние версии) также поддерживает поддержку расширения __has_include.

  • MSVC. Похоже, что MSVC++ 12.0 (Visual Studio 2013) является первой версией, предоставляющей заголовок intrin.h - not x86intrin.h... это предполагает: #if (_MSC_VER >= 1800) как тест версии, Конечно, если вы пытаетесь написать код, который переносится во всех этих разных компиляторах, имя заголовка на этой платформе будет наименьшим из ваших проблем.