Reactor: Rework optimization flags.

Replace the old 'runOptimizations' flag on Nucleus::acquireRoutine() and Nucleus::acquireCoroutine() with a new OptimizationLevel enumerator.
runOptimizations was always true, and there is already the rr::optimization extern to control the optimization passes performed.

All Function and Coroutines are now passed the new vk::ReactorOptimizationLevel. This will be changed to a non-Default value in another CL.

Bug: b/135609394
Change-Id: I1154da05d413b18a471a3818fbb03f356a3d0e6c
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/33482
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index 30bcf94..bdcfe0a 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -1534,7 +1534,7 @@
 			}
 		}
 
-		return function("BlitRoutine");
+		return function(vk::ReactorOptimizationLevel, "BlitRoutine");
 	}
 
 	Routine *Blitter::getBlitRoutine(const State &state)
@@ -1889,7 +1889,7 @@
 			}
 		}
 
-		return function("BlitRoutine");
+		return function(vk::ReactorOptimizationLevel, "BlitRoutine");
 	}
 
 	void Blitter::updateBorders(vk::Image* image, const VkImageSubresourceLayers& subresourceLayers)
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index 898da83..51f4517 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -238,7 +238,7 @@
 		{
 			QuadRasterizer *generator = new PixelProgram(state, pipelineLayout, pixelShader, descriptorSets);
 			generator->generate();
-			routine = (*generator)("PixelRoutine_%0.8X", state.shaderID);
+			routine = (*generator)(vk::ReactorOptimizationLevel, "PixelRoutine_%0.8X", state.shaderID);
 			delete generator;
 
 			routineCache->add(state, routine);
diff --git a/src/Device/VertexProcessor.cpp b/src/Device/VertexProcessor.cpp
index 2f489bb..76daf76 100644
--- a/src/Device/VertexProcessor.cpp
+++ b/src/Device/VertexProcessor.cpp
@@ -105,7 +105,7 @@
 		{
 			VertexRoutine *generator = new VertexProgram(state, pipelineLayout, vertexShader, descriptorSets);
 			generator->generate();
-			routine = (*generator)("VertexRoutine_%0.8X", state.shaderID);
+			routine = (*generator)(vk::ReactorOptimizationLevel, "VertexRoutine_%0.8X", state.shaderID);
 			delete generator;
 
 			routineCache->add(state, routine);
diff --git a/src/Pipeline/SetupRoutine.cpp b/src/Pipeline/SetupRoutine.cpp
index a87aac6..1973a71 100644
--- a/src/Pipeline/SetupRoutine.cpp
+++ b/src/Pipeline/SetupRoutine.cpp
@@ -453,7 +453,7 @@
 			Return(1);
 		}
 
-		routine = function("SetupRoutine");
+		routine = function(vk::ReactorOptimizationLevel, "SetupRoutine");
 	}
 
 	void SetupRoutine::setupGradient(Pointer<Byte> &primitive, Pointer<Byte> &triangle, Float4 &w012, Float4 (&m)[3], Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2, int attribute, int planeEquation, bool flat, bool perspective, int component)
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index a54eb8d..6255726 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -231,7 +231,7 @@
 		}
 	}
 
-	return (ImageSampler*)function("sampler")->getEntry();
+	return (ImageSampler*)function(vk::ReactorOptimizationLevel, "sampler")->getEntry();
 }
 
 sw::TextureType SpirvShader::convertTextureType(VkImageViewType imageViewType)
diff --git a/src/Reactor/Coroutine.hpp b/src/Reactor/Coroutine.hpp
index 3d88048..993e7e0 100644
--- a/src/Reactor/Coroutine.hpp
+++ b/src/Reactor/Coroutine.hpp
@@ -133,7 +133,7 @@
 		// called without building a new rr::Function or rr::Coroutine.
 		// While automatically called by operator(), finalize() should be called
 		// as early as possible to release the global Reactor mutex lock.
-		inline void finalize();
+		inline void finalize(OptimizationLevel optLevel = OptimizationLevel::Default);
 
 		// Starts execution of the coroutine and returns a unique_ptr to a
 		// Stream<> that exposes the await() function for obtaining yielded
@@ -147,7 +147,7 @@
 	};
 
 	template<typename Return, typename... Arguments>
-	Coroutine<Return(Arguments...)>::Coroutine() : routine{}
+	Coroutine<Return(Arguments...)>::Coroutine()
 	{
 		core.reset(new Nucleus());
 
@@ -164,11 +164,11 @@
 	}
 
 	template<typename Return, typename... Arguments>
