英特尔C++编译器和/或 GCC 是否支持以下英特尔内部函数,就像 MSVC 自 2012/2013 年以来所做的那样?
#include <immintrin.h> // for the following intrinsics
int _rdrand16_step(uint16_t*);
int _rdrand32_step(uint32_t*);
int _rdrand64_step(uint64_t*);
int _rdseed16_step(uint16_t*);
int _rdseed32_step(uint32_t*);
int _rdseed64_step(uint64_t*);
如果支持这些内部函数,因为它们支持哪个版本(请使用编译时常量(?
GCC 和 Intel 编译器都支持它们。GCC 支持于 2010 年底推出。他们需要标头<immintrin.h>
.
至少从 4.6 版开始就存在 GCC 支持,但似乎没有任何特定的编译时常量 - 您可以检查__GNUC_MAJOR__ > 4 || (__GNUC_MAJOR__ == 4 && __GNUC_MINOR__ >= 6)
.
所有主要编译器都通过 <immintrin.h>
.
支持英特尔的rdrand
和rdseed
内部函数。rdseed
需要一些编译器的最新版本,例如GCC9(2019(或clang7(2018(,尽管到目前为止它们已经稳定了很长一段时间。 如果您希望使用较旧的编译器,或者不启用 ISA 扩展选项(如 -march=skylake
(,则库1 包装器函数而不是内部函数是一个不错的选择。 (内联 asm 不是必需的,除非你想玩它,否则我不推荐它。
#include <immintrin.h>
#include <stdint.h>
// gcc -march=native or haswell or znver1 or whatever, or manually enable -mrdrnd
uint64_t rdrand64(){
unsigned long long ret; // not uint64_t, GCC/clang wouldn't compile.
do{}while( !_rdrand64_step(&ret) ); // retry until success.
return ret;
}
// and equivalent for _rdseed64_step
// and 32 and 16-bit sizes with unsigned and unsigned short.
某些编译器在编译时启用指令时定义__RDRND__
。 GCC/clang,因为他们完全支持内在的,但只是后来的ICC(19.0(。 对于 ICC,-march=ivybridge
并不意味着在 2021.1.
之前-mrdrnd
或定义__RDRND__
ICX是基于LLVM的,行为类似于clang.
MSVC 不定义任何宏;它对内部函数的处理仅围绕运行时功能检测而设计,这与 GCC/Clang 不同,GCC/Clang 的简单方法是编译时 CPU 功能选项。
为什么do{}while()
而不是while(){}
? 事实证明,ICC编译成一个不那么愚蠢的循环,do{}while()
,而不是无用地剥离第一次迭代。 其他编译器无法从这种手动操作中受益,这不是ICC的正确性问题。
为什么unsigned long long
而不是uint64_t
? 该类型必须与内部函数或 C 所期望的指针类型一致,尤其是编译器会抱怨C++无论对象表示是否相同(64 位无符号(。 例如,在Linux上,uint64_t
是unsigned long
,但GCC/clang的immintrin.h
定义int _rdrand64_step(unsigned long long*)
,与Windows相同。 所以你总是需要unsigned long long ret
GCC/clang。 MSVC 不是问题,因为它只能 (AFAIK( 针对 Windows,其中 unsigned long long
是唯一的 64 位无符号类型><。但是ICC将内在定义为在为GNU/Linux编译时采取unsigned long*
,根据我对 https://godbolt.org/的测试。 因此,要移植到ICC,您实际上需要#ifdef __INTEL_COMPILER
;即使在C++我也不知道如何使用auto
或其他类型推导来声明与其匹配的变量。
支持内部函数的编译器版本
在Godbolt上测试;它的MSVC的最早版本是2015年,ICC 2013,所以我不能再回去了。 对 _rdrand16_step
/32/64 的支持都在任何给定的编译器中同时引入。 64 需要 64 位模式。
中央处理器 | 海湾合作委员会 | 铛 | MSVC | 国际商会 | |
---|---|---|---|---|---|
rdrand | 常春藤桥/挖掘机 | 4.6 | 3.2 | 2015 年之前 (19.10( | 在 13.0.1 之前,但 19.0 用于定义__RDRND__ -mrdrnd 。 2021.1 for -march=ivybridge 启用-mrdrnd |
rdseed | 布罗德韦尔/禅宗1 | 9.1 | 7,0 | 2015 年之前 (19.10( | 之前(?( 13.0.1,但 19.0 还添加了-mrdrnd 和-mrdseed 选项( |
对RDSEED和RDRAND指令的内部支持。
但是,您可以使用 NASM 或 MASM 实现这些指令。程序集代码可在以下位置获得:
https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
对于英特尔编译器,您可以使用标头来确定版本。可以使用以下宏来确定版本和子版本:
__INTEL_COMPILER //Major Version
__INTEL_COMPILER_UPDATE // Minor Update.
例如,如果您使用 ICC15.0 Update 3 编译器,它将显示您有
__INTEL_COMPILER = 1500
__INTEL_COMPILER_UPDATE = 3
有关预定义宏的更多详细信息,您可以转到:https://software.intel.com/en-us/node/524490