From: Yi Chen <[email protected]>

Adapt std::random_device to use the Hygon x86 hardware RNG instructions
RDRAND and RDSEED, bringing Hygon C86 platforms to parity with Intel and AMD.
Prior to this change Hygon was absent from the CPUID vendor allowlists that
gate RDRAND/RDSEED in random_device::_M_init, so std::random_device fell
through to a software RNG.

Hygon C86 CPUs report the HygonGenuine vendor signature (CPUID leaf 0
ebx 0x6f677948) and support both RDRAND and RDSEED.  Add signature_HYGON_ebx
to the RDSEED and RDRAND vendor allowlists in random_device::_M_init, matching
the existing ebx-only Intel/AMD pattern.  With this, the explicit "rdseed" and
"rdrand" token paths select sources on Hygon in exactly the same order as on
Intel/AMD.

For the default device (the "default" token, which == any) Hygon prefers RDRAND,
the higher-throughput instruction, suited to bulk generation; RDSEED provides
higher-entropy seed material at lower throughput and remains fully accessible
via the explicit "rdseed" token and the "hw"/"hardware" tokens.  Choosing RDRAND
for the Hygon default therefore favors throughput for the common case while
preserving RDSEED access for security-sensitive callers, and the entropy()
guarantee is unchanged (32 bits per call for both paths).  The default policy is
handled by a dedicated check at the top of _M_init, kept separate from the
explicit-token paths so their selection order stays identical to Intel/AMD.
The existing RDSEED-first default policy is retained for Intel and AMD; their
behavior is entirely unchanged.

Tested on Hygon C86 7185: random_device("default"), ("rdrand") and ("rdseed")
all succeed; entropy() returns 32 for each; the existing 94087.cc test, which
exercises the default-token path, passes on Hygon.

        * src/c++11/random.cc (random_device::_M_init): Add signature_HYGON_ebx 
to
        the RDSEED and RDRAND CPUID vendor allowlists.  For the default device 
on
        Hygon, prefer RDRAND via a dedicated check at the top of the function.

Signed-off-by: Yi Chen <[email protected]>
---
 libstdc++-v3/src/c++11/random.cc | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/src/c++11/random.cc b/libstdc++-v3/src/c++11/random.cc
index 2f37fd5b88e..d616852b44d 100644
--- a/libstdc++-v3/src/c++11/random.cc
+++ b/libstdc++-v3/src/c++11/random.cc
@@ -390,14 +390,35 @@ namespace std _GLIBCXX_VISIBILITY(default)
     }
 #endif // _GLIBCXX_USE_CRT_RAND_S
 
+#ifdef USE_RDRAND
+    // For the default device on Hygon prefer RDRAND (faster than RDSEED for
+    // bulk generation); an explicit "rdseed" token still selects rdseed below.
+    if (which == any)
+    {
+      unsigned int eax, ebx, ecx, edx;
+      if (__get_cpuid_max(0, &ebx) > 0 && ebx == signature_HYGON_ebx)
+       {
+         // CPUID.01H:ECX.RDRAND[bit 30]
+         __cpuid(1, eax, ebx, ecx, edx);
+         if (ecx & bit_RDRND)
+           {
+             _M_func = &__x86_rdrand;
+             return;
+           }
+       }
+    }
+#endif // USE_RDRAND
+
 #ifdef USE_RDSEED
     if (which & rdseed)
     {
       unsigned int eax, ebx, ecx, edx;
       // Check availability of cpuid and, for now at least, also the
-      // CPU signature for Intel and AMD.
+      // CPU signature for Intel, AMD and Hygon.
       if (__get_cpuid_max(0, &ebx) > 0
-         && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx))
+         && (ebx == signature_INTEL_ebx
+             || ebx == signature_AMD_ebx
+             || ebx == signature_HYGON_ebx))
        {
          // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
          __cpuid_count(7, 0, eax, ebx, ecx, edx);
@@ -425,9 +446,11 @@ namespace std _GLIBCXX_VISIBILITY(default)
     {
       unsigned int eax, ebx, ecx, edx;
       // Check availability of cpuid and, for now at least, also the
-      // CPU signature for Intel and AMD.
+      // CPU signature for Intel, AMD and Hygon.
       if (__get_cpuid_max(0, &ebx) > 0
-         && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx))
+         && (ebx == signature_INTEL_ebx
+             || ebx == signature_AMD_ebx
+             || ebx == signature_HYGON_ebx))
        {
          // CPUID.01H:ECX.RDRAND[bit 30]
          __cpuid(1, eax, ebx, ecx, edx);
-- 
2.34.1


Reply via email to