RDRAND 和 RDSEED 在各种编译器上的内在函数
RDRAND and RDSEED intrinsics on various compilers?
英特尔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
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 我需要知道编译器如何在cpp中使用析构函数
- 编译器如何区分std::vector的构造函数
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 填充上编译器生成的复制构造函数之间的不一致
- 编译器找不到'aligned_alloc'函数
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 为什么编译器将其解析为函数指针而不是递归调用?
- 表达式未评估为常数两个级别的constexpr函数(编译器错误?)
- 从 std::streambif 继承时不兼容析构函数编译器警告
- 在构造函数 - 编译器错误中调用的成员变量的驱动器
- 复制初始化和显式构造函数-编译器的差异
- 静态函数编译器优化C++
- 为什么派生类虚函数可以调用基类虚函数?编译器如何实现
- 复制构造函数 - 编译器错误 C2040 和 C2440
- 带有模板返回类型的虚基函数:编译器在使用pointtype作为模板参数的派生类时失败(MSVC 2013)
- C++中虚拟函数编译器的作用