哪个头文件为不同的 x86 SIMD 指令集扩展(MMX、 SSE、 AVX、 ...)提供了内部特性?在网上似乎不可能找到这样的名单。如果我说错了请纠正我。
这些天你通常应该只包括 <immintrin.h>。它包括一切。
<immintrin.h>
GCC 和 clang 会阻止您在编译时没有启用指令(例如使用 -march=native或 -mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1或其他指令)时使用内部函数
-march=native
-mavx2 -mbmi2 -mpopcnt -mfma -mcx16 -mtune=znver1
MSVC 和 ICC 将允许您在编译时不启用任何内部函数而使用内部函数,但是在使用 AVX 内部函数之前,您仍然可以使用 应该启用 AVX。
从历史上看(在 immintrin.h引入所有内容之前) ,您必须手动包含所需的最高级别内部函数的标题。
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
包括其中一个拉在所有以前的(除了 AMD-only SSE4A: immintrin.h不拉)
一些编译器也有针对 AVX512的 <zmmintrin.h>。
<zmmintrin.h>
在 GCC/clang 上,如果使用 just
#include <x86intrin.h>
它将包括所有的 SSE/AVX 头,这是根据编译器开关启用,如 -march=haswell或只是 -march=native。此外,一些 x86特定指令(如 bswap或 ror)可以作为内部函数使用。
-march=haswell
bswap
ror
这个头 <intrin.h>的 MSVC 等价物
<intrin.h>
如果您只想要便携式 SIMD,请使用 #include <immintrin.h>
#include <immintrin.h>
MSVC、 ICC 和 gcc/clang (我认为还有其他像 Sun 这样的编译器)都支持 Intel 唯一的内部特性查找器/搜索工具 https://software.intel.com/sites/landingpage/IntrinsicsGuide/记录的 SIMD 内部特性的这个头文件
头的名称取决于您的编译器和目标体系结构。
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-only 的。如果你反对包含更多你实际需要的东西,那么你可以通过查看表格来选择正确的包含。
_bit_scan_forward
_rdtsc
x86intrin.h是获得 AMD XOP (只适用于推土机,甚至不适用于未来的 AMD CPU)内部特性的推荐方法,而不是拥有自己的头。
有些编译器仍然会生成错误消息,如果你使用内部指令集你没有启用(例如 _mm_fmadd_ps没有启用 fma,即使你包括 immintrin.h和启用 AVX2)。
_mm_fmadd_ps
20200914: 最新最佳实践: <immintrin.h>(也得到 MSVC的支持)
我将把剩下的答案留给历史性的目的; 它可能对较老的编译器/平台组合有用..。
正如许多答案和评论所述,<x86intrin.h>是 x86[-64] SIMD 内部函数的 的综合头文件。它还提供了支持其他 ISA 扩展的内部指令。gcc、 clang和 icc都已经决定了。我需要对支持头部的版本进行一些深入研究,并且认为列出一些发现可能会有用... < br/> < br/>
<x86intrin.h>
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的形式发行。
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系列发生了什么。
clang (LLVM) 3.9.1
clang (LLVM) 5.0.0
4.x
令人恼火的是,苹果的版本与 LLVM项目的版本不一致。也就是说,目前的版本: clang-800.0.42.1,是基于 LLVM 3.9.0的。第一个基于 LLVM 3.0的版本似乎是 Apple clang 2.1回到 Xcode 4.1。在 Xcode 4.3.3中,LLVM 3.1首先与 Apple clang 3.1(数字重合)一起出现。苹果还定义了 __apple_build_version__,例如 clang-800.0.42.10。这似乎是可用的最稳定、严格升级的版本控制方案。如果您不想支持遗留编译器,那么将这些值中的一个作为最低要求。
LLVM
clang-800.0.42.1
LLVM 3.9.0
LLVM 3.0
Apple clang 2.1
Xcode 4.1
Xcode 4.3.3
LLVM 3.1
Apple clang 3.1
__apple_build_version__
任何最新版本的 clang,包括苹果版本,因此应该没有问题与 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 扩展有用。< br/> < br/>
__GNUC__
4.2.1
Icc : 据我所知,由于至少 Intel C + + 16.0支持 x86intrin.h头文件。版本测试可以使用以下命令执行: #if (__INTEL_COMPILER >= 1600)。这个版本(可能还有更早的版本)也提供了对 __has_include扩展的支持。
#if (__INTEL_COMPILER >= 1600)
MSVC : 看起来 MSVC++ 12.0 (Visual Studio 2013)是第一个提供 intrin.h头文件的版本-没有 x86intrin.h... 这表明: #if (_MSC_VER >= 1800)作为一个版本测试。当然,如果您试图编写跨所有这些不同编译器的可移植代码,那么这个平台上的头名将是最小的问题。
MSVC++ 12.0 (Visual Studio 2013)
#if (_MSC_VER >= 1800)