Index: include/llvm/Support/RandomNumberGenerator.h =================================================================== --- /dev/null +++ include/llvm/Support/RandomNumberGenerator.h @@ -0,0 +1,54 @@ +//==- llvm/Support/RandomNumberGenerator.h - RNG for diversity ---*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an abstraction for random number generation (RNG). +// Note that the current implementation is not cryptographically secure +// as it uses the C++11 facilities. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_ +#define LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_ + +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace llvm { + +class RandomNumberGenerator { +public: + /// \brief Add additional personalization data to the RNG seed. + /// + /// This function should be used to add deterministic command line + /// argument data to the RNG initialization, resulting in a + /// different stream of random numbers for each invocation during a + /// build. The input to this function should be unique per + /// compilation unit. + static void SetSalt(const StringRef &Salt); + + static RandomNumberGenerator *Get(); + + /// \brief Returns a random number in the range [0, Max). + uint64_t Random(uint64_t Max); + +private: + std::default_random_engine generator; + + void Seed(StringRef Salt, uint64_t Seed); + + RandomNumberGenerator(); + // Noncopyable. + RandomNumberGenerator(const RandomNumberGenerator &other) = delete; + RandomNumberGenerator & + operator=(const RandomNumberGenerator &other) = delete; +}; +} + +#endif Index: lib/Support/CMakeLists.txt =================================================================== --- lib/Support/CMakeLists.txt +++ lib/Support/CMakeLists.txt @@ -40,6 +40,7 @@ MD5.cpp PluginLoader.cpp PrettyStackTrace.cpp + RandomNumberGenerator.cpp Regex.cpp SmallPtrSet.cpp SmallVector.cpp Index: lib/Support/RandomNumberGenerator.cpp =================================================================== --- /dev/null +++ lib/Support/RandomNumberGenerator.cpp @@ -0,0 +1,86 @@ +//===-- RandomNumberGenerator.cpp - Implement RNG class -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements random number generation (RNG). +// The current implementation is NOT cryptographically secure as it uses +// the C++11 facilities. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "rng" +#include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/ThreadLocal.h" + +using namespace llvm; + +// Initialized once, then only read by threads, so no locking required. +static std::string SaltData; + +// Do not change to cl::opt since this silently breaks argument parsing. +static cl::opt +RandomSeed("rng-seed", cl::value_desc("seed"), + cl::desc("Seed for the random number generator"), cl::init(0)); + +static cl::opt +SaltDataOpt("salt-data", + cl::desc("Salt data for the RNG (testing only, should be set " + "by command line options"), + cl::Hidden, cl::location(SaltData)); + +static ManagedStatic > Instance; + +void RandomNumberGenerator::SetSalt(const StringRef &Salt) { + SaltData = Salt; +} + +RandomNumberGenerator *RandomNumberGenerator::Get() { + RandomNumberGenerator *RNG = + const_cast(Instance->get()); + + if (RNG == nullptr) { + RNG = new RandomNumberGenerator; + Instance->set(RNG); + } + + return RNG; +} + +// Note that every new RNG will produce the same stream of +// pseudo-random numbers, unless SetSalt is called again. +RandomNumberGenerator::RandomNumberGenerator() { + if (RandomSeed == 0 && SaltData.empty()) + DEBUG(errs() + << "Warning! Using unseeded and unsalted random number generator\n"); + + Seed(SaltData, RandomSeed); +} + +uint64_t RandomNumberGenerator::Random(uint64_t Max) { + std::uniform_int_distribution distribution(0, Max - 1); + return distribution(generator); +} + +void RandomNumberGenerator::Seed(StringRef Salt, uint64_t Seed) { + DEBUG(dbgs() << "Re-Seeding RNG from salt and seed\n"); + DEBUG(dbgs() << "Salt: " << Salt << "\n"); + DEBUG(dbgs() << "Seed: " << Seed << "\n"); + + // Sequence: Seed-low, Seed-high, Salt... + size_t SeedSize = Salt.size() + 2; + uint32_t Seeds[SeedSize]; + Seeds[0] = Seed; + Seeds[1] = Seed >> 32; + std::copy_n(Salt.begin(), Salt.size(), Seeds + 2); + + std::seed_seq SeedSeq(Seeds, Seeds + SeedSize); + generator.seed(SeedSeq); +}