Eliminate duplicate LLVM contexts

The LLVMContext object is used for caching LLVM types, eliminating
duplicate constants, and things like handling diagnostics information.
Previously we created one for the JITBuilder as well as the JITRoutine.
While having multiple ones is mostly benign from a correctness point of
view, it adds unnecessary overhead.

This change reuses the context created for the JITBuilder object (which
is used during IR construction), for the JITRoutine (which uses it for
actual compilation).

Bug: b/177024837
Change-Id: Iefbbd7fbeb53e67ab41914fad471dd94d9755311
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/51568
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Reactor/LLVMJIT.cpp b/src/Reactor/LLVMJIT.cpp
index ff373b2..c7b5f30 100644
--- a/src/Reactor/LLVMJIT.cpp
+++ b/src/Reactor/LLVMJIT.cpp
@@ -627,13 +627,13 @@
 	llvm::orc::RTDyldObjectLinkingLayer objectLayer;
 	llvm::orc::IRCompileLayer compileLayer;
 	llvm::orc::MangleAndInterner mangle;
-	llvm::orc::ThreadSafeContext ctx;
 	llvm::orc::JITDylib &dylib;
 	std::vector<const void *> addresses;
 
 public:
 	JITRoutine(
 	    std::unique_ptr<llvm::Module> module,
+	    std::unique_ptr<llvm::LLVMContext> context,
 	    const char *name,
 	    llvm::Function **funcs,
 	    size_t count,
@@ -645,11 +645,9 @@
 	    })
 	    , compileLayer(session, objectLayer, std::make_unique<llvm::orc::ConcurrentIRCompiler>(JITGlobals::get()->getTargetMachineBuilder(config.getOptimization().getLevel())))
 	    , mangle(session, JITGlobals::get()->getDataLayout())
-	    , ctx(std::make_unique<llvm::LLVMContext>())
 	    , dylib(Unwrap(session.createJITDylib("<routine>")))
 	    , addresses(count)
 	{
-
 #ifdef ENABLE_RR_DEBUG_INFO
 		// TODO(b/165000222): Update this on next LLVM roll.
 		// https://github.com/llvm/llvm-project/commit/98f2bb4461072347dcca7d2b1b9571b3a6525801
@@ -698,7 +696,7 @@
 		// after this point.
 		funcs = nullptr;
 
-		llvm::cantFail(compileLayer.add(dylib, llvm::orc::ThreadSafeModule(std::move(module), ctx)));
+		llvm::cantFail(compileLayer.add(dylib, llvm::orc::ThreadSafeModule(std::move(module), std::move(context))));
 
 		// Resolve the function addresses.
 		for(size_t i = 0; i < count; i++)
@@ -736,8 +734,9 @@
 
 JITBuilder::JITBuilder(const rr::Config &config)
     : config(config)
-    , module(new llvm::Module("", context))
-    , builder(new llvm::IRBuilder<>(context))
+    , context(new llvm::LLVMContext())
+    , module(new llvm::Module("", *context))
+    , builder(new llvm::IRBuilder<>(*context))
 {
 	module->setTargetTriple(LLVM_DEFAULT_TARGET_TRIPLE);
 	module->setDataLayout(JITGlobals::get()->getDataLayout());
@@ -787,7 +786,7 @@
 std::shared_ptr<rr::Routine> JITBuilder::acquireRoutine(const char *name, llvm::Function **funcs, size_t count, const rr::Config &cfg)
 {
 	ASSERT(module);
-	return std::make_shared<JITRoutine>(std::move(module), name, funcs, count, cfg);
+	return std::make_shared<JITRoutine>(std::move(module), std::move(context), name, funcs, count, cfg);
 }
 
 }  // namespace rr
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 2cfd9cd..2fb46c1 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -642,7 +642,7 @@
 
 BasicBlock *Nucleus::createBasicBlock()
 {
-	return B(llvm::BasicBlock::Create(jit->context, "", jit->function));
+	return B(llvm::BasicBlock::Create(*jit->context, "", jit->function));
 }
 
 BasicBlock *Nucleus::getInsertBlock()
@@ -664,10 +664,10 @@
 	jit->function = rr::createFunction("", T(ReturnType), T(Params));
 
 #ifdef ENABLE_RR_DEBUG_INFO
-	jit->debugInfo = std::make_unique<DebugInfo>(jit->builder.get(), &jit->context, jit->module.get(), jit->function);
+	jit->debugInfo = std::make_unique<DebugInfo>(jit->builder.get(), jit->context.get(), jit->module.get(), jit->function);
 #endif  // ENABLE_RR_DEBUG_INFO
 
-	jit->builder->SetInsertPoint(llvm::BasicBlock::Create(jit->context, "", jit->function));
+	jit->builder->SetInsertPoint(llvm::BasicBlock::Create(*jit->context, "", jit->function));
 }
 
 Value *Nucleus::getArgument(unsigned int index)