-	void Coroutine<Return(Arguments...)>::finalize()
+	void Coroutine<Return(Arguments...)>::finalize(OptimizationLevel optLevel /* = OptimizationLevel::Default */)
 	{
 		if(core != nullptr)
 		{
-			routine.reset(core->acquireCoroutine("coroutine", true));
+			routine.reset(core->acquireCoroutine("coroutine", optLevel));
 			core.reset(nullptr);
 		}
 	}
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index d6f530d..af049c6 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -219,7 +219,11 @@
 		using ObjLayer = llvm::orc::RTDyldObjectLinkingLayer;
 		using CompileLayer = llvm::orc::IRCompileLayer<ObjLayer, llvm::orc::SimpleCompiler>;
 	public:
-		JITRoutine(std::unique_ptr<llvm::Module> module, llvm::Function **funcs, size_t count) :
+		JITRoutine(
+				std::unique_ptr<llvm::Module> module,
+				llvm::Function **funcs,
+				size_t count,
+				rr::OptimizationLevel optLevel) :
 			resolver(createLegacyLookupResolver(
 				session,
 				[&](const std::string &name) {
@@ -241,6 +245,8 @@
 			targetMachine(llvm::EngineBuilder()
 #ifdef ENABLE_RR_DEBUG_INFO
 				.setOptLevel(llvm::CodeGenOpt::None)
+#else
+				.setOptLevel(toLLVM(optLevel))
 #endif // ENABLE_RR_DEBUG_INFO
 				.setMArch(JITGlobals::get()->arch)
 				.setMAttrs(JITGlobals::get()->mattrs)
@@ -306,6 +312,19 @@
 		}
 
 	private:
+		static ::llvm::CodeGenOpt::Level toLLVM(rr::OptimizationLevel 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));
+			}
+			return ::llvm::CodeGenOpt::Default;
+		}
+
 		std::shared_ptr<llvm::orc::SymbolResolver> resolver;
 		std::unique_ptr<llvm::TargetMachine> targetMachine;
 		llvm::orc::ExecutionSession session;
@@ -361,10 +380,10 @@
 			passManager->run(*module);
 		}
 
-		rr::Routine *acquireRoutine(llvm::Function **funcs, size_t count)
+		rr::Routine *acquireRoutine(llvm::Function **funcs, size_t count, rr::OptimizationLevel optLevel)
 		{
 			ASSERT(module);
-			return new JITRoutine(std::move(module), funcs, count);
+			return new JITRoutine(std::move(module), funcs, count, optLevel);
 		}
 
 		llvm::LLVMContext context;
@@ -1118,7 +1137,7 @@
 		::codegenMutex.unlock();
 	}
 
-	Routine *Nucleus::acquireRoutine(const char *name, bool runOptimizations)
+	Routine *Nucleus::acquireRoutine(const char *name, OptimizationLevel optimizationLevel)
 	{
 		if(jit->builder->GetInsertBlock()->empty() || !jit->builder->GetInsertBlock()->back().isTerminator())
 		{
@@ -1156,10 +1175,7 @@
 		}
 #endif // defined(ENABLE_RR_LLVM_IR_VERIFICATION) || !defined(NDEBUG)
 
-		if(runOptimizations)
-		{
-			optimize();
-		}
+		optimize();
 
 		if(false)
 		{
@@ -1168,7 +1184,7 @@
 			jit->module->print(file, 0);
 		}
 
-		auto routine = jit->acquireRoutine(&jit->function, 1);
+		auto routine = jit->acquireRoutine(&jit->function, 1, optimizationLevel);
 		jit.reset();
 
 		return routine;
@@ -4656,7 +4672,7 @@
 	jit->builder->SetInsertPoint(resumeBlock);
 }
 
