x86 SIMD内部函数的头文件


131

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

Answers:


174

这些天,您通常应该只包括<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不会加载)

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


62
或者,您可以#include <x86intrin.h>选择所需的一切。
Paul R

2
zmmintrin.h具有AVX-512内在函数。
2014年

3
为什么SSE3 / SSSE3 / SSE4.1和4.2为p,t,s和n?这些字符代表什么?
phuclv

5
@LưuVĩnhPhúcSSE3 = Prescott新指令,SSSE3 = Tejas新指令。我认为SSE4.2和AES是指它们引入的处理器家族(Nehalem和Westmere)
Drew McGowen

14
不要<zmmintrin.h>直接包括在内;gcc甚至没有提供它。只需使用<immintrin.h>或什至更完整<x86intrin.h>。除非您有意避免为较新版本的SSE包括内在函数,否则此答案基本上是过时的,因为在为SSE2进行编译时使用SSE4.1指令时,编译器不会抱怨。(gcc / clang 确实抱怨,所以您应该为他们使用immintrin.h。关于其他人的IDK。)
Peter Cordes

76

在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 /


我不确定,是否可以使用较新的版本...无论如何,只要gcc,icc和clang都可以,我认为可以使用它:-)
Gunther Piez 2012年

5
MSVC没有<x86intrin.h>,但是<intrin.h>达到了类似的效果。当然,您仍然需要条件编译。:-(
Cody Gray

所有主要的x86编译器都有#include <immintrin.h>。将其用于SIMD内部函数。您只需要更大(甚至更慢的编译器),x86intrin.h或者intrin.h需要诸如整数旋转/位扫描内在函数之类的东西(尽管英特尔在其内在函数指南中提供了其中的一些文档)immintrin.h )。
彼得·科德斯

IIRC,还有一些非SIMD内在英特尔文档在immintrin.h之中,但GCC,铛,和/或MSVC只有在x86intrin.h/ intrin.h不是immintrin.h
彼得·科德斯

56

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

  • 适用于Windows的Microsoft C ++(针对x86,x86-64或ARM)和Intel C / C ++编译器 intrin.h
  • 对于针对x86 / x86-64的gcc / clang / icc,请使用 x86intrin.h
  • 对于使用NEON定位gcc / clang / armcc的ARM arm_neon.h
  • 对于使用WMMX的gcc / clang / armcc定位ARM mmintrin.h
  • 对于使用VMX(aka 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内置文件Sun VIS用户指南
onitake 2014年

44

从这个页面

+----------------+------------------------------------------------------------------------------------------+
|     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获得所有英特尔扩展,或者x86intrin.h如果您需要所有内容,包括_bit_scan_forward_rdtsc,以及所有向量内在函数都包括仅AMD的。如果您反对包含更多实际需要的内容,则可以通过查看表来选择正确的包含。

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

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


1
smmintrin(SSE4.1)是Penryn(45nm Core2),而不是Nehalem(“ i7”)。我们可以停止使用“ i7”作为架构名称吗? 现在,英特尔一直将其用于SnB系列已经变得毫无意义
彼得·科德斯

immintrin.h在GCC 9.1.0上似乎没有包含_popcnt32_popcnt64(不要与popcntintrin.h!混淆)。因此看来x86intrin.h还是有目的的。
Thom Wiggers

12

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

  • gcc:对x86intrin.hfirst的支持出现在中gcc-4.5.0。该gcc-4发行版系列将不再被保持,同时gcc-6.x当前稳定版本系列。gcc-5还介绍了__has_include所有clang-3.x版本中都存在的扩展。gcc-7处于预发行版本(回归测试等),并且遵循当前的版本控制方案,将以发行gcc-7.1.0

  • clangx86intrin.h似乎所有clang-3.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.1LLVM 3.1首先在中出现Apple clang 3.1(数字重合)Xcode 4.3.3

    苹果还定义了__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.1x86intrin.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)作为版本测试。当然,如果您要编写可在所有这些不同的编译器之间移植的代码,则此平台上的标头名称将是最少的问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.