[PATCH 1/1] libstdc++: Add Hygon x86 RNG instructions support to std::random_device
Jonathan Wakely
jwakely@redhat.com
Tue Jun 30 13:31:06 GMT 2026
On Tue, 30 Jun 2026 at 11:28, <chencyy@hygon.cn> wrote:
>
> From: Yi Chen <chencyy@hygon.cn>
>
> 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.
Thanks, I'll get this pushed to trunk.
>
> * 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 <chencyy@hygon.cn>
> ---
> 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
>
>
More information about the Libstdc++
mailing list