哪些头文件提供了不同的x86 SIMD指令集扩展(MMX,SSE,AVX等)的内置函数?似乎很难在线上找到这样的列表。如果我错了,请纠正我。
哪些头文件提供了不同的x86 SIMD指令集扩展(MMX,SSE,AVX等)的内置函数?似乎很难在线上找到这样的列表。如果我错了,请纠正我。
<immintrin.h>
,它会包含所有内容。-march=native
或-mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
等)。immintrin.h
引入所有内容之前),您需要手动包含一个头文件以获取所需级别的内部函数。<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
包含这些头文件中的任意一个会包含之前的所有头文件(除了仅限于AMD的SSE4A: immintrin.h
不会包含它)。
一些编译器还有用于AVX512的<zmmintrin.h>
。
在GCC / clang上,如果你只使用
#include <x86intrin.h>
这个头文件将包括所有根据编译器开关(如-march=haswell
或-march=native
)启用的SSE/AVX头文件。此外,一些特定于x86的指令,如bswap
或ror
,会作为内建函数可用。
MSVC等效的头文件是<intrin.h>
如果你只想要可移植的SIMD,请使用#include <immintrin.h>
MSVC、ICC以及gcc/clang(还有其他编译器,例如Sun)都支持该头文件,用于Intel唯一Intrinsics查找工具/搜索工具记录的SIMD内建函数:https://software.intel.com/sites/landingpage/IntrinsicsGuide/
<x86intrin.h>
头文件,但是<intrin.h>
可以实现类似的效果。当然,你仍然需要条件编译。 :-( - Cody Gray#include <immintrin.h>
**。使用它来进行SIMD内嵌函数。只有当您需要像整数旋转/位扫描内嵌函数这样的东西时,您才需要更大(并且稍微慢一些)的x86intrin.h
或intrin.h
(尽管英特尔在其内嵌函数指南中将其中一些文档化为在immintrin.h
中可用)。 - Peter Cordesx86intrin.h
/ intrin.h
中提供,而不在immintrin.h
中。 - Peter Cordes头文件的名称取决于你的编译器和目标架构。
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
即可获得所有英特尔扩展,或者如果您需要包括_bit_scan_forward
和_rdtsc
以及包括AMD专有的所有矢量内在函数,则使用x86intrin.h
。如果您反对包含实际不需要的内容,则可以通过查看表格选择正确的包含文件。
x86intrin.h
是获取 AMD XOP(仅适用于Bulldozer,甚至未来的AMD CPU)内在函数的推荐方法,而不是具有自己的头文件。
一些编译器仍然会生成错误消息,如果您使用尚未启用的指令集的内在函数(例如,如果您包括immintrin.h
并启用了AVX2,则没有启用fma的情况下使用_mm_fmadd_ps
)。
smmintrin
(SSE4.1)是Penryn(45nm Core2),而不是Nehalem(“i7”)。我们能否停止使用“i7”作为架构名称?现在英特尔已经继续在SnB系列中使用它,这意义已经不存在了。 - Peter Cordesimmintrin.h
在 GCC 9.1.0 中似乎没有包含 _popcnt32
和 _popcnt64
(不要与 popcntintrin.h
中的那些混淆!)内置函数。因此,看来 x86intrin.h
仍然有其作用。 - Thom Wiggers20200914: 最新最佳实践: <immintrin.h>
(也受到MSVC
支持)。
我将保留其余的回答以供历史记录使用;它可能对旧的编译器/平台组合很有用...
正如许多答案和评论所述,<x86intrin.h>
是x86[-64] SIMD内部函数的综合头文件。它还提供支持其他ISA扩展指令的内部函数。 gcc
,clang
和icc
都已经在此上达成共识。我需要挖掘一些支持头文件的版本,并认为列出一些发现可能会很有用...
gcc: x86intrin.h
支持首次出现在gcc-4.5.0
。 不再维护gcc-4
发布系列,而gcc-6.x
是当前稳定发布系列。 gcc-5
还引入了所有clang-3.x
版本中存在的__has_include
扩展。 gcc-7
处于预发布状态(回归测试等),根据当前的版本控制方案,将发布为gcc-7.1.0
。
clang:所有clang-3.x
版本似乎都支持x86intrin.h
。 最新的稳定发行版是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
的版本似乎是Xcode 4.1
中的Apple clang 2.1
。 LLVM 3.1
在Xcode 4.3.3
中首次出现,并与Apple clang 3.1
(数字上的巧合)一起出现。
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
有一个技巧你不能太依赖,那就是在clang
中使用__GNUC__
的版本。由于历史原因,版本控制被固定在了4.2.1
上,在x86intrin.h
头文件之前。但对于一些简单的保持向后兼容性的GNU C扩展来说偶尔还是很有用的。
icc: 据我所知,自至少Intel C++ 16.0以来,支持x86intrin.h
头文件。版本测试可以使用:#if (__INTEL_COMPILER >= 1600)
。 这个版本(可能还包括更早的版本)还提供了__has_include
扩展的支持。
MSVC: 看起来MSVC++ 12.0 (Visual Studio 2013)
是第一个提供intrin.h
头文件而非x86intrin.h
的版本……这表明:版本测试应该是#if (_MSC_VER >= 1800)
。当然,如果你试图编写能够跨所有这些不同编译器的可移植代码,此平台上的头文件名将是你最不关心的问题。
__has_builtin
而不是烦人的版本检查。同时需要注意,GCC在某些内建函数上仍存在一些错误;在这种情况下,我会考虑使用特定于目标的内建函数,即使它们是未经记录的。 - FrankHB
#include <x86intrin.h>
,这将引入您所需的所有内容。 - Paul R<zmmintrin.h>
,因为gcc甚至不提供它。**只需使用<immintrin.h>
**或者更加完整的<x86intrin.h>
。这个答案基本上已经过时了,除非你有意避免包含新版本SSE的内置函数,因为当你编译为SSE2时,编译器不会在你使用SSE4.1指令时发出警告。(gcc/clang 会 发出警告,所以你应该为它们使用immintrin.h。其他编译器我不清楚。) - Peter Cordes