Заголовочные файлы для встроенных функций x86 SIMD

131

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

fredoverflow
источник

Ответы:

174

В наши дни вы обычно должны просто включать <immintrin.h> . Он включает в себя все.

GCC и clang остановят вас от использования встроенных функций для инструкций, которые вы не включили во время компиляции (например, с помощью -march=nativeили-mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1 или что-то еще.)

MSVC и ICC позволят вам использовать встроенные функции без включения чего-либо во время компиляции, но вы все равно должны включить AVX перед использованием встроенных функций AVX.


Исторически (до того, как immintrin.hвтягивать все) вам приходилось вручную включать заголовок для самого высокого уровня встроенных функций, который вы хотели.

Это все еще может быть полезно с MSVC и ICC, чтобы вы не могли использовать наборы инструкций, которые вам не нужны.

<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

Включение одного из этих подтягиваний во все предыдущие (кроме SSE4A только для AMD: immintrin.hэто не задействует)

Некоторые компиляторы также есть <zmmintrin.h>для AVX512.

fredoverflow
источник
62
Или вы можете просто #include <x86intrin.h>втягивать все, что вам нужно.
Paul R
2
zmmintrin.h имеет встроенные функции AVX-512.
onitake
3
Почему p, t, s и n для SSE3 / SSSE3 / SSE4.1 и 4.2? Что представляют собой эти персонажи?
phuclv
5
@ LưuVĩnhPhúc SSE3 = Новые инструкции Prescott, SSSE3 = Новые инструкции Tejas. Я думаю, что SSE4.2 и AES относятся к семейству процессоров, в котором они были представлены (Nehalem и Westmere)
Дрю МакГоуэн,
14
Не включайте <zmmintrin.h>напрямую; gcc даже не предоставляет этого. Просто используйте<immintrin.h> или еще более полный <x86intrin.h>. Этот ответ в основном устарел, если только вы намеренно не избегаете включения встроенных функций для новых версий SSE, потому что ваш компилятор не жалуется, когда вы используете инструкцию SSE4.1 при компиляции для SSE2. (gcc / clang действительно жалуются, поэтому вы должны просто использовать для них immintrin.h. IDK о других.)
Питер Кордес
76

В GCC / clang, если вы используете только

#include <x86intrin.h>

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


Эквивалент этого заголовка в MSVC <intrin.h>


Если вам просто нужен портативный SIMD, используйте #include <immintrin.h>

MSVC, ICC и gcc / clang (и другие компиляторы, вроде Sun, я думаю) поддерживают этот заголовок для встроенных функций SIMD, задокументированных единственным встроенным средством поиска / поиска Intel: https://software.intel.com/sites/landingpage/IntrinsicsGuide /

Гюнтер Пьез
источник
Я не был уверен, могут ли более новые версии ... В любом случае, если они есть в gcc, icc и clang, я думаю, что можно использовать :-)
Гюнтер Пьез
5
MSVC не имеет <x86intrin.h>, но дает <intrin.h>аналогичный эффект. Конечно, вам все еще нужна условная компиляция. :-(
Коди Грей
Все основные компиляторы x86 имеют #include <immintrin.h>. Используйте это для внутренних функций SIMD. Вам нужен только еще больший (и немного более медленный для компилятора) x86intrin.hили intrin.hесли вам нужны такие вещи, как встроенные функции целочисленного поворота / побитового сканирования (хотя Intel документирует некоторые из них как доступные immintrin.h в своем руководстве по встроенным функциям ).
Питер Кордес
IIRC, есть некоторые встроенные функции, отличные от SIMD, которые Intel документирует как находящиеся в immintrin.h, но которые gcc, clang и / или MSVC имеют только в x86intrin.h/, intrin.hно не в immintrin.h.
Питер Кордес
56

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

  • Для Microsoft C ++ (для x86, x86-64 или ARM) и компилятора Intel C / 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 (он же 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
Марат Духан
источник
Вот еще кое-что, что можно добавить в свой список: В UltraSPARC + VIS с gcc используйте visintrin.h; если у вас есть Sun VSDK, vis.h предлагает другой набор встроенных функций. Документацию можно найти здесь: встроенные функции GCC VIS , руководство пользователя Sun VIS .
onitake
44

С этой страницы

+----------------+------------------------------------------------------------------------------------------+
|     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- рекомендуемый способ получить встроенные функции для AMD XOP (только Bulldozer, даже не будущие процессоры AMD) вместо того, чтобы иметь собственный заголовок.

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

RubenLaguna
источник
1
smmintrin(SSE4.1) - это Penryn (45 нм Core2), а не Nehalem ("i7"). Можем ли мы перестать использовать «i7» в качестве названия архитектуры? Это бессмысленно сейчас, когда Intel продолжила использовать его для семейства SnB .
Питер Кордес
immintrin.hпохоже, не включает _popcnt32и _popcnt64(не путать с теми, что есть popcntintrin.h!) встроенные функции в GCC 9.1.0. Так что, похоже, это x86intrin.hвсе еще служит цели.
Том Виггерс,
12

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

  • 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 лязгнула : досадно, что версия 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's free..."
#endif

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

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

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

Бретт Хейл
источник