RDRAND 和 RDSEED 在各种编译器上的内在函数

RDRAND and RDSEED intrinsics on various compilers?

本文关键字:函数 编译器 RDSEED RDRAND      更新时间:2023-10-16

英特尔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> .
支持英特尔的rdrandrdseed内部函数。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_tunsigned 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.63.22015 年之前 (19.10(在 13.0.1 之前,但 19.0 用于定义__RDRND__ -mrdrnd。 2021.1 for -march=ivybridge 启用-mrdrnd
rdseed 布罗德韦尔/禅宗19.17,02015 年之前 (19.10(之前(?( 13.0.1,但 19.0 还添加了-mrdrnd-mrdseed选项(
Microsoft编译器没有

对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