@@ -906,7 +906,7 @@
 				// above, but certain backends cannot deal with this.
 				// Load as an integer and bitcast. See b/136037244.
 				auto size = jit->module->getDataLayout().getTypeStoreSize(elTy);
-				auto elAsIntTy = llvm::IntegerType::get(jit->context, size * 8);
+				auto elAsIntTy = llvm::IntegerType::get(*jit->context, size * 8);
 				auto ptrCast = jit->builder->CreatePointerCast(V(ptr), elAsIntTy->getPointerTo());
 				auto load = jit->builder->CreateAlignedLoad(ptrCast, alignment, isVolatile);
 				load->setAtomic(atomicOrdering(atomic, memoryOrder));
@@ -917,11 +917,11 @@
 			{
 				// More exotic types require falling back to the extern:
 				// void __atomic_load(size_t size, void *ptr, void *ret, int ordering)
-				auto sizetTy = llvm::IntegerType::get(jit->context, sizeof(size_t) * 8);
-				auto intTy = llvm::IntegerType::get(jit->context, sizeof(int) * 8);
-				auto i8Ty = llvm::Type::getInt8Ty(jit->context);
+				auto sizetTy = llvm::IntegerType::get(*jit->context, sizeof(size_t) * 8);
+				auto intTy = llvm::IntegerType::get(*jit->context, sizeof(int) * 8);
+				auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
 				auto i8PtrTy = i8Ty->getPointerTo();
-				auto voidTy = llvm::Type::getVoidTy(jit->context);
+				auto voidTy = llvm::Type::getVoidTy(*jit->context);
 				auto funcTy = llvm::FunctionType::get(voidTy, { sizetTy, i8PtrTy, i8PtrTy, intTy }, false);
 				auto func = jit->module->getOrInsertFunction("__atomic_load", funcTy);
 				auto size = jit->module->getDataLayout().getTypeStoreSize(elTy);
@@ -976,10 +976,10 @@
 			{
 				// Mark all memory writes as initialized by calling __msan_unpoison
 				// void __msan_unpoison(const volatile void *a, size_t size)
-				auto voidTy = llvm::Type::getVoidTy(jit->context);
-				auto i8Ty = llvm::Type::getInt8Ty(jit->context);
+				auto voidTy = llvm::Type::getVoidTy(*jit->context);
+				auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
 				auto voidPtrTy = i8Ty->getPointerTo();
-				auto sizetTy = llvm::IntegerType::get(jit->context, sizeof(size_t) * 8);
+				auto sizetTy = llvm::IntegerType::get(*jit->context, sizeof(size_t) * 8);
 				auto funcTy = llvm::FunctionType::get(voidTy, { voidPtrTy, sizetTy }, false);
 				auto func = jit->module->getOrInsertFunction("__msan_unpoison", funcTy);
 				auto size = jit->module->getDataLayout().getTypeStoreSize(elTy);
@@ -1005,7 +1005,7 @@
 				// above, but certain backends cannot deal with this.
 				// Store as an bitcast integer. See b/136037244.
 				auto size = jit->module->getDataLayout().getTypeStoreSize(elTy);
-				auto elAsIntTy = llvm::IntegerType::get(jit->context, size * 8);
+				auto elAsIntTy = llvm::IntegerType::get(*jit->context, size * 8);
 				auto valCast = jit->builder->CreateBitCast(V(value), elAsIntTy);
 				auto ptrCast = jit->builder->CreatePointerCast(V(ptr), elAsIntTy->getPointerTo());
 				auto store = jit->builder->CreateAlignedStore(valCast, ptrCast, alignment, isVolatile);
@@ -1015,11 +1015,11 @@
 			{
 				// More exotic types require falling back to the extern:
 				// void __atomic_store(size_t size, void *ptr, void *val, int ordering)
-				auto sizetTy = llvm::IntegerType::get(jit->context, sizeof(size_t) * 8);
-				auto intTy = llvm::IntegerType::get(jit->context, sizeof(int) * 8);
-				auto i8Ty = llvm::Type::getInt8Ty(jit->context);
+				auto sizetTy = llvm::IntegerType::get(*jit->context, sizeof(size_t) * 8);
+				auto intTy = llvm::IntegerType::get(*jit->context, sizeof(int) * 8);
+				auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
 				auto i8PtrTy = i8Ty->getPointerTo();
-				auto voidTy = llvm::Type::getVoidTy(jit->context);
+				auto voidTy = llvm::Type::getVoidTy(*jit->context);
 				auto funcTy = llvm::FunctionType::get(voidTy, { sizetTy, i8PtrTy, i8PtrTy, intTy }, false);
 				auto func = jit->module->getOrInsertFunction("__atomic_store", funcTy);
 				auto size = jit->module->getDataLayout().getTypeStoreSize(elTy);
@@ -1049,8 +1049,8 @@
 	ASSERT(V(mask)->getType()->isVectorTy());
 
 	auto numEls = llvm::cast<llvm::VectorType>(V(mask)->getType())->getNumElements();
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i32Ty = llvm::Type::getInt32Ty(jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i32Ty = llvm::Type::getInt32Ty(*jit->context);
 	auto elVecTy = llvm::VectorType::get(T(elTy), numEls, false);
 	auto elVecPtrTy = elVecTy->getPointerTo();
 	auto i8Mask = jit->builder->CreateIntCast(V(mask), llvm::VectorType::get(i1Ty, numEls, false), false);  // vec<int, int, ...> -> vec<bool, bool, ...>
@@ -1069,8 +1069,8 @@
 	ASSERT(V(mask)->getType()->isVectorTy());
 
 	auto numEls = llvm::cast<llvm::VectorType>(V(mask)->getType())->getNumElements();
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i32Ty = llvm::Type::getInt32Ty(jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i32Ty = llvm::Type::getInt32Ty(*jit->context);
 	auto elVecTy = V(val)->getType();
 	auto elVecPtrTy = elVecTy->getPointerTo();
 	auto i1Mask = jit->builder->CreateIntCast(V(mask), llvm::VectorType::get(i1Ty, numEls, false), false);  // vec<int, int, ...> -> vec<bool, bool, ...>
@@ -1082,9 +1082,9 @@
 	{
 		// Mark memory writes as initialized by calling __msan_unpoison
 		// void __msan_unpoison(const volatile void *a, size_t size)
-		auto voidTy = llvm::Type::getVoidTy(jit->context);
+		auto voidTy = llvm::Type::getVoidTy(*jit->context);
 		auto voidPtrTy = voidTy->getPointerTo();
-		auto sizetTy = llvm::IntegerType::get(jit->context, sizeof(size_t) * 8);
+		auto sizetTy = llvm::IntegerType::get(*jit->context, sizeof(size_t) * 8);
 		auto funcTy = llvm::FunctionType::get(voidTy, { voidPtrTy, sizetTy }, false);
 		auto func = jit->module->getOrInsertFunction("__msan_unpoison", funcTy);
 		auto size = jit->module->getDataLayout().getTypeStoreSize(llvm::cast<llvm::VectorType>(elVecTy)->getElementType());
@@ -1093,8 +1093,8 @@
 		{
 			// Check mask for this element
 			auto idx = llvm::ConstantInt::get(i32Ty, i);
-			auto thenBlock = llvm::BasicBlock::Create(jit->context, "", jit->function);
-			auto mergeBlock = llvm::BasicBlock::Create(jit->context, "", jit->function);
+			auto thenBlock = llvm::BasicBlock::Create(*jit->context, "", jit->function);
+			auto mergeBlock = llvm::BasicBlock::Create(*jit->context, "", jit->function);
 			jit->builder->CreateCondBr(jit->builder->CreateExtractElement(i1Mask, idx), thenBlock, mergeBlock);
 			jit->builder->SetInsertPoint(thenBlock);
 
@@ -1116,9 +1116,9 @@
 	ASSERT(mask->getType()->isVectorTy());
 
 	auto numEls = llvm::cast<llvm::VectorType>(mask->getType())->getNumElements();
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i32Ty = llvm::Type::getInt32Ty(jit->context);
-	auto i8Ty = llvm::Type::getInt8Ty(jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i32Ty = llvm::Type::getInt32Ty(*jit->context);
+	auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
 	auto i8PtrTy = i8Ty->getPointerTo();
 	auto elPtrTy = elTy->getPointerTo();
 	auto elVecTy = llvm::VectorType::get(elTy, numEls, false);
@@ -1182,9 +1182,9 @@
 	ASSERT(mask->getType()->isVectorTy());
 
 	auto numEls = llvm::cast<llvm::VectorType>(mask->getType())->getNumElements();
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i32Ty = llvm::Type::getInt32Ty(jit->context);
-	auto i8Ty = llvm::Type::getInt8Ty(jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i32Ty = llvm::Type::getInt32Ty(*jit->context);
+	auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
 	auto i8PtrTy = i8Ty->getPointerTo();
 	auto elVecTy = val->getType();
 	auto elTy = llvm::cast<llvm::VectorType>(elVecTy)->getElementType();
@@ -1212,8 +1212,8 @@
 		{
 			// Check mask for this element
 			auto idx = llvm::ConstantInt::get(i32Ty, i);
-			auto thenBlock = llvm::BasicBlock::Create(jit->context, "", jit->function);
-			auto mergeBlock = llvm::BasicBlock::Create(jit->context, "", jit->function);
+			auto thenBlock = llvm::BasicBlock::Create(*jit->context, "", jit->function);
+			auto mergeBlock = llvm::BasicBlock::Create(*jit->context, "", jit->function);
 			jit->builder->CreateCondBr(jit->builder->CreateExtractElement(i1Mask, idx), thenBlock, mergeBlock);
 			jit->builder->SetInsertPoint(thenBlock);
 
@@ -1598,7 +1598,7 @@
 
 	for(int i = 0; i < size; i++)
 	{
-		swizzle[i] = llvm::ConstantInt::get(llvm::Type::getInt32Ty(jit->context), select[i]);
+		swizzle[i] = llvm::ConstantInt::get(llvm::Type::getInt32Ty(*jit->context), select[i]);
 	}
 
 	llvm::Value *shuffle = llvm::ConstantVector::get(llvm::ArrayRef<llvm::Constant *>(swizzle, size));
@@ -1622,7 +1622,7 @@
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
 	llvm::SwitchInst *sw = reinterpret_cast<llvm::SwitchInst *>(switchCases);
-	sw->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(jit->context), label, true), B(branch));
+	sw->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*jit->context), label, true), B(branch));
 }
 
 void Nucleus::createUnreachable()
@@ -1648,7 +1648,7 @@
 
 static llvm::Type *getNaturalIntType()
 {
-	return llvm::Type::getIntNTy(jit->context, sizeof(int) * 8);
+	return llvm::Type::getIntNTy(*jit->context, sizeof(int) * 8);
 }
 
 Type *Nucleus::getPrintfStorageType(Type *valueType)
@@ -1660,7 +1660,7 @@
 	}
 	if(valueTy->isFloatTy())
 	{
-		return T(llvm::Type::getDoubleTy(jit->context));
+		return T(llvm::Type::getDoubleTy(*jit->context));
 	}
 
 	UNIMPLEMENTED_NO_BUG("getPrintfStorageType: add more cases as needed");
@@ -1676,49 +1676,49 @@
 Value *Nucleus::createConstantLong(int64_t i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt64Ty(jit->context), i, true));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt64Ty(*jit->context), i, true));
 }
 
 Value *Nucleus::createConstantInt(int i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt32Ty(jit->context), i, true));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*jit->context), i, true));
 }
 
 Value *Nucleus::createConstantInt(unsigned int i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt32Ty(jit->context), i, false));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt32Ty(*jit->context), i, false));
 }
 
 Value *Nucleus::createConstantBool(bool b)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt1Ty(jit->context), b));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt1Ty(*jit->context), b));
 }
 
 Value *Nucleus::createConstantByte(signed char i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt8Ty(jit->context), i, true));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*jit->context), i, true));
 }
 
 Value *Nucleus::createConstantByte(unsigned char i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt8Ty(jit->context), i, false));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt8Ty(*jit->context), i, false));
 }
 
 Value *Nucleus::createConstantShort(short i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt16Ty(jit->context), i, true));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt16Ty(*jit->context), i, true));
 }
 
 Value *Nucleus::createConstantShort(unsigned short i)
 {
 	RR_DEBUG_INFO_UPDATE_LOC();
-	return V(llvm::ConstantInt::get(llvm::Type::getInt16Ty(jit->context), i, false));
+	return V(llvm::ConstantInt::get(llvm::Type::getInt16Ty(*jit->context), i, false));
 }
 
 Value *Nucleus::createConstantFloat(float x)
