Refactor LLVM initialization code

Change-Id: Ie944a14c1d4ae30d7e30f84408c598c9e021ea66
Reviewed-on: https://swiftshader-review.googlesource.com/20471
Tested-by: Logan Chien <loganchien@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index b83fd97..801aef3 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -64,10 +64,14 @@
 	extern bool JITEmitDebugInfo;
 }
 
+namespace sw
+{
+	class LLVMReactorJIT;
+}
+
 namespace
 {
-	sw::LLVMRoutineManager *routineManager = nullptr;
-	llvm::ExecutionEngine *executionEngine = nullptr;
+	sw::LLVMReactorJIT *reactorJIT = nullptr;
 	llvm::IRBuilder<> *builder = nullptr;
 	llvm::LLVMContext *context = nullptr;
 	llvm::Module *module = nullptr;
@@ -78,6 +82,93 @@
 
 namespace sw
 {
+	class LLVMReactorJIT
+	{
+	private:
+		std::string arch;
+		llvm::SmallVector<std::string, 16> mattrs;
+		sw::LLVMRoutineManager *routineManager;
+		llvm::ExecutionEngine *executionEngine;
+
+	public:
+		LLVMReactorJIT(const std::string &arch_,
+					   const llvm::SmallVectorImpl<std::string> &mattrs_) :
+			arch(arch_),
+			mattrs(mattrs_.begin(), mattrs_.end()),
+			routineManager(nullptr),
+			executionEngine(nullptr)
+		{
+		}
+
+		void startSession()
+		{
+			std::string error;
+
+			::module = new llvm::Module("", *::context);
+
+			routineManager = new LLVMRoutineManager();
+
+			llvm::TargetMachine *targetMachine =
+				llvm::EngineBuilder::selectTarget(
+					::module, arch, "", mattrs, llvm::Reloc::Default,
+					llvm::CodeModel::JITDefault, &error);
+
+			executionEngine = llvm::JIT::createJIT(
+				::module, &error, routineManager, llvm::CodeGenOpt::Aggressive,
+				true, targetMachine);
+		}
+
+		void endSession()
+		{
+			delete executionEngine;
+			executionEngine = nullptr;
+			routineManager = nullptr;
+
+			::function = nullptr;
+			::module = nullptr;
+		}
+
+		LLVMRoutine *acquireRoutine(llvm::Function *func)
+		{
+			void *entry = executionEngine->getPointerToFunction(::function);
+			return routineManager->acquireRoutine(entry);
+		}
+
+		void optimize(llvm::Module *module)
+		{
+			static llvm::PassManager *passManager = nullptr;
+
+			if(!passManager)
+			{
+				passManager = new llvm::PassManager();
+
+				passManager->add(new llvm::TargetData(*executionEngine->getTargetData()));
+				passManager->add(llvm::createScalarReplAggregatesPass());
+
+				for(int pass = 0; pass < 10 && optimization[pass] != Disabled; pass++)
+				{
+					switch(optimization[pass])
+					{
+					case Disabled:                                                                       break;
+					case CFGSimplification:    passManager->add(llvm::createCFGSimplificationPass());    break;
+					case LICM:                 passManager->add(llvm::createLICMPass());                 break;
+					case AggressiveDCE:        passManager->add(llvm::createAggressiveDCEPass());        break;
+					case GVN:                  passManager->add(llvm::createGVNPass());                  break;
+					case InstructionCombining: passManager->add(llvm::createInstructionCombiningPass()); break;
+					case Reassociate:          passManager->add(llvm::createReassociatePass());          break;
+					case DeadStoreElimination: passManager->add(llvm::createDeadStoreEliminationPass()); break;
+					case SCCP:                 passManager->add(llvm::createSCCPPass());                 break;
+					case ScalarReplAggregates: passManager->add(llvm::createScalarReplAggregatesPass()); break;
+					default:
+						assert(false);
+					}
+				}
+			}
+
+			passManager->run(*::module);
+		}
+	};
+
 	Optimization optimization[10] = {InstructionCombining, Disabled};
 
 	enum EmulatedType
@@ -192,34 +283,38 @@
 		::codegenMutex.lock();   // Reactor and LLVM are currently not thread safe
 
 		llvm::InitializeNativeTarget();
-		llvm::JITEmitDebugInfo = false;
 
 		if(!::context)
 		{
 			::context = new llvm::LLVMContext();
 		}
 
-		::module = new llvm::Module("", *::context);
-		::routineManager = new LLVMRoutineManager();
-
 		#if defined(__x86_64__)
-			const char *architecture = "x86-64";
+			static const char arch[] = "x86-64";
 		#else
-			const char *architecture = "x86";
+			static const char arch[] = "x86";
 		#endif
 
-		llvm::SmallVector<std::string, 1> MAttrs;
-		MAttrs.push_back(CPUID::supportsMMX()    ? "+mmx"   : "-mmx");
-		MAttrs.push_back(CPUID::supportsCMOV()   ? "+cmov"  : "-cmov");
-		MAttrs.push_back(CPUID::supportsSSE()    ? "+sse"   : "-sse");
-		MAttrs.push_back(CPUID::supportsSSE2()   ? "+sse2"  : "-sse2");
-		MAttrs.push_back(CPUID::supportsSSE3()   ? "+sse3"  : "-sse3");
-		MAttrs.push_back(CPUID::supportsSSSE3()  ? "+ssse3" : "-ssse3");
-		MAttrs.push_back(CPUID::supportsSSE4_1() ? "+sse41" : "-sse41");
+		llvm::SmallVector<std::string, 1> mattrs;
+		mattrs.push_back(CPUID::supportsMMX()    ? "+mmx"   : "-mmx");
+		mattrs.push_back(CPUID::supportsCMOV()   ? "+cmov"  : "-cmov");
+		mattrs.push_back(CPUID::supportsSSE()    ? "+sse"   : "-sse");
+		mattrs.push_back(CPUID::supportsSSE2()   ? "+sse2"  : "-sse2");
+		mattrs.push_back(CPUID::supportsSSE3()   ? "+sse3"  : "-sse3");
+		mattrs.push_back(CPUID::supportsSSSE3()  ? "+ssse3" : "-ssse3");
+		mattrs.push_back(CPUID::supportsSSE4_1() ? "+sse41" : "-sse41");
 
-		std::string error;
-		llvm::TargetMachine *targetMachine = llvm::EngineBuilder::selectTarget(::module, architecture, "", MAttrs, llvm::Reloc::Default, llvm::CodeModel::JITDefault, &error);
-		::executionEngine = llvm::JIT::createJIT(::module, 0, ::routineManager, llvm::CodeGenOpt::Aggressive, true, targetMachine);
+		llvm::JITEmitDebugInfo = false;
+		llvm::UnsafeFPMath = true;
+		// llvm::NoInfsFPMath = true;
+		// llvm::NoNaNsFPMath = true;
+
+		if(!::reactorJIT)
+		{
+			::reactorJIT = new LLVMReactorJIT(arch, mattrs);
+		}
+
+		::reactorJIT->startSession();
 
 		if(!::builder)
 		{
@@ -241,12 +336,7 @@
 
 	Nucleus::~Nucleus()
 	{
-		delete ::executionEngine;
-		::executionEngine = nullptr;
-
-		::routineManager = nullptr;
-		::function = nullptr;
-		::module = nullptr;
+		::reactorJIT->endSession();
 
 		::codegenMutex.unlock();
 	}
@@ -286,8 +376,7 @@
 			::module->print(file, 0);
 		}
 
-		void *entry = ::executionEngine->getPointerToFunction(::function);
-		LLVMRoutine *routine = ::routineManager->acquireRoutine(entry);
+		LLVMRoutine *routine = ::reactorJIT->acquireRoutine(::function);
 
 		if(CodeAnalystLogJITCode)
 		{
@@ -299,40 +388,7 @@
 
 	void Nucleus::optimize()
 	{
-		static llvm::PassManager *passManager = nullptr;
-
-		if(!passManager)
-		{
-			passManager = new llvm::PassManager();
-
-			llvm::UnsafeFPMath = true;
-		//	llvm::NoInfsFPMath = true;
-		//	llvm::NoNaNsFPMath = true;
-
-			passManager->add(new llvm::TargetData(*::executionEngine->getTargetData()));
-			passManager->add(llvm::createScalarReplAggregatesPass());
-
-			for(int pass = 0; pass < 10 && optimization[pass] != Disabled; pass++)
-			{
-				switch(optimization[pass])
-				{
-				case Disabled:                                                                       break;
-				case CFGSimplification:    passManager->add(llvm::createCFGSimplificationPass());    break;
-				case LICM:                 passManager->add(llvm::createLICMPass());                 break;
-				case AggressiveDCE:        passManager->add(llvm::createAggressiveDCEPass());        break;
-				case GVN:                  passManager->add(llvm::createGVNPass());                  break;
-				case InstructionCombining: passManager->add(llvm::createInstructionCombiningPass()); break;
-				case Reassociate:          passManager->add(llvm::createReassociatePass());          break;
-				case DeadStoreElimination: passManager->add(llvm::createDeadStoreEliminationPass()); break;
-				case SCCP:                 passManager->add(llvm::createSCCPPass());                 break;
-				case ScalarReplAggregates: passManager->add(llvm::createScalarReplAggregatesPass()); break;
-				default:
-					assert(false);
-				}
-			}
-		}
-
-		passManager->run(*::module);
+		::reactorJIT->optimize(::module);
 	}
 
 	Value *Nucleus::allocateStackVariable(Type *type, int arraySize)