Какие файлы заголовков предоставляют встроенные функции для различных расширений набора инструкций SIMD x86 (MMX, SSE, AVX, ...)? В сети такой список найти невозможно. Поправьте меня если я ошибаюсь.
Какие файлы заголовков предоставляют встроенные функции для различных расширений набора инструкций SIMD x86 (MMX, SSE, AVX, ...)? В сети такой список найти невозможно. Поправьте меня если я ошибаюсь.
Ответы:
В наши дни вы обычно должны просто включать <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.
<zmmintrin.h>
напрямую; gcc даже не предоставляет этого. Просто используйте<immintrin.h>
или еще более полный <x86intrin.h>
. Этот ответ в основном устарел, если только вы намеренно не избегаете включения встроенных функций для новых версий SSE, потому что ваш компилятор не жалуется, когда вы используете инструкцию SSE4.1 при компиляции для SSE2. (gcc / clang действительно жалуются, поэтому вы должны просто использовать для них immintrin.h. IDK о других.)
В 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 /
<x86intrin.h>
, но дает <intrin.h>
аналогичный эффект. Конечно, вам все еще нужна условная компиляция. :-(
#include <immintrin.h>
. Используйте это для внутренних функций SIMD. Вам нужен только еще больший (и немного более медленный для компилятора) x86intrin.h
или intrin.h
если вам нужны такие вещи, как встроенные функции целочисленного поворота / побитового сканирования (хотя Intel документирует некоторые из них как доступные immintrin.h
в своем руководстве по встроенным функциям ).
x86intrin.h
/, intrin.h
но не в immintrin.h
.
Имя заголовка зависит от вашего компилятора и целевой архитектуры.
intrin.h
x86intrin.h
arm_neon.h
mmintrin.h
altivec.h
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
С этой страницы
+----------------+------------------------------------------------------------------------------------------+
| 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).
smmintrin
(SSE4.1) - это Penryn (45 нм Core2), а не Nehalem ("i7"). Можем ли мы перестать использовать «i7» в качестве названия архитектуры? Это бессмысленно сейчас, когда Intel продолжила использовать его для семейства SnB .
immintrin.h
похоже, не включает _popcnt32
и _popcnt64
(не путать с теми, что есть popcntintrin.h
!) встроенные функции в GCC 9.1.0. Так что, похоже, это x86intrin.h
все еще служит цели.
Поскольку многие ответов и комментарии заявили, <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 лязгнула : досадно, что версия 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)
как тест версии. Конечно, если вы пытаетесь написать код, который переносится на все эти разные компиляторы, имя заголовка на этой платформе будет наименьшей из ваших проблем.
#include <x86intrin.h>
втягивать все, что вам нужно.