@@ -1776,32 +1776,32 @@
 
 Type *Void::type()
 {
-	return T(llvm::Type::getVoidTy(jit->context));
+	return T(llvm::Type::getVoidTy(*jit->context));
 }
 
 Type *Bool::type()
 {
-	return T(llvm::Type::getInt1Ty(jit->context));
+	return T(llvm::Type::getInt1Ty(*jit->context));
 }
 
 Type *Byte::type()
 {
-	return T(llvm::Type::getInt8Ty(jit->context));
+	return T(llvm::Type::getInt8Ty(*jit->context));
 }
 
 Type *SByte::type()
 {
-	return T(llvm::Type::getInt8Ty(jit->context));
+	return T(llvm::Type::getInt8Ty(*jit->context));
 }
 
 Type *Short::type()
 {
-	return T(llvm::Type::getInt16Ty(jit->context));
+	return T(llvm::Type::getInt16Ty(*jit->context));
 }
 
 Type *UShort::type()
 {
-	return T(llvm::Type::getInt16Ty(jit->context));
+	return T(llvm::Type::getInt16Ty(*jit->context));
 }
 
 Type *Byte4::type()
@@ -2338,12 +2338,12 @@
 
 Type *Int::type()
 {
-	return T(llvm::Type::getInt32Ty(jit->context));
+	return T(llvm::Type::getInt32Ty(*jit->context));
 }
 
 Type *Long::type()
 {
-	return T(llvm::Type::getInt64Ty(jit->context));
+	return T(llvm::Type::getInt64Ty(*jit->context));
 }
 
 UInt::UInt(RValue<Float> cast)
