Reactor: Add support for specifying and modifying default configuration settings.
rr::Config holds the full reactor configuration state.
rr::Config::Edit holds edits on a config, which can be applied on top of the current defaults.
Default configurations are updated atomically, preventing modifications to the default state from tearing.
Bug: b/137167988
Change-Id: Ib05f2cfc31ab22fb9a891a267fffe33c18691028
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/33768
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index c2c7ae7..2e4e5ba 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -105,6 +105,20 @@
namespace
{
+ // Default configuration settings. Must be accessed under mutex lock.
+ std::mutex defaultConfigLock;
+ rr::Config &defaultConfig()
+ {
+ // This uses a static in a function to avoid the cost of a global static
+ // initializer. See http://neugierig.org/software/chromium/notes/2011/08/static-initializers.html
+ static rr::Config config = rr::Config::Edit()
+ .set(rr::Optimization::Level::Default)
+ .add(rr::Optimization::Pass::ScalarReplAggregates)
+ .add(rr::Optimization::Pass::InstructionCombining)
+ .apply({});
+ return config;
+ }
+
class LLVMInitializer
{
protected:
@@ -228,7 +242,7 @@
std::unique_ptr<llvm::Module> module,
llvm::Function **funcs,
size_t count,
- rr::OptimizationLevel optLevel) :
+ const rr::Config &config) :
resolver(createLegacyLookupResolver(
session,
[&](const std::string &name) {
@@ -251,7 +265,7 @@
#ifdef ENABLE_RR_DEBUG_INFO
.setOptLevel(llvm::CodeGenOpt::None)
#else
- .setOptLevel(toLLVM(optLevel))
+ .setOptLevel(toLLVM(config.getOptimization().getLevel()))
#endif // ENABLE_RR_DEBUG_INFO
.setMCPU(JITGlobals::get()->mcpu)
.setMArch(JITGlobals::get()->march)
@@ -318,15 +332,15 @@
}
private:
- static ::llvm::CodeGenOpt::Level toLLVM(rr::OptimizationLevel level)
+ static ::llvm::CodeGenOpt::Level toLLVM(rr::Optimization::Level level)
{
switch (level)
{
- case rr::OptimizationLevel::None: return ::llvm::CodeGenOpt::None;
- case rr::OptimizationLevel::Less: return ::llvm::CodeGenOpt::Less;
- case rr::OptimizationLevel::Default: return ::llvm::CodeGenOpt::Default;
- case rr::OptimizationLevel::Aggressive: return ::llvm::CodeGenOpt::Aggressive;
- default: UNREACHABLE("Unknown OptimizationLevel %d", int(level));
+ case rr::Optimization::Level::None: return ::llvm::CodeGenOpt::None;
+ case rr::Optimization::Level::Less: return ::llvm::CodeGenOpt::Less;
+ case rr::Optimization::Level::Default: return ::llvm::CodeGenOpt::Default;
+ case rr::Optimization::Level::Aggressive: return ::llvm::CodeGenOpt::Aggressive;
+ default: UNREACHABLE("Unknown Optimization Level %d", int(level));
}
return ::llvm::CodeGenOpt::Default;
}
@@ -343,15 +357,17 @@
class JITBuilder
{
public:
- JITBuilder():
+ JITBuilder(const rr::Config &config) :
+ config(config),
module(new llvm::Module("", context)),
builder(new llvm::IRBuilder<>(context))
{
module->setDataLayout(JITGlobals::get()->dataLayout);
}
- void optimize()
+ void optimize(const rr::Config &cfg)
{
+
#ifdef ENABLE_RR_DEBUG_INFO
if (debugInfo != nullptr)
{
@@ -362,36 +378,35 @@
std::unique_ptr<llvm::legacy::PassManager> passManager(
new llvm::legacy::PassManager());
- passManager->add(llvm::createSROAPass());
-
- for(int pass = 0; pass < 10 && rr::optimization[pass] != rr::Disabled; pass++)
+ for(auto pass : cfg.getOptimization().getPasses())
{
- switch(rr::optimization[pass])
+ switch(pass)
{
- case rr::Disabled: break;
- case rr::CFGSimplification: passManager->add(llvm::createCFGSimplificationPass()); break;
- case rr::LICM: passManager->add(llvm::createLICMPass()); break;
- case rr::AggressiveDCE: passManager->add(llvm::createAggressiveDCEPass()); break;
- case rr::GVN: passManager->add(llvm::createGVNPass()); break;
- case rr::InstructionCombining: passManager->add(llvm::createInstructionCombiningPass()); break;
- case rr::Reassociate: passManager->add(llvm::createReassociatePass()); break;
- case rr::DeadStoreElimination: passManager->add(llvm::createDeadStoreEliminationPass()); break;
- case rr::SCCP: passManager->add(llvm::createSCCPPass()); break;
- case rr::ScalarReplAggregates: passManager->add(llvm::createSROAPass()); break;
+ case rr::Optimization::Pass::Disabled: break;
+ case rr::Optimization::Pass::CFGSimplification: passManager->add(llvm::createCFGSimplificationPass()); break;
+ case rr::Optimization::Pass::LICM: passManager->add(llvm::createLICMPass()); break;
+ case rr::Optimization::Pass::AggressiveDCE: passManager->add(llvm::createAggressiveDCEPass()); break;
+ case rr::Optimization::Pass::GVN: passManager->add(llvm::createGVNPass()); break;
+ case rr::Optimization::Pass::InstructionCombining: passManager->add(llvm::createInstructionCombiningPass()); break;
+ case rr::Optimization::Pass::Reassociate: passManager->add(llvm::createReassociatePass()); break;
+ case rr::Optimization::Pass::DeadStoreElimination: passManager->add(llvm::createDeadStoreEliminationPass()); break;
+ case rr::Optimization::Pass::SCCP: passManager->add(llvm::createSCCPPass()); break;
+ case rr::Optimization::Pass::ScalarReplAggregates: passManager->add(llvm::createSROAPass()); break;
default:
- UNREACHABLE("optimization[pass]: %d, pass: %d", int(rr::optimization[pass]), int(pass));
+ UNREACHABLE("pass: %d", int(pass));
}
}
passManager->run(*module);
}
- rr::Routine *acquireRoutine(llvm::Function **funcs, size_t count, rr::OptimizationLevel optLevel)
+ rr::Routine *acquireRoutine(llvm::Function **funcs, size_t count, const rr::Config &cfg)
{
ASSERT(module);
- return new JITRoutine(std::move(module), funcs, count, optLevel);
+ return new JITRoutine(std::move(module), funcs, count, cfg);
}
+ const rr::Config config;
llvm::LLVMContext context;
std::unique_ptr<llvm::Module> module;
std::unique_ptr<llvm::IRBuilder<>> builder;
@@ -1002,8 +1017,6 @@
return it->second;
}
- Optimization optimization[10] = {InstructionCombining, Disabled};
-
// The abstract Type* types are implemented as LLVM types, except that
// 64-bit vectors are emulated using 128-bit ones to avoid use of MMX in x86
// and VFP in ARM, and eliminate the overhead of converting them to explicit
@@ -1134,7 +1147,7 @@
::codegenMutex.lock(); // Reactor and LLVM are currently not thread safe
ASSERT(jit == nullptr);
- jit.reset(new JITBuilder());
+ jit.reset(new JITBuilder(Nucleus::getDefaultConfig()));
}
Nucleus::~Nucleus()
@@ -1143,8 +1156,29 @@
::codegenMutex.unlock();
}
- Routine *Nucleus::acquireRoutine(const char *name, OptimizationLevel optimizationLevel)
+ void Nucleus::setDefaultConfig(const Config &cfg)
{
+ std::unique_lock<std::mutex> lock(::defaultConfigLock);
+ ::defaultConfig() = cfg;
+ }
+
+ void Nucleus::adjustDefaultConfig(const Config::Edit &cfgEdit)
+ {
+ std::unique_lock<std::mutex> lock(::defaultConfigLock);
+ auto &config = ::defaultConfig();
+ config = cfgEdit.apply(config);
+ }
+
+ Config Nucleus::getDefaultConfig()
+ {
+ std::unique_lock<std::mutex> lock(::defaultConfigLock);
+ return ::defaultConfig();
+ }
+
+ Routine *Nucleus::acquireRoutine(const char *name, const Config::Edit &cfgEdit /* = Config::Edit::None */)
+ {
+ auto cfg = cfgEdit.apply(jit->config);
+
if(jit->builder->GetInsertBlock()->empty() || !jit->builder->GetInsertBlock()->back().isTerminator())
{
llvm::Type *type = jit->function->getReturnType();
@@ -1181,7 +1215,7 @@
}
#endif // defined(ENABLE_RR_LLVM_IR_VERIFICATION) || !defined(NDEBUG)
- optimize();
+ jit->optimize(cfg);
if(false)
{
@@ -1190,17 +1224,12 @@
jit->module->print(file, 0);
}
- auto routine = jit->acquireRoutine(&jit->function, 1, optimizationLevel);
+ auto routine = jit->acquireRoutine(&jit->function, 1, cfg);
jit.reset();
return routine;
}
- void Nucleus::optimize()
- {
- jit->optimize();
- }
-
Value *Nucleus::allocateStackVariable(Type *type, int arraySize)
{
// Need to allocate it in the entry block for mem2reg to work
@@ -4678,7 +4707,7 @@
jit->builder->SetInsertPoint(resumeBlock);
}
-Routine* Nucleus::acquireCoroutine(const char *name, OptimizationLevel optimizationLevel)
+Routine* Nucleus::acquireCoroutine(const char *name, const Config::Edit &cfgEdit /* = Config::Edit::None */)
{
ASSERT_MSG(jit->coroutine.id != nullptr, "acquireCoroutine() called without a call to createCoroutine()");
@@ -4707,7 +4736,8 @@
pm.add(llvm::createCoroCleanupPass());
pm.run(*jit->module);
- optimize();
+ auto cfg = cfgEdit.apply(jit->config);
+ jit->optimize(cfg);
if(false)
{
@@ -4720,7 +4750,7 @@
funcs[Nucleus::CoroutineEntryBegin] = jit->function;
funcs[Nucleus::CoroutineEntryAwait] = jit->coroutine.await;
funcs[Nucleus::CoroutineEntryDestroy] = jit->coroutine.destroy;
- auto routine = jit->acquireRoutine(funcs, Nucleus::CoroutineEntryCount, optimizationLevel);
+ auto routine = jit->acquireRoutine(funcs, Nucleus::CoroutineEntryCount, cfg);
jit.reset();
return routine;