153

哪些头文件为不同的 x86 SIMD 指令集扩展(MMX、SSE、AVX...)提供了内在函数?在网上似乎不可能找到这样的清单。如我错了请纠正我。

4

5 回答 5

202

这些天你通常应该只包括<immintrin.h>. 它包括一切。

GCC 和 clang 将阻止您使用内在函数来执行您在编译时未启用的指令(例如,使用-march=nativeor-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

包括其中一个拉入所有以前的拉(除了仅 AMD 的 SSE4A:immintrin.h不拉入)

一些编译器也有<zmmintrin.h>AVX512。

于 2012-06-27T14:45:09.623 回答
85

在 GCC/clang 上,如果你只使用

#include <x86intrin.h>

它将包括根据编译器开关启用的所有 SSE/AVX 标头,-march=haswell例如-march=native. 此外,一些 x86 特定指令类似于bswapror可用作内在函数。


此标头的 MSVC 等效项<intrin.h>


如果您只想要便携式 SIMD,请使用#include <immintrin.h>

MSVC、ICC 和 gcc/clang(以及我认为的其他编译器,如 Sun)都支持英特尔唯一的内部函数查找器/搜索工具记录的 SIMD 内部函数的此标头:https ://software.intel.com/sites/landingpage/IntrinsicsGuide /

于 2012-06-27T15:59:30.743 回答
61

标头名称取决于您的编译器和目标体系结构。

  • 对于 Microsoft C++(面向 x86、x86-64 或 ARM)和适用于 Windows 的 Intel C/C++ 编译器intrin.h
  • 对于针对 x86/x86-64 的 gcc/clang/icc 使用x86intrin.h
  • 对于使用 NEON 以 ARM 为目标的 gcc/clang/armccarm_neon.h
  • 对于 gcc/clang/armcc,使用 WMMX 以 ARM 为目标mmintrin.h
  • 对于带有 VMX(又名 Altivec)和/或 VSX 的针对 PowerPC 的 gcc/clang/xlcc 使用altivec.h
  • 对于使用 SPE 的 gcc/clang 目标 PowerPCspe.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
于 2014-03-10T03:22:49.467 回答
50

从这个页面

+----------------+------------------------------------------------------------------------------------------+
|     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_forwardand在内的所有内容,_rdtsc以及所有矢量内在函数都包括仅 AMD 的。如果您反对包含更多您实际需要的内容,那么您可以通过查看表格来选择正确的包含。

x86intrin.h是获得AMD XOP 内在函数的推荐方法(仅限推土机,甚至未来的 AMD CPU),而不是拥有自己的标头。

_mm_fmadd_ps如果您对未启用的指令集使用内部函数(例如,即使您包含immintrin.h并启用了 AVX2 ,也未启用 fma),某些编译器仍会生成错误消息。

于 2015-07-02T13:23:37.730 回答
20

20200914:最新的最佳实践:(<immintrin.h>也受MSVC支持)

我将把剩下的答案留作历史用途;它可能对较旧的编译器/平台组合有用......


正如许多答案和评论所述,<x86intrin.h>是x86[-64] SIMD 内在函数综合标头。它还为其他 ISA 扩展提供内在函数支持指令。gcc, clang, 并且icc都解决了这个问题。我需要对支持标头的版本进行一些挖掘,并认为列出一些发现可能很有用......

  • gcc : 支持x86intrin.hfirst 出现在gcc-4.5.0. gcc-4发布系列不再维护,gcc-6.x而是当前稳定的发布系列。gcc-5还介绍了所有版本中__has_include存在的扩展。处于预发布(回归测试等)并遵循当前版本控制方案,将发布为.clang-3.xgcc-7gcc-7.1.0

  • clangx86intrin.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'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)作为版本测试。当然,如果您尝试编写可在所有这些不同编译器之间移植的代码,那么此平台上的标头名称将是您遇到的最少问题。

于 2017-02-27T19:11:16.963 回答