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/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index bcc2f7e..178c075 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -55,6 +55,18 @@
 
 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)
+			.apply({});
+		return config;
+	}
+
 	Ice::GlobalContext *context = nullptr;
 	Ice::Cfg *function = nullptr;
 	Ice::CfgNode *basicBlock = nullptr;
@@ -77,6 +89,19 @@
 		#define __x86_64__ 1
 	#endif
 
+	static Ice::OptLevel toIce(rr::Optimization::Level level)
+	{
+		switch (level)
+		{
+			case rr::Optimization::Level::None:       return Ice::Opt_0;
+			case rr::Optimization::Level::Less:       return Ice::Opt_1;
+			case rr::Optimization::Level::Default:    return Ice::Opt_2;
+			case rr::Optimization::Level::Aggressive: return Ice::Opt_2;
+			default: UNREACHABLE("Unknown Optimization Level %d", int(level));
+		}
+		return Ice::Opt_2;
+	}
+
 	class CPUID
 	{
 	public:
@@ -204,8 +229,6 @@
 		return Ice::typeWidthInBytes(T(type));
 	}
 
-	Optimization optimization[10] = {InstructionCombining, Disabled};
-
 	using ElfHeader = std::conditional<sizeof(void*) == 8, Elf64_Ehdr, Elf32_Ehdr>::type;
 	using SectionHeader = std::conditional<sizeof(void*) == 8, Elf64_Shdr, Elf32_Shdr>::type;
 
@@ -548,7 +571,7 @@
 			Flags.setTargetInstructionSet(CPUID::SSE4_1 ? Ice::X86InstructionSet_SSE4_1 : Ice::X86InstructionSet_SSE2);
 		#endif
 		Flags.setOutFileType(Ice::FT_Elf);
-		Flags.setOptLevel(Ice::Opt_2);
+		Flags.setOptLevel(toIce(getDefaultConfig().getOptimization().getLevel()));
 		Flags.setApplicationBinaryInterface(Ice::ABI_Platform);
 		Flags.setVerbose(false ? Ice::IceV_Most : Ice::IceV_None);
 		Flags.setDisableHybridAssembly(true);
@@ -585,7 +608,26 @@
 		::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 */)
 	{
 		if(basicBlock->getInsts().empty() || basicBlock->getInsts().back().getKind() != Ice::Inst::Ret)
 		{
@@ -594,7 +636,7 @@
 
 		::function->setFunctionName(Ice::GlobalString::createWithString(::context, name));
 
-		optimize();
+		rr::optimize(::function);
 
 		::function->translate();
 		ASSERT(!::function->hasError());
@@ -624,11 +666,6 @@
 		return handoffRoutine;
 	}
 
-	void Nucleus::optimize()
-	{
-		rr::optimize(::function);
-	}
-
 	Value *Nucleus::allocateStackVariable(Type *t, int arraySize)
 	{
 		Ice::Type type = T(t);
@@ -3506,7 +3543,7 @@
 	void FlushDebug() {}
 
 	void Nucleus::createCoroutine(Type *YieldType, std::vector<Type*> &Params) { UNIMPLEMENTED("createCoroutine"); }
-	Routine* Nucleus::acquireCoroutine(const char *name, OptimizationLevel optimizationLevel) { UNIMPLEMENTED("acquireCoroutine"); return nullptr; }
+	Routine* Nucleus::acquireCoroutine(const char *name, const Config::Edit &cfgEdit /* = Config::Edit::None */) { UNIMPLEMENTED("acquireCoroutine"); return nullptr; }
 	void Nucleus::yield(Value* val) { UNIMPLEMENTED("Yield"); }
 
 }