Support the new LLVM pass manager

The legacy pass manager is deprecated in LLVM 13 [0], and will be
removed entirely by LLVM 16. We should use the new pass manager [1] when
building with a recent version of LLVM.

Since we still use LLVM 10 by default, we need two code paths for now.

Note that this change illustrates that LLVMReactor.cpp still has some
dependencies on the guts of LLVM, that belong in LLVMJIT.cpp instead.
This will be cleaned up in a subsequent change. This one is based
directly on cl/442613159 which was authored by aeubanks@.

[0] https://releases.llvm.org/13.0.0/docs/ReleaseNotes.html#changes-to-the-llvm-ir
[1] https://llvm.org/docs/NewPassManager.html

Bug: b/229474816
Bug: b/229437380
Bug: b/229629349
Change-Id: I6fa9e6783595e808e3c0bd46d54fc5407cfc7588
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/65148
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 802c046..3ff5613 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -404,6 +404,7 @@
         "/wd4838" # conversion from 'type_1' to 'type_2' requires a narrowing conversion
         "/wd5030" # attribute 'attribute' is not recognized
         "/wd5038" # data member 'member1' will be initialized after data member 'member2' data member 'member' will be initialized after base class 'base_class'
+        "/wd4146" # unary minus operator applied to unsigned type, result still unsigned
     )
 
     # Treat specific warnings as errors
diff --git a/src/Reactor/LLVMJIT.cpp b/src/Reactor/LLVMJIT.cpp
index b6ee726..a217b92 100644
--- a/src/Reactor/LLVMJIT.cpp
+++ b/src/Reactor/LLVMJIT.cpp
@@ -31,7 +31,6 @@
 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
 #include "llvm/IR/DiagnosticInfo.h"
-#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/TargetSelect.h"
@@ -40,6 +39,22 @@
 #include "llvm/Transforms/Scalar.h"
 #include "llvm/Transforms/Scalar/GVN.h"
 
+#if LLVM_VERSION_MAJOR >= 13  // New pass manager
+#	include "llvm/IR/PassManager.h"
+#	include "llvm/Passes/PassBuilder.h"
+#	include "llvm/Transforms/Scalar/ADCE.h"
+#	include "llvm/Transforms/Scalar/DeadStoreElimination.h"
+#	include "llvm/Transforms/Scalar/EarlyCSE.h"
+#	include "llvm/Transforms/Scalar/LICM.h"
+#	include "llvm/Transforms/Scalar/Reassociate.h"
+#	include "llvm/Transforms/Scalar/SCCP.h"
+#	include "llvm/Transforms/Scalar/SROA.h"
+#	include "llvm/Transforms/Scalar/SimplifyCFG.h"
+#else  // Legacy pass manager
+#	include "llvm/IR/LegacyPassManager.h"
+#	include "llvm/Transforms/Scalar.h"
+#endif
+
 #ifdef _MSC_VER
     __pragma(warning(pop))
 #endif
@@ -848,6 +863,58 @@
 	}
 #endif  // ENABLE_RR_DEBUG_INFO
 
+#if LLVM_VERSION_MAJOR >= 13  // New pass manager
+	llvm::LoopAnalysisManager lam;
+	llvm::FunctionAnalysisManager fam;
+	llvm::CGSCCAnalysisManager cgam;
+	llvm::ModuleAnalysisManager mam;
+	llvm::PassBuilder pb;
+
+	pb.registerModuleAnalyses(mam);
+	pb.registerCGSCCAnalyses(cgam);
+	pb.registerFunctionAnalyses(fam);
+	pb.registerLoopAnalyses(lam);
+	pb.crossRegisterProxies(lam, fam, cgam, mam);
+
+	llvm::ModulePassManager pm;
+	llvm::FunctionPassManager fpm;
+
+	if(__has_feature(memory_sanitizer) && msanInstrumentation)
+	{
+		llvm::MemorySanitizerOptions msanOpts;
+		pm.addPass(llvm::ModuleMemorySanitizerPass(msanOpts));
+		pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::MemorySanitizerPass(msanOpts)));
+	}
+
+	for(auto pass : cfg.getOptimization().getPasses())
+	{
+		switch(pass)
+		{
+		case rr::Optimization::Pass::Disabled: break;
+		case rr::Optimization::Pass::CFGSimplification: fpm.addPass(llvm::SimplifyCFGPass()); break;
+		case rr::Optimization::Pass::LICM: fpm.addPass(llvm::createFunctionToLoopPassAdaptor(
+			llvm::LICMPass(llvm::SetLicmMssaOptCap, llvm::SetLicmMssaNoAccForPromotionCap, true)));
+			break;
+		case rr::Optimization::Pass::AggressiveDCE: fpm.addPass(llvm::ADCEPass()); break;
+		case rr::Optimization::Pass::GVN: fpm.addPass(llvm::GVNPass()); break;
+		case rr::Optimization::Pass::InstructionCombining: fpm.addPass(llvm::InstCombinePass()); break;
+		case rr::Optimization::Pass::Reassociate: fpm.addPass(llvm::ReassociatePass()); break;
+		case rr::Optimization::Pass::DeadStoreElimination: fpm.addPass(llvm::DSEPass()); break;
+		case rr::Optimization::Pass::SCCP: fpm.addPass(llvm::SCCPPass()); break;
+		case rr::Optimization::Pass::ScalarReplAggregates: fpm.addPass(llvm::SROAPass()); break;
+		case rr::Optimization::Pass::EarlyCSEPass: fpm.addPass(llvm::EarlyCSEPass()); break;
+		default:
+			UNREACHABLE("pass: %d", int(pass));
+		}
+	}
+
+	if(!fpm.isEmpty())
+	{
+		pm.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(fpm)));
+	}
+
+	pm.run(*module, mam);
+#else  // Legacy pass manager
 	llvm::legacy::PassManager passManager;
 
 	if(__has_feature(memory_sanitizer) && msanInstrumentation)
