diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2019-08-13 21:59:26 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2019-10-09 07:31:28 -0700 |
commit | 780137d585344bf9de906a285a50498104c0c66e (patch) | |
tree | 12ba9d636b58091a4e0935fe1b9375297fde5a20 | |
parent | 74858dc4af2c70b1c1540a7eda550620227badac (diff) |
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>
-rw-r--r-- | config.tests/x86_simd/main.cpp | 17 | ||||
-rw-r--r-- | configure.json | 12 | ||||
-rw-r--r-- | mkspecs/common/gcc-base.conf | 1 | ||||
-rw-r--r-- | mkspecs/common/icc-base-unix.conf | 1 | ||||
-rw-r--r-- | mkspecs/common/msvc-version.conf | 1 | ||||
-rw-r--r-- | mkspecs/features/simd.prf | 1 | ||||
-rw-r--r-- | mkspecs/win32-clang-msvc/qmake.conf | 1 | ||||
-rw-r--r-- | src/corelib/tools/qsimd.cpp | 36 |
8 files changed, 69 insertions, 1 deletions
diff --git a/config.tests/x86_simd/main.cpp b/config.tests/x86_simd/main.cpp index 4fac13973a..0e7ebed8d9 100644 --- a/config.tests/x86_simd/main.cpp +++ b/config.tests/x86_simd/main.cpp @@ -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() { diff --git a/configure.json b/configure.json index 8ebb3c841f..ce71e67993 100644 --- a/configure.json +++ b/configure.json @@ -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", diff --git a/mkspecs/common/gcc-base.conf b/mkspecs/common/gcc-base.conf index 4d82321cba..472333d2ea 100644 --- a/mkspecs/common/gcc-base.conf +++ b/mkspecs/common/gcc-base.conf @@ -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 diff --git a/mkspecs/common/icc-base-unix.conf b/mkspecs/common/icc-base-unix.conf index 54eda984b7..e0bb55577e 100644 --- a/mkspecs/common/icc-base-unix.conf +++ b/mkspecs/common/icc-base-unix.conf @@ -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 diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index af33132077..adb45582c7 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -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 diff --git a/mkspecs/features/simd.prf b/mkspecs/features/simd.prf index a0b40fcf11..3918c4fe73 100644 --- a/mkspecs/features/simd.prf +++ b/mkspecs/features/simd.prf @@ -137,6 +137,7 @@ addSimdCompiler(avx512ifma) addSimdCompiler(avx512vbmi) addSimdCompiler(f16c) addSimdCompiler(rdrnd) +addSimdCompiler(rdseed) addSimdCompiler(neon) addSimdCompiler(mips_dsp) addSimdCompiler(mips_dspr2) diff --git a/mkspecs/win32-clang-msvc/qmake.conf b/mkspecs/win32-clang-msvc/qmake.conf index 238e401b84..be7cdaa396 100644 --- a/mkspecs/win32-clang-msvc/qmake.conf +++ b/mkspecs/win32-clang-msvc/qmake.conf @@ -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 diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index fb9b5996f6..6e3b0f9faf 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -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 |