@@ -2404,7 +2404,7 @@
 
 Type *UInt::type()
 {
-	return T(llvm::Type::getInt32Ty(jit->context));
+	return T(llvm::Type::getInt32Ty(*jit->context));
 }
 
 //	Int2::Int2(RValue<Int> cast)
@@ -2836,7 +2836,7 @@
 
 Type *Half::type()
 {
-	return T(llvm::Type::getInt16Ty(jit->context));
+	return T(llvm::Type::getInt16Ty(*jit->context));
 }
 
 RValue<Float> Rcp_pp(RValue<Float> x, bool exactAtPow2)
@@ -3032,7 +3032,7 @@
 
 Type *Float::type()
 {
-	return T(llvm::Type::getFloatTy(jit->context));
+	return T(llvm::Type::getFloatTy(*jit->context));
 }
 
 Type *Float2::type()
@@ -3445,7 +3445,7 @@
 	RR_DEBUG_INFO_UPDATE_LOC();
 	auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::ctlz, { T(UInt::type()) });
 	return RValue<UInt>(V(jit->builder->CreateCall(func, { V(v.value()),
-	                                                       isZeroUndef ? llvm::ConstantInt::getTrue(jit->context) : llvm::ConstantInt::getFalse(jit->context) })));
+	                                                       isZeroUndef ? llvm::ConstantInt::getTrue(*jit->context) : llvm::ConstantInt::getFalse(*jit->context) })));
 }
 
 RValue<UInt4> Ctlz(RValue<UInt4> v, bool isZeroUndef)
