mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-19 09:05:17 +08:00
libstdc++: Add support for POWER9 DARN instruction to std::random_device
The ISA-3.0 instruction set includes DARN ("deliver a random number") which can be used similarly to the existing support for RDRAND and RDSEED. libstdc++-v3/ChangeLog: * src/c++11/random.cc [__powerpc__] (USE_DARN): Define. (__ppc_darn): New function to use POWER9 DARN instruction. (Which): Add 'darn' enumerator. (which_source): Check for __ppc_darn. (random_device::_M_init): Support "darn" and "hw" tokens. (random_device::_M_getentropy): Add darn to switch. * testsuite/26_numerics/random/random_device/cons/token.cc: Check "darn" token. * testsuite/26_numerics/random/random_device/entropy.cc: Likewise.
This commit is contained in:
parent
bdb9d47218
commit
5997e6a6ec
@ -37,6 +37,8 @@
|
|||||||
# ifdef _GLIBCXX_X86_RDSEED
|
# ifdef _GLIBCXX_X86_RDSEED
|
||||||
# define USE_RDSEED 1
|
# define USE_RDSEED 1
|
||||||
# endif
|
# endif
|
||||||
|
#elif defined __powerpc__ && defined __BUILTIN_CPU_SUPPORTS__
|
||||||
|
# define USE_DARN 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
@ -69,7 +71,7 @@
|
|||||||
#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
|
#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
|
||||||
// The OS provides a source of randomness we can use.
|
// The OS provides a source of randomness we can use.
|
||||||
# pragma GCC poison _M_mt
|
# pragma GCC poison _M_mt
|
||||||
#elif defined USE_RDRAND || defined USE_RDSEED
|
#elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
|
||||||
// Hardware instructions might be available, but use cpuid checks at runtime.
|
// Hardware instructions might be available, but use cpuid checks at runtime.
|
||||||
# pragma GCC poison _M_mt
|
# pragma GCC poison _M_mt
|
||||||
// If the runtime cpuid checks fail we'll use a linear congruential engine.
|
// If the runtime cpuid checks fail we'll use a linear congruential engine.
|
||||||
@ -135,6 +137,24 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_DARN
|
||||||
|
unsigned int
|
||||||
|
__attribute__((target("cpu=power9")))
|
||||||
|
__ppc_darn(void*)
|
||||||
|
{
|
||||||
|
const uint64_t failed = -1;
|
||||||
|
unsigned int retries = 10;
|
||||||
|
uint64_t val = __builtin_darn();
|
||||||
|
while (val == failed) [[__unlikely__]]
|
||||||
|
{
|
||||||
|
if (--retries == 0)
|
||||||
|
std::__throw_runtime_error(__N("random_device: darn failed"));
|
||||||
|
val = __builtin_darn();
|
||||||
|
}
|
||||||
|
return (uint32_t)val;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _GLIBCXX_USE_CRT_RAND_S
|
#ifdef _GLIBCXX_USE_CRT_RAND_S
|
||||||
unsigned int
|
unsigned int
|
||||||
__winxp_rand_s(void*)
|
__winxp_rand_s(void*)
|
||||||
@ -193,11 +213,16 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum Which {
|
enum Which : unsigned {
|
||||||
rand_s = 1, rdseed = 2, rdrand = 4, device_file = 8, prng = 16,
|
device_file = 1, prng = 2, rand_s = 4,
|
||||||
|
rdseed = 64, rdrand = 128, darn = 256,
|
||||||
any = 0xffff
|
any = 0xffff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr Which
|
||||||
|
operator|(Which l, Which r) noexcept
|
||||||
|
{ return Which(unsigned(l) | unsigned(r)); }
|
||||||
|
|
||||||
inline Which
|
inline Which
|
||||||
which_source(random_device::result_type (*func [[maybe_unused]])(void*),
|
which_source(random_device::result_type (*func [[maybe_unused]])(void*),
|
||||||
void* file [[maybe_unused]])
|
void* file [[maybe_unused]])
|
||||||
@ -221,6 +246,11 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
return rdrand;
|
return rdrand;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_DARN
|
||||||
|
if (func == &__ppc_darn)
|
||||||
|
return darn;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _GLIBCXX_USE_DEV_RANDOM
|
#ifdef _GLIBCXX_USE_DEV_RANDOM
|
||||||
if (file != nullptr)
|
if (file != nullptr)
|
||||||
return device_file;
|
return device_file;
|
||||||
@ -269,6 +299,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
else if (token == "rdrand" || token == "rdrnd")
|
else if (token == "rdrand" || token == "rdrnd")
|
||||||
which = rdrand;
|
which = rdrand;
|
||||||
#endif // USE_RDRAND
|
#endif // USE_RDRAND
|
||||||
|
#ifdef USE_DARN
|
||||||
|
else if (token == "darn")
|
||||||
|
which = darn;
|
||||||
|
#endif
|
||||||
|
#if defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
|
||||||
|
else if (token == "hw" || token == "hardware")
|
||||||
|
which = rdrand | rdseed | darn;
|
||||||
|
#endif
|
||||||
#ifdef _GLIBCXX_USE_CRT_RAND_S
|
#ifdef _GLIBCXX_USE_CRT_RAND_S
|
||||||
else if (token == "rand_s")
|
else if (token == "rand_s")
|
||||||
which = rand_s;
|
which = rand_s;
|
||||||
@ -346,6 +384,17 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
}
|
}
|
||||||
#endif // USE_RDRAND
|
#endif // USE_RDRAND
|
||||||
|
|
||||||
|
#ifdef USE_DARN
|
||||||
|
if (which & darn)
|
||||||
|
{
|
||||||
|
if (__builtin_cpu_supports("darn"))
|
||||||
|
{
|
||||||
|
_M_func = &__ppc_darn;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_DARN
|
||||||
|
|
||||||
#ifdef _GLIBCXX_USE_DEV_RANDOM
|
#ifdef _GLIBCXX_USE_DEV_RANDOM
|
||||||
if (which & device_file)
|
if (which & device_file)
|
||||||
{
|
{
|
||||||
@ -497,6 +546,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
{
|
{
|
||||||
case rdrand:
|
case rdrand:
|
||||||
case rdseed:
|
case rdseed:
|
||||||
|
case darn:
|
||||||
return (double) max;
|
return (double) max;
|
||||||
case rand_s:
|
case rand_s:
|
||||||
case prng:
|
case prng:
|
||||||
|
@ -51,8 +51,9 @@ test03()
|
|||||||
{
|
{
|
||||||
// At least one of these tokens should be valid.
|
// At least one of these tokens should be valid.
|
||||||
const std::string tokens[] = {
|
const std::string tokens[] = {
|
||||||
"rdseed", "rdrand", "rand_s", "/dev/urandom", "/dev/random", "mt19937",
|
"rdseed", "rdrand", "darn",
|
||||||
"prng"
|
"rand_s", "/dev/urandom", "/dev/random",
|
||||||
|
"mt19937", "prng"
|
||||||
};
|
};
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (const std::string& token : tokens)
|
for (const std::string& token : tokens)
|
||||||
|
@ -22,7 +22,7 @@ test01()
|
|||||||
VERIFY( entropy <= max );
|
VERIFY( entropy <= max );
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto token : { "rdrand", "rdseed" })
|
for (auto token : { "rdrand", "rdseed", "darn", "hw" })
|
||||||
if (__gnu_test::random_device_available(token))
|
if (__gnu_test::random_device_available(token))
|
||||||
{
|
{
|
||||||
const double entropy = std::random_device(token).entropy();
|
const double entropy = std::random_device(token).entropy();
|
||||||
|
Loading…
Reference in New Issue
Block a user