QRandom: add support for RDSEED

The Intel whitepaer[1] recommends using the RDSEED over RDRAND whenever
present. libstdc++ from GCC 10 will also use it in std::random_device.

[ChangeLog][QtCore][QRandomGenerator] The system() random generator will
now use the RDSEED instruction on x86 processors whenever available as
the first source of random data. It will fall back to RDRAND and then to
the system functions, in that order.

[1] https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide

Change-Id: I907a43cd9a714da288a2fffd15bab176e54e1975
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2019-08-13 21:59:26 -07:00
parent 74858dc4af
commit 780137d585
8 changed files with 69 additions and 1 deletions

View File

@ -132,6 +132,23 @@ attribute_target("rdrnd") int test_rdrnd()
}
#endif
#if T(RDSEED)
attribute_target("rdseed") int test_rdseed()
{
unsigned short us;
unsigned int ui;
if (_rdseed16_step(&us))
return 1;
if (_rdseed32_step(&ui))
return 1;
# if defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
unsigned long long ull;
if (_rdseed64_step(&ull))
return 1;
# endif
}
#endif
#if T(SHANI)
attribute_target("sha") void test_shani()
{

View File

@ -527,6 +527,10 @@
"label": "RDRAND instruction",
"type": "x86Simd"
},
"rdseed": {
"label": "RDSEED instruction",
"type": "x86Simd"
},
"shani": {
"label": "SHA new instructions",
"type": "x86Simd"
@ -1181,6 +1185,14 @@
{ "type": "define", "name": "QT_COMPILER_SUPPORTS_RDRND", "value": 1 }
]
},
"rdseed": {
"label": "RDSEED",
"condition": "tests.rdseed",
"output": [
"privateConfig",
{ "type": "define", "name": "QT_COMPILER_SUPPORTS_RDSEED", "value": 1 }
]
},
"shani": {
"label": "SHA",
"condition": "features.sse2 && tests.shani",

View File

@ -93,6 +93,7 @@ QMAKE_CFLAGS_SSE4_1 += -msse4.1
QMAKE_CFLAGS_SSE4_2 += -msse4.2
QMAKE_CFLAGS_F16C += -mf16c
QMAKE_CFLAGS_RDRND += -mrdrnd
QMAKE_CFLAGS_RDSEED += -mrdseed
QMAKE_CFLAGS_AVX += -mavx
QMAKE_CFLAGS_AVX2 += -mavx2
QMAKE_CFLAGS_AVX512F += -mavx512f

View File

@ -51,6 +51,7 @@ QMAKE_CFLAGS_AVX512VL += -march=skylake-avx512
QMAKE_CFLAGS_AESNI += -maes
QMAKE_CFLAGS_F16C += $$QMAKE_CFLAGS_AVX2
QMAKE_CFLAGS_RDRND += -mrdrnd
QMAKE_CFLAGS_RDSEED += -mrdseed
QMAKE_CFLAGS_SHANI += -msha
QMAKE_CXX = icpc

View File

@ -50,6 +50,7 @@ greaterThan(QMAKE_MSC_VER, 1799) {
QMAKE_CFLAGS_F16C = -arch:AVX
QMAKE_CFLAGS_RDRND =
QMAKE_CFLAGS_RDSEED =
equals(QMAKE_MSC_VER, 1800) {
QMAKE_CFLAGS_RELEASE += -Zc:strictStrings

View File

@ -137,6 +137,7 @@ addSimdCompiler(avx512ifma)
addSimdCompiler(avx512vbmi)
addSimdCompiler(f16c)
addSimdCompiler(rdrnd)
addSimdCompiler(rdseed)
addSimdCompiler(neon)
addSimdCompiler(mips_dsp)
addSimdCompiler(mips_dspr2)

View File

@ -15,6 +15,7 @@ QMAKE_CFLAGS_AVX = -mavx
QMAKE_CFLAGS_AVX2 = -mavx2
QMAKE_CFLAGS_F16C = -mf16c
QMAKE_CFLAGS_RDRND = -mrdrnd
QMAKE_CFLAGS_RDSEED = -mrdseed
QMAKE_CFLAGS_AVX512F = -mavx512f
QMAKE_CFLAGS_AVX512ER = -mavx512er
QMAKE_CFLAGS_AVX512CD = -mavx512cd

View File

@ -626,8 +626,40 @@ void qDumpCPUFeatures()
# ifdef Q_PROCESSOR_X86_64
# define _rdrandXX_step _rdrand64_step
# define _rdseedXX_step _rdseed64_step
# else
# define _rdrandXX_step _rdrand32_step
# define _rdseedXX_step _rdseed32_step
# endif
# if QT_COMPILER_SUPPORTS_HERE(RDSEED)
static QT_FUNCTION_TARGET(RDSEED) unsigned *qt_random_rdseed(unsigned *ptr, unsigned *end) noexcept
{
// Unlike for the RDRAND code below, the Intel whitepaper describing the
// use of the RDSEED instruction indicates we should not retry in a loop.
// If the independent bit generator used by RDSEED is out of entropy, it
// may take time to replenish.
// https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdseedXX_step(reinterpret_cast<qregisteruint *>(ptr)) == 0)
goto out;
ptr += sizeof(qregisteruint)/sizeof(*ptr);
}
if (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
if (_rdseed32_step(ptr) == 0)
goto out;
++ptr;
}
out:
return ptr;
}
# else
static unsigned *qt_random_rdseed(unsigned *ptr, unsigned *)
{
return ptr;
}
# endif
QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
@ -636,6 +668,9 @@ QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) no
unsigned *end = ptr + count;
int retries = 10;
if (qCpuHasFeature(RDSEED))
ptr = qt_random_rdseed(ptr, end);
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
ptr += sizeof(qregisteruint)/sizeof(*ptr);
@ -657,5 +692,4 @@ out:
}
#endif
QT_END_NAMESPACE