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