【问题标题】:Header files for x86 SIMD intrinsicsx86 SIMD 内部函数的头文件
【发布时间】:2012-06-29 00:59:28
【问题描述】:

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

【问题讨论】:

    标签: x86 header-files sse simd intrinsics


    【解决方案1】:

    这些天你通常应该只包括<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
    

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

    一些编译器还为 AVX512 提供 &lt;zmmintrin.h&gt;

    【讨论】:

    • 或者你也可以#include &lt;x86intrin.h&gt; 获取你需要的一切。
    • zmmintrin.h 具有 AVX-512 内在函数。
    • 为什么 SSE3/SSSE3/SSE4.1 和 4.2 有 p、t、s 和 n?这些字符代表什么?
    • @LưuVĩnhPhúc SSE3 = Prescott 新指令,SSSE3 = Tejas 新指令。我认为 SSE4.2 和 AES 指的是它们被引入的处理器系列(Nehalem 和 Westmere)
    • 不要直接包含&lt;zmmintrin.h&gt;; gcc 甚至不提供它。 只需使用 &lt;immintrin.h&gt; 或更完整的 &lt;x86intrin.h&gt;。这个答案基本上已经过时了,除非您有意避免包含较新版本的 SSE 的内在函数,因为在为 SSE2 编译时使用 SSE4.1 指令时编译器不会抱怨。 (gcc/clang do 抱怨,所以你应该只为他们使用 immintrin.h。关于其他人的 IDK。)
    【解决方案2】:

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

    #include <x86intrin.h>
    

    它将包括所有根据编译器开关启用的 SSE/AVX 标头,例如 -march=haswell 或只是 -march=native。此外,一些 x86 特定指令(如 bswapror)可作为内部函数使用。


    此标头 &lt;intrin.h&gt; 的 MSVC 等效项


    如果您只需要便携式 SIMD,请使用 #include &lt;immintrin.h&gt;

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

    【讨论】:

    • 我不确定,如果较新的版本可能......无论如何只要 gcc、icc 和 clang 有它,我认为可以使用 :-)
    • MSVC 没有&lt;x86intrin.h&gt;,但&lt;intrin.h&gt; 实现了类似的效果。当然,您仍然需要条件编译。 :-(
    • 所有主要的 x86 编译器都有 #include &lt;immintrin.h&gt;。将其用于 SIMD 内在函数。如果您需要整数旋转/位扫描内在函数之类的东西,您只需要更大(并且编译器稍微慢一些)x86intrin.hintrin.h(尽管英特尔记录了其中一些在 immintrin.h in their intrinsics guide 中可用)。
    • IIRC,英特尔在 immintrin.h 中记录了一些非 SIMD 内在函数,但 gcc、clang 和/或 MSVC 仅在 x86intrin.h / intrin.h 中具有,但 immintrin.h中。
    【解决方案3】:

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

    • 对于 Microsoft C++(针对 x86、x86-64 或 ARM)和适用于 Windows 的 Intel C/C++ 编译器,请使用 intrin.h
    • 对于针对 x86/x86-64 的 gcc/clang/icc,请使用 x86intrin.h
    • 对于使用 NEON 的 gcc/clang/armcc 目标 ARM,请使用 arm_neon.h
    • 对于使用 WMMX 以 ARM 为目标的 gcc/clang/armcc,请使用 mmintrin.h
    • 对于使用 VMX(又名 Altivec)和/或 VSX 以 PowerPC 为目标的 gcc/clang/xlcc,请使用 altivec.h
    • 对于带有 SPE 的 gcc/clang 目标 PowerPC 使用 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
    

    【讨论】:

    • 这里还有一些要添加到您的列表中:在带有 gcc 的 UltraSPARC+VIS 上,使用 visintrin.h;如果您有 Sun 的 VSDK,vis.h 会提供一组不同的内在函数。可在此处找到文档:GCC VIS builtinsSun VIS user's guide
    【解决方案4】:

    来自page

    +----------------+------------------------------------------------------------------------------------------+
    |     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-only, not even future AMD CPUs) 的内在函数的推荐方法,而不是拥有自己的标头。

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

    【讨论】:

    • smmintrin (SSE4.1) 是 Penryn (45nm Core2),而不是 Nehalem ("i7")。我们可以停止使用“i7”作为架构名称吗? It's meaningless now that Intel has kept using it for SnB-family.
    • immintrin.h 似乎不包括 _popcnt32_popcnt64(不要与 popcntintrin.h 中的那些混淆!)GCC 9.1.0 的内在函数。所以看来x86intrin.h 仍然是有目的的。
    【解决方案5】:

    20200914: 最新最佳实践:&lt;immintrin.h&gt;(也受 MSVC 支持)

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


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

    • 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 的版本似乎是Apple clang 2.1 回到Xcode 4.1LLVM 3.1Xcode 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.1x86intrin.h 标头之前的版本。它有时对保持向后兼容的简单 GNU C 扩展很有用。

    • icc :据我所知,至少从 Intel C++ 16.0 开始就支持 x86intrin.h 标头。版本测试可以通过:#if (__INTEL_COMPILER &gt;= 1600) 执行。此版本(可能还有更早的版本)还提供对 __has_include 扩展的支持。

    • MSVC:看来MSVC++ 12.0 (Visual Studio 2013) 是第一个提供intrin.h 标头的版本 - 不是 x86intrin.h... 这表明:#if (_MSC_VER &gt;= 1800)作为版本测试。当然,如果您尝试编写可在所有这些不同编译器之间移植的代码,那么这个平台上的标头名称将是您最少的问题。

    【讨论】:

    猜你喜欢
    • 2012-11-05
    • 2021-12-09
    • 2021-04-15
    • 1970-01-01
    • 2020-12-26
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多