From 5d42d69d936bc3f29e849aac33d331b198143145 Mon Sep 17 00:00:00 2001 From: "Mikhail R. Gadelha" Date: Wed, 17 Jul 2024 17:01:26 +0200 Subject: [PATCH] [libc] Change rand implementation so all tests pass in both 32- and 64-bit systems (#98692) This patch makes rand select different algorithms depending on the arch. This is needed to avoid a test failure in 32-bit systems where the LSB of rand was not uniform enough when the 64-bit constants are used in 32-bit systems. --- libc/src/stdlib/rand.cpp | 41 +++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/libc/src/stdlib/rand.cpp b/libc/src/stdlib/rand.cpp index 1931727e2d9d19..a8a4fab3377ccc 100644 --- a/libc/src/stdlib/rand.cpp +++ b/libc/src/stdlib/rand.cpp @@ -14,20 +14,39 @@ namespace LIBC_NAMESPACE_DECL { -// An implementation of the xorshift64star pseudo random number generator. This -// is a good general purpose generator for most non-cryptographics applications. LLVM_LIBC_FUNCTION(int, rand, (void)) { unsigned long orig = rand_next.load(cpp::MemoryOrder::RELAXED); - for (;;) { - unsigned long x = orig; - x ^= x >> 12; - x ^= x << 25; - x ^= x >> 27; - if (rand_next.compare_exchange_strong(orig, x, cpp::MemoryOrder::ACQUIRE, - cpp::MemoryOrder::RELAXED)) - return static_cast((x * 0x2545F4914F6CDD1Dul) >> 32) & RAND_MAX; - sleep_briefly(); + + // An implementation of the xorshift64star pseudo random number generator. + // This is a good general purpose generator for most non-cryptographics + // applications. + if constexpr (sizeof(void *) == sizeof(uint64_t)) { + for (;;) { + unsigned long x = orig; + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + if (rand_next.compare_exchange_strong(orig, x, cpp::MemoryOrder::ACQUIRE, + cpp::MemoryOrder::RELAXED)) + return static_cast((x * 0x2545F4914F6CDD1Dul) >> 32) & RAND_MAX; + sleep_briefly(); + } + } else { + // This is the xorshift32 pseudo random number generator, slightly different + // from the 64-bit star version above, as the previous version fails to + // generate uniform enough LSB in 32-bit systems. + for (;;) { + unsigned long x = orig; + x ^= x >> 13; + x ^= x << 27; + x ^= x >> 5; + if (rand_next.compare_exchange_strong(orig, x, cpp::MemoryOrder::ACQUIRE, + cpp::MemoryOrder::RELAXED)) + return static_cast(x * 1597334677ul) & RAND_MAX; + sleep_briefly(); + } } + __builtin_unreachable(); } } // namespace LIBC_NAMESPACE_DECL