包括正确的内在 header

Including the correct intrinsic header

我一直在阅读关于哪个 header 文件更适合访问英特尔内在函数的意见:x86intrin.himmintrin.h

两者似乎都实现了相同的结果,但我敢肯定,在代码可移植性方面肯定存在一些细微差别。也许一个比另一个更常见或更完整?

我找不到任何关于它们的解释。如果有人知道为什么有 2 个文件,以及它们有什么区别,这将是一个受欢迎的 SO 答案。

说到可移植性,对于较老的编译器(如gcc < v4.4.0),当然会变得更复杂,而且两者都不可用。必须考虑包括 另一个 内在 header(可能 emmintrin.h 以获得 SSE 支持)。

(在此处发布答案是因为 Header files for x86 SIMD intrinsics 的答案已过时,建议包括个别 header 文件)。


immintrin.h 可移植到所有编译器,包括所有 Intel SIMD 内在函数,以及一些标量扩展,如 BMI2 _pdep_u32。 (对于 AMD SSE4a 和 XOP(仅 Bulldozer-family,为 Zen 而放弃),您还需要包含一个不同的 header。)

我能想到的包含 <emmintrin.h> 的唯一原因是,如果您正在使用 MSVC 并且想要为您不想依赖的 ISA 扩展保留未定义的内在函数。

GCC 的模型要求您在使用内部函数之前启用扩展,这意味着编译器会为您进行此检查,因此您可以 #include <immintrin.h> 但如果您尝试使用 _mm_shuffle_epi8 (pshufb) 没有 -mssse3.

不要使用早于 gcc4.4 的编译器。它们已经过时并且通常会生成较慢的代码,尤其是对于在调整设置时不存在的现代 CPU正在决定中。


gcc/clang 的 x86intrin.h 与 MSVC intrin.h 仅在您需要一些额外的 non-SIMD 内在函数时才有用,例如 MSVC 的 _BitScanReverse() 而不是始终可以跨编译器移植。像 integer rotate / bit-scan intrinsics 之类的东西是基线(不像 BMI1 lzcnt/tzcnt 或 BMI2 rorx)但很难或不可能以编译器将要表达的方式在 C 中表达识别循环并将其转换回单个指令。

Intel 在 their intrinsics guide 中记录了其中一些在 immintrin.h 中可用,但 gcc/clang 和 MSVC 实际上在 x86intrin.hintrin.h 中有它们headers,分别。

参见Get CPU cycle count?示例使用#ifdef _MSC_VER选择正确的header来定义uint64_t __rdtsc(void)__rdtscp().