-Routine* Nucleus::acquireCoroutine(const char *name, bool runOptimizations)
+Routine* Nucleus::acquireCoroutine(const char *name, OptimizationLevel optimizationLevel)
 {
 	ASSERT_MSG(jit->coroutine.id != nullptr, "acquireCoroutine() called without a call to createCoroutine()");
 
@@ -4685,10 +4701,7 @@
 	pm.add(llvm::createCoroCleanupPass());
 	pm.run(*jit->module);
 
-	if(runOptimizations)
-	{
-		optimize();
-	}
+	optimize();
 
 	if(false)
 	{
@@ -4701,7 +4714,7 @@
 	funcs[Nucleus::CoroutineEntryBegin] = jit->function;
 	funcs[Nucleus::CoroutineEntryAwait] = jit->coroutine.await;
 	funcs[Nucleus::CoroutineEntryDestroy] = jit->coroutine.destroy;
-	Routine *routine = jit->acquireRoutine(funcs, Nucleus::CoroutineEntryCount);
+	auto routine = jit->acquireRoutine(funcs, Nucleus::CoroutineEntryCount, optimizationLevel);
 	jit.reset();
 
 	return routine;
diff --git a/src/Reactor/Nucleus.hpp b/src/Reactor/Nucleus.hpp
index 3362fb4..1b4e2db 100644
--- a/src/Reactor/Nucleus.hpp
+++ b/src/Reactor/Nucleus.hpp
@@ -21,6 +21,10 @@
 #include <vector>
 #include <atomic>
 
+#ifdef None
+#undef None  // b/127920555
+#endif
+
 namespace rr
 {
 	class Type;
@@ -47,6 +51,14 @@
 
 	extern Optimization optimization[10];
 
+	enum class OptimizationLevel
+	{
+		None,
+		Less,
+		Default,
+		Aggressive,
+	};
+
 	class Nucleus
 	{
 	public:
@@ -54,7 +66,7 @@
 
 		virtual ~Nucleus();
 
-		Routine *acquireRoutine(const char *name, bool runOptimizations = true);
+		Routine *acquireRoutine(const char *name, OptimizationLevel optimizationLevel);
 
 		static Value *allocateStackVariable(Type *type, int arraySize = 0);
 		static BasicBlock *createBasicBlock();
@@ -81,7 +93,7 @@
 		};
 
 		static void createCoroutine(Type *ReturnType, std::vector<Type*> &Params);
-		Routine *acquireCoroutine(const char *name, bool runOptimizations = true);
+		Routine *acquireCoroutine(const char *name, OptimizationLevel optimizationLevel);
 		static void yield(Value*);
 
 		// Terminators
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index d9419a8..53853c0 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -2465,6 +2465,7 @@
 		}
 
 		Routine *operator()(const char *name, ...);
+		Routine *operator()(OptimizationLevel optLevel, const char *name, ...);
 
 	protected:
 		Nucleus *core;
@@ -3039,7 +3040,20 @@
 		vsnprintf(fullName, 1024, name, vararg);
 		va_end(vararg);
 
-		return core->acquireRoutine(fullName, true);
+		return core->acquireRoutine(fullName, OptimizationLevel::Default);
+	}
+
+	template<typename Return, typename... Arguments>
+	Routine *Function<Return(Arguments...)>::operator()(OptimizationLevel optLevel, const char *name, ...)
+	{
+		char fullName[1024 + 1];
+
+		va_list vararg;
+		va_start(vararg, name);
+		vsnprintf(fullName, 1024, name, vararg);
+		va_end(vararg);
+
+		return core->acquireRoutine(fullName, optLevel);
 	}
 
 	template<class T, class S>
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index d655c93..e8cc581 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -585,7 +585,7 @@
 		::codegenMutex.unlock();
 	}
 
-	Routine *Nucleus::acquireRoutine(const char *name, bool runOptimizations)
+	Routine *Nucleus::acquireRoutine(const char *name, OptimizationLevel optimizationLevel)
 	{
 		if(basicBlock->getInsts().empty() || basicBlock->getInsts().back().getKind() != Ice::Inst::Ret)
 		{
@@ -3506,7 +3506,7 @@
 	void FlushDebug() {}
 
 	void Nucleus::createCoroutine(Type *YieldType, std::vector<Type*> &Params) { UNIMPLEMENTED("createCoroutine"); }
-	Routine* Nucleus::acquireCoroutine(const char *name, bool runOptimizations) { UNIMPLEMENTED("acquireCoroutine"); return nullptr; }
+	Routine* Nucleus::acquireCoroutine(const char *name, OptimizationLevel optimizationLevel) { UNIMPLEMENTED("acquireCoroutine"); return nullptr; }
 	void Nucleus::yield(Value* val) { UNIMPLEMENTED("Yield"); }
 
 }
diff --git a/src/Vulkan/VkConfig.h b/src/Vulkan/VkConfig.h
index 157f34e..adaa353 100644
--- a/src/Vulkan/VkConfig.h
+++ b/src/Vulkan/VkConfig.h
@@ -17,6 +17,8 @@
 
 #include "Version.h"
 
+#include "Reactor/Nucleus.hpp" // ReactorOptimizationLevel
+
 #include <Vulkan/VulkanPlatform.h>
 
 namespace vk
@@ -77,6 +79,9 @@
 	MAX_POINT_SIZE = 1,		// Large points are not supported. If/when we turn this on, must be >= 64.
 };
 
+// Optimization level to use for JIT functions.
+static constexpr auto ReactorOptimizationLevel = rr::OptimizationLevel::Default;
+
 }
 
 #endif // VK_CONFIG_HPP_
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index cf4764b..d54fddc 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -242,7 +242,7 @@
 	// TODO(b/119409619): use allocator.
 	auto program = std::make_shared<sw::ComputeProgram>(key.getShader(), key.getLayout(), descriptorSets);
 	program->generate();
-	program->finalize();
+	program->finalize(vk::ReactorOptimizationLevel);
 	return program;
 }