@@ -876,6 +943,7 @@
 	}
 
 	passManager.run(*module);
+#endif
 }
 
 std::shared_ptr<rr::Routine> JITBuilder::acquireRoutine(const char *name, llvm::Function **funcs, size_t count, const rr::Config &cfg)
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 74a83a3..33904af 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -23,7 +23,6 @@
 
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsX86.h"
-#include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Alignment.h"
@@ -32,6 +31,16 @@
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Scalar.h"
 
+#if LLVM_VERSION_MAJOR >= 13  // New pass manager
+#	include "llvm/Passes/PassBuilder.h"
+#else  // Legacy pass manager
+#	include "llvm/IR/LegacyPassManager.h"
+#	include "llvm/Pass.h"
+#	include "llvm/Transforms/Coroutines.h"
+#	include "llvm/Transforms/IPO.h"
+#	include "llvm/Transforms/Scalar.h"
+#endif
+
 #include <fstream>
 #include <iostream>
 #include <mutex>
@@ -614,10 +623,9 @@
 		}
 
 #if defined(ENABLE_RR_LLVM_IR_VERIFICATION) || !defined(NDEBUG)
+		if(llvm::verifyModule(*jit->module, &llvm::errs()))
 		{
-			llvm::legacy::PassManager pm;
-			pm.add(llvm::createVerifierPass());
-			pm.run(*jit->module);
+			llvm::report_fatal_error("Invalid LLVM module");
 		}
 #endif  // defined(ENABLE_RR_LLVM_IR_VERIFICATION) || !defined(NDEBUG)
 
@@ -4391,6 +4399,23 @@
 
 	if(isCoroutine)
 	{
+#if LLVM_VERSION_MAJOR >= 13  // New pass manager
+		llvm::PassBuilder pb;
+		llvm::LoopAnalysisManager lam;
+		llvm::FunctionAnalysisManager fam;
+		llvm::CGSCCAnalysisManager cgam;
+		llvm::ModuleAnalysisManager mam;
+
+		pb.registerModuleAnalyses(mam);
+		pb.registerCGSCCAnalyses(cgam);
+		pb.registerFunctionAnalyses(fam);
+		pb.registerLoopAnalyses(lam);
+		pb.crossRegisterProxies(lam, fam, cgam, mam);
+
+		llvm::ModulePassManager mpm =
+		    pb.buildO0DefaultPipeline(llvm::OptimizationLevel::O0);
+		mpm.run(*jit->module, mam);
+#else
 		// Run manadory coroutine transforms.
 		llvm::legacy::PassManager pm;
 
@@ -4401,13 +4426,13 @@
 		pm.add(llvm::createCoroCleanupLegacyPass());
 
 		pm.run(*jit->module);
+#endif
 	}
 
 #if defined(ENABLE_RR_LLVM_IR_VERIFICATION) || !defined(NDEBUG)
+	if(llvm::verifyModule(*jit->module, &llvm::errs()))
 	{
-		llvm::legacy::PassManager pm;
-		pm.add(llvm::createVerifierPass());
-		pm.run(*jit->module);
+		llvm::report_fatal_error("Invalid LLVM module");
 	}
 #endif  // defined(ENABLE_RR_LLVM_IR_VERIFICATION) || !defined(NDEBUG)