@@ -3453,7 +3453,7 @@
 	RR_DEBUG_INFO_UPDATE_LOC();
 	auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::ctlz, { T(UInt4::type()) });
 	return RValue<UInt4>(V(jit->builder->CreateCall(func, { V(v.value()),
-	                                                        isZeroUndef ? llvm::ConstantInt::getTrue(jit->context) : llvm::ConstantInt::getFalse(jit->context) })));
+	                                                        isZeroUndef ? llvm::ConstantInt::getTrue(*jit->context) : llvm::ConstantInt::getFalse(*jit->context) })));
 }
 
 RValue<UInt> Cttz(RValue<UInt> v, bool isZeroUndef)
@@ -3461,7 +3461,7 @@
 	RR_DEBUG_INFO_UPDATE_LOC();
 	auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::cttz, { T(UInt::type()) });
 	return RValue<UInt>(V(jit->builder->CreateCall(func, { V(v.value()),
-	                                                       isZeroUndef ? llvm::ConstantInt::getTrue(jit->context) : llvm::ConstantInt::getFalse(jit->context) })));
+	                                                       isZeroUndef ? llvm::ConstantInt::getTrue(*jit->context) : llvm::ConstantInt::getFalse(*jit->context) })));
 }
 
 RValue<UInt4> Cttz(RValue<UInt4> v, bool isZeroUndef)
@@ -3469,7 +3469,7 @@
 	RR_DEBUG_INFO_UPDATE_LOC();
 	auto func = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::cttz, { T(UInt4::type()) });
 	return RValue<UInt4>(V(jit->builder->CreateCall(func, { V(v.value()),
-	                                                        isZeroUndef ? llvm::ConstantInt::getTrue(jit->context) : llvm::ConstantInt::getFalse(jit->context) })));
+	                                                        isZeroUndef ? llvm::ConstantInt::getTrue(*jit->context) : llvm::ConstantInt::getFalse(*jit->context) })));
 }
 
 RValue<Int> MinAtomic(RValue<Pointer<Int>> x, RValue<Int> y, std::memory_order memoryOrder)
@@ -3510,7 +3510,7 @@
 	RR_DEBUG_INFO_UPDATE_LOC();
 	// Note: this should work for 32-bit pointers as well because 'inttoptr'
 	// is defined to truncate (and zero extend) if necessary.
-	auto ptrAsInt = llvm::ConstantInt::get(llvm::Type::getInt64Ty(jit->context), reinterpret_cast<uintptr_t>(ptr));
+	auto ptrAsInt = llvm::ConstantInt::get(llvm::Type::getInt64Ty(*jit->context), reinterpret_cast<uintptr_t>(ptr));
 	return RValue<Pointer<Byte>>(V(jit->builder->CreateIntToPtr(ptrAsInt, T(Pointer<Byte>::type()))));
 }
 
@@ -3923,8 +3923,8 @@
 #ifdef ENABLE_RR_PRINT
 void VPrintf(const std::vector<Value *> &vals)
 {
-	auto i32Ty = llvm::Type::getInt32Ty(jit->context);
-	auto i8PtrTy = llvm::Type::getInt8PtrTy(jit->context);
+	auto i32Ty = llvm::Type::getInt32Ty(*jit->context);
+	auto i8PtrTy = llvm::Type::getInt8PtrTy(*jit->context);
 	auto funcTy = llvm::FunctionType::get(i32Ty, { i8PtrTy }, true);
 	auto func = jit->module->getOrInsertFunction("rr::DebugPrintf", funcTy);
 	jit->builder->CreateCall(func, V(vals));
@@ -3933,7 +3933,7 @@
 
 void Nop()
 {
-	auto voidTy = llvm::Type::getVoidTy(jit->context);
+	auto voidTy = llvm::Type::getVoidTy(*jit->context);
 	auto funcTy = llvm::FunctionType::get(voidTy, {}, false);
 	auto func = jit->module->getOrInsertFunction("nop", funcTy);
 	jit->builder->CreateCall(func);
@@ -3989,11 +3989,11 @@
 	ASSERT(jit->coroutine.id == nullptr);
 
 	// Types
-	auto voidTy = llvm::Type::getVoidTy(jit->context);
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i8Ty = llvm::Type::getInt8Ty(jit->context);
-	auto i32Ty = llvm::Type::getInt32Ty(jit->context);
-	auto i8PtrTy = llvm::Type::getInt8PtrTy(jit->context);
+	auto voidTy = llvm::Type::getVoidTy(*jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
+	auto i32Ty = llvm::Type::getInt32Ty(*jit->context);
+	auto i8PtrTy = llvm::Type::getInt8PtrTy(*jit->context);
 	auto promiseTy = jit->coroutine.yieldType;
 	auto promisePtrTy = promiseTy->getPointerTo();
 
@@ -4036,9 +4036,9 @@
 		auto args = jit->coroutine.await->arg_begin();
 		auto handle = args++;
 		auto outPtr = args++;
-		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(jit->context, "co_await", jit->coroutine.await));
-		auto doneBlock = llvm::BasicBlock::Create(jit->context, "done", jit->coroutine.await);
-		auto resumeBlock = llvm::BasicBlock::Create(jit->context, "resume", jit->coroutine.await);
+		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(*jit->context, "co_await", jit->coroutine.await));
+		auto doneBlock = llvm::BasicBlock::Create(*jit->context, "done", jit->coroutine.await);
+		auto resumeBlock = llvm::BasicBlock::Create(*jit->context, "resume", jit->coroutine.await);
 
 		auto done = jit->builder->CreateCall(coro_done, { handle }, "done");
 		jit->builder->CreateCondBr(done, doneBlock, resumeBlock);
@@ -4064,7 +4064,7 @@
 	//
 	{
 		auto handle = jit->coroutine.destroy->arg_begin();
-		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(jit->context, "", jit->coroutine.destroy));
+		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(*jit->context, "", jit->coroutine.destroy));
 		jit->builder->CreateCall(coro_destroy, { handle });
 		jit->builder->CreateRetVoid();
 	}
@@ -4103,12 +4103,12 @@
 	//
 
 #ifdef ENABLE_RR_DEBUG_INFO
-	jit->debugInfo = std::make_unique<rr::DebugInfo>(jit->builder.get(), &jit->context, jit->module.get(), jit->function);
+	jit->debugInfo = std::make_unique<rr::DebugInfo>(jit->builder.get(), jit->context.get(), jit->module.get(), jit->function);
 #endif  // ENABLE_RR_DEBUG_INFO
 
-	jit->coroutine.suspendBlock = llvm::BasicBlock::Create(jit->context, "suspend", jit->function);
-	jit->coroutine.endBlock = llvm::BasicBlock::Create(jit->context, "end", jit->function);
-	jit->coroutine.destroyBlock = llvm::BasicBlock::Create(jit->context, "destroy", jit->function);
+	jit->coroutine.suspendBlock = llvm::BasicBlock::Create(*jit->context, "suspend", jit->function);
+	jit->coroutine.endBlock = llvm::BasicBlock::Create(*jit->context, "end", jit->function);
+	jit->coroutine.destroyBlock = llvm::BasicBlock::Create(*jit->context, "destroy", jit->function);
 
 	jit->builder->SetInsertPoint(jit->coroutine.entryBlock, jit->coroutine.entryBlock->begin());
 	jit->coroutine.promise = jit->builder->CreateAlloca(promiseTy, nullptr, "promise");
@@ -4130,7 +4130,7 @@
 	// Build the end block
 	jit->builder->SetInsertPoint(jit->coroutine.endBlock);
 	auto action = jit->builder->CreateCall(coro_suspend, {
-	                                                         llvm::ConstantTokenNone::get(jit->context),
+	                                                         llvm::ConstantTokenNone::get(*jit->context),
 	                                                         llvm::ConstantInt::get(i1Ty, 1),  // final: true
 	                                                     });
 	auto switch_ = jit->builder->CreateSwitch(action, jit->coroutine.suspendBlock, 3);
@@ -4156,9 +4156,9 @@
 	// Coroutines are initially created as a regular function.
 	// Upon the first call to Yield(), the function is promoted to a true
 	// coroutine.
-	auto voidTy = llvm::Type::getVoidTy(jit->context);
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i8PtrTy = llvm::Type::getInt8PtrTy(jit->context);
+	auto voidTy = llvm::Type::getVoidTy(*jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i8PtrTy = llvm::Type::getInt8PtrTy(*jit->context);
 	auto handleTy = i8PtrTy;
 	auto boolTy = i1Ty;
 	auto promiseTy = T(YieldType);
@@ -4168,7 +4168,7 @@
 	jit->coroutine.await = rr::createFunction("coroutine_await", boolTy, { handleTy, promisePtrTy });
 	jit->coroutine.destroy = rr::createFunction("coroutine_destroy", voidTy, { handleTy });
 	jit->coroutine.yieldType = promiseTy;
-	jit->coroutine.entryBlock = llvm::BasicBlock::Create(jit->context, "function", jit->function);
+	jit->coroutine.entryBlock = llvm::BasicBlock::Create(*jit->context, "function", jit->function);
 
 	jit->builder->SetInsertPoint(jit->coroutine.entryBlock);
 }
@@ -4202,19 +4202,19 @@
 	Variable::materializeAll();
 
 	// Types
-	auto i1Ty = llvm::Type::getInt1Ty(jit->context);
-	auto i8Ty = llvm::Type::getInt8Ty(jit->context);
+	auto i1Ty = llvm::Type::getInt1Ty(*jit->context);
+	auto i8Ty = llvm::Type::getInt8Ty(*jit->context);
 
 	// Intrinsics
 	auto coro_suspend = llvm::Intrinsic::getDeclaration(jit->module.get(), llvm::Intrinsic::coro_suspend);
 
 	// Create a block to resume execution.
-	auto resumeBlock = llvm::BasicBlock::Create(jit->context, "resume", jit->function);
+	auto resumeBlock = llvm::BasicBlock::Create(*jit->context, "resume", jit->function);
 
 	// Store the promise (yield value)
 	jit->builder->CreateStore(V(val), jit->coroutine.promise);
 	auto action = jit->builder->CreateCall(coro_suspend, {
-	                                                         llvm::ConstantTokenNone::get(jit->context),
+	                                                         llvm::ConstantTokenNone::get(*jit->context),
 	                                                         llvm::ConstantInt::get(i1Ty, 0),  // final: true
 	                                                     });
 	auto switch_ = jit->builder->CreateSwitch(action, jit->coroutine.suspendBlock, 3);
@@ -4239,10 +4239,10 @@
 		// handle.
 		jit->builder->CreateRet(llvm::Constant::getNullValue(jit->function->getReturnType()));
 		// The 'coroutine_await' function always returns false (coroutine done).
-		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(jit->context, "", jit->coroutine.await));
+		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(*jit->context, "", jit->coroutine.await));
 		jit->builder->CreateRet(llvm::Constant::getNullValue(jit->coroutine.await->getReturnType()));
 		// The 'coroutine_destroy' does nothing, returns void.
-		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(jit->context, "", jit->coroutine.destroy));
+		jit->builder->SetInsertPoint(llvm::BasicBlock::Create(*jit->context, "", jit->coroutine.destroy));
 		jit->builder->CreateRetVoid();
 	}
 
diff --git a/src/Reactor/LLVMReactor.hpp b/src/Reactor/LLVMReactor.hpp
index d18869f..254be42 100644
--- a/src/Reactor/LLVMReactor.hpp
+++ b/src/Reactor/LLVMReactor.hpp
@@ -95,7 +95,7 @@
 	std::shared_ptr<rr::Routine> acquireRoutine(const char *name, llvm::Function **funcs, size_t count, const rr::Config &cfg);
 
 	const Config config;
-	llvm::LLVMContext context;
+	std::unique_ptr<llvm::LLVMContext> context;
 	std::unique_ptr<llvm::Module> module;
 	std::unique_ptr<llvm::IRBuilder<>> builder;
 	llvm::Function *function = nullptr;