diff --git a/mlir/include/mlir/ExecutionEngine/OptUtils.h b/mlir/include/mlir/ExecutionEngine/OptUtils.h --- a/mlir/include/mlir/ExecutionEngine/OptUtils.h +++ b/mlir/include/mlir/ExecutionEngine/OptUtils.h @@ -14,8 +14,6 @@ #ifndef MLIR_EXECUTIONENGINE_OPTUTILS_H #define MLIR_EXECUTIONENGINE_OPTUTILS_H -#include "llvm/Pass.h" - #include #include @@ -27,10 +25,6 @@ namespace mlir { -/// Initialize LLVM passes that can be used when running MLIR code using -/// ExecutionEngine. -void initializeLLVMPasses(); - /// Create a module transformer function for MLIR ExecutionEngine that runs /// LLVM IR passes corresponding to the given speed and size optimization /// levels (e.g. -O2 or -Os). If not null, `targetMachine` is used to @@ -40,18 +34,6 @@ makeOptimizingTransformer(unsigned optLevel, unsigned sizeLevel, llvm::TargetMachine *targetMachine); -/// Create a module transformer function for MLIR ExecutionEngine that runs -/// LLVM IR passes explicitly specified, plus an optional optimization level, -/// Any optimization passes, if present, will be inserted before the pass at -/// position optPassesInsertPos. If not null, `targetMachine` is used to -/// initialize passes that provide target-specific information to the LLVM -/// optimizer. `targetMachine` must outlive the returned std::function. -std::function -makeLLVMPassesTransformer(llvm::ArrayRef llvmPasses, - llvm::Optional mbOptLevel, - llvm::TargetMachine *targetMachine, - unsigned optPassesInsertPos = 0); - } // namespace mlir #endif // MLIR_EXECUTIONENGINE_OPTUTILS_H diff --git a/mlir/lib/CAPI/ExecutionEngine/ExecutionEngine.cpp b/mlir/lib/CAPI/ExecutionEngine/ExecutionEngine.cpp --- a/mlir/lib/CAPI/ExecutionEngine/ExecutionEngine.cpp +++ b/mlir/lib/CAPI/ExecutionEngine/ExecutionEngine.cpp @@ -48,8 +48,8 @@ // Create a transformer to run all LLVM optimization passes at the // specified optimization level. auto llvmOptLevel = static_cast(optLevel); - auto transformer = mlir::makeLLVMPassesTransformer( - /*passes=*/{}, llvmOptLevel, /*targetMachine=*/tmOrError->get()); + auto transformer = mlir::makeOptimizingTransformer( + llvmOptLevel, /*sizeLevel=*/0, /*targetMachine=*/tmOrError->get()); ExecutionEngineOptions jitOptions; jitOptions.transformer = transformer; jitOptions.jitCodeGenOptLevel = llvmOptLevel; diff --git a/mlir/lib/ExecutionEngine/JitRunner.cpp b/mlir/lib/ExecutionEngine/JitRunner.cpp --- a/mlir/lib/ExecutionEngine/JitRunner.cpp +++ b/mlir/lib/ExecutionEngine/JitRunner.cpp @@ -57,10 +57,6 @@ llvm::cl::OptionCategory optFlags{"opt-like flags"}; - // CLI list of pass information - llvm::cl::list llvmPasses{ - llvm::cl::desc("LLVM optimizing passes to run"), llvm::cl::cat(optFlags)}; - // CLI variables for -On options. llvm::cl::opt optO0{"O0", llvm::cl::desc("Run opt passes and codegen at O0"), @@ -322,27 +318,6 @@ Optional optLevel = getCommandLineOptLevel(options); SmallVector>, 4> optFlags{ options.optO0, options.optO1, options.optO2, options.optO3}; - unsigned optCLIPosition = 0; - // Determine if there is an optimization flag present, and its CLI position - // (optCLIPosition). - for (unsigned j = 0; j < 4; ++j) { - auto &flag = optFlags[j].get(); - if (flag) { - optCLIPosition = flag.getPosition(); - break; - } - } - // Generate vector of pass information, plus the index at which we should - // insert any optimization passes in that vector (optPosition). - SmallVector passes; - unsigned optPosition = 0; - for (unsigned i = 0, e = options.llvmPasses.size(); i < e; ++i) { - passes.push_back(options.llvmPasses[i]); - if (optCLIPosition < options.llvmPasses.getPosition(i)) { - optPosition = i; - optCLIPosition = UINT_MAX; // To ensure we never insert again - } - } MLIRContext context(registry); @@ -367,11 +342,11 @@ return EXIT_FAILURE; } - auto transformer = mlir::makeLLVMPassesTransformer( - passes, optLevel, /*targetMachine=*/tmOrError->get(), optPosition); - CompileAndExecuteConfig compileAndExecuteConfig; - compileAndExecuteConfig.transformer = transformer; + if (optLevel) { + compileAndExecuteConfig.transformer = mlir::makeOptimizingTransformer( + *optLevel, /*sizeLevel=*/0, /*targetMachine=*/tmOrError->get()); + } compileAndExecuteConfig.llvmModuleBuilder = config.llvmModuleBuilder; compileAndExecuteConfig.runtimeSymbolMap = config.runtimesymbolMap; diff --git a/mlir/lib/ExecutionEngine/OptUtils.cpp b/mlir/lib/ExecutionEngine/OptUtils.cpp --- a/mlir/lib/ExecutionEngine/OptUtils.cpp +++ b/mlir/lib/ExecutionEngine/OptUtils.cpp @@ -13,135 +13,76 @@ #include "mlir/ExecutionEngine/OptUtils.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/Passes/OptimizationLevel.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Error.h" -#include "llvm/Support/StringSaver.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Coroutines.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include -#include -// Run the module and function passes managed by the module manager. -static void runPasses(llvm::legacy::PassManager &modulePM, - llvm::legacy::FunctionPassManager &funcPM, - llvm::Module &m) { - funcPM.doInitialization(); - for (auto &func : m) { - funcPM.run(func); - } - funcPM.doFinalization(); - modulePM.run(m); -} +using namespace llvm; -// Initialize basic LLVM transformation passes under lock. -void mlir::initializeLLVMPasses() { - static std::mutex mutex; - std::lock_guard lock(mutex); +static Optional mapToLevel(unsigned optLevel, + unsigned sizeLevel) { + switch (optLevel) { + case 0: + return OptimizationLevel::O0; - auto ®istry = *llvm::PassRegistry::getPassRegistry(); - llvm::initializeCore(registry); - llvm::initializeTransformUtils(registry); - llvm::initializeScalarOpts(registry); - llvm::initializeIPO(registry); - llvm::initializeInstCombine(registry); - llvm::initializeAggressiveInstCombine(registry); - llvm::initializeAnalysis(registry); - llvm::initializeVectorization(registry); - llvm::initializeCoroutines(registry); -} + case 1: + return OptimizationLevel::O1; -// Populate pass managers according to the optimization and size levels. -// This behaves similarly to LLVM opt. -static void populatePassManagers(llvm::legacy::PassManager &modulePM, - llvm::legacy::FunctionPassManager &funcPM, - unsigned optLevel, unsigned sizeLevel, - llvm::TargetMachine *targetMachine) { - llvm::PassManagerBuilder builder; - builder.OptLevel = optLevel; - builder.SizeLevel = sizeLevel; - builder.Inliner = llvm::createFunctionInliningPass( - optLevel, sizeLevel, /*DisableInlineHotCallSite=*/false); - builder.LoopVectorize = optLevel > 1 && sizeLevel < 2; - builder.SLPVectorize = optLevel > 1 && sizeLevel < 2; - builder.DisableUnrollLoops = (optLevel == 0); + case 2: + switch (sizeLevel) { + case 0: + return OptimizationLevel::O2; - // Add all coroutine passes to the builder. - addCoroutinePassesToExtensionPoints(builder); + case 1: + return OptimizationLevel::Os; - if (targetMachine) { - // Add pass to initialize TTI for this specific target. Otherwise, TTI will - // be initialized to NoTTIImpl by default. - modulePM.add(createTargetTransformInfoWrapperPass( - targetMachine->getTargetIRAnalysis())); - funcPM.add(createTargetTransformInfoWrapperPass( - targetMachine->getTargetIRAnalysis())); - } + case 2: + return OptimizationLevel::Oz; + } - builder.populateModulePassManager(modulePM); - builder.populateFunctionPassManager(funcPM); + case 3: + return OptimizationLevel::O3; + } + return None; } - // Create and return a lambda that uses LLVM pass manager builder to set up // optimizations based on the given level. -std::function +std::function mlir::makeOptimizingTransformer(unsigned optLevel, unsigned sizeLevel, - llvm::TargetMachine *targetMachine) { - return [optLevel, sizeLevel, targetMachine](llvm::Module *m) -> llvm::Error { - llvm::legacy::PassManager modulePM; - llvm::legacy::FunctionPassManager funcPM(m); - populatePassManagers(modulePM, funcPM, optLevel, sizeLevel, targetMachine); - runPasses(modulePM, funcPM, *m); - - return llvm::Error::success(); - }; -} - -// Create and return a lambda that is given a set of passes to run, plus an -// optional optimization level to pre-populate the pass manager. -std::function mlir::makeLLVMPassesTransformer( - llvm::ArrayRef llvmPasses, - llvm::Optional mbOptLevel, llvm::TargetMachine *targetMachine, - unsigned optPassesInsertPos) { - return [llvmPasses, mbOptLevel, optPassesInsertPos, - targetMachine](llvm::Module *m) -> llvm::Error { - llvm::legacy::PassManager modulePM; - llvm::legacy::FunctionPassManager funcPM(m); - - bool insertOptPasses = mbOptLevel.hasValue(); - for (unsigned i = 0, e = llvmPasses.size(); i < e; ++i) { - const auto *passInfo = llvmPasses[i]; - if (!passInfo->getNormalCtor()) - continue; - - if (insertOptPasses && optPassesInsertPos == i) { - populatePassManagers(modulePM, funcPM, mbOptLevel.getValue(), 0, - targetMachine); - insertOptPasses = false; - } - - auto *pass = passInfo->createPass(); - if (!pass) - return llvm::make_error( - "could not create pass " + passInfo->getPassName(), - llvm::inconvertibleErrorCode()); - modulePM.add(pass); + TargetMachine *targetMachine) { + return [optLevel, sizeLevel, targetMachine](Module *m) -> Error { + Optional ol = mapToLevel(optLevel, sizeLevel); + if (!ol) { + return make_error( + formatv("invalid optimization/size level {0}/{1}", optLevel, + sizeLevel) + .str(), + inconvertibleErrorCode()); } - - if (insertOptPasses) - populatePassManagers(modulePM, funcPM, mbOptLevel.getValue(), 0, - targetMachine); - - runPasses(modulePM, funcPM, *m); - return llvm::Error::success(); + LoopAnalysisManager lam; + FunctionAnalysisManager fam; + CGSCCAnalysisManager cgam; + ModuleAnalysisManager mam; + + PassBuilder pb(targetMachine); + + pb.registerModuleAnalyses(mam); + pb.registerCGSCCAnalyses(cgam); + pb.registerFunctionAnalyses(fam); + pb.registerLoopAnalyses(lam); + pb.crossRegisterProxies(lam, fam, cgam, mam); + + ModulePassManager mpm; + if (*ol == OptimizationLevel::O0) + mpm.addPass(pb.buildO0DefaultPipeline(*ol)); + else + mpm.addPass(pb.buildPerModuleDefaultPipeline(*ol)); + + mpm.run(*m, mam); + return Error::success(); }; } diff --git a/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp b/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp --- a/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp +++ b/mlir/tools/mlir-cpu-runner/mlir-cpu-runner.cpp @@ -26,7 +26,6 @@ llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmParser(); - mlir::initializeLLVMPasses(); mlir::DialectRegistry registry; mlir::registerAllToLLVMIRTranslations(registry); diff --git a/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp b/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp --- a/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp +++ b/mlir/tools/mlir-spirv-cpu-runner/mlir-spirv-cpu-runner.cpp @@ -90,7 +90,6 @@ llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - mlir::initializeLLVMPasses(); mlir::JitRunnerConfig jitRunnerConfig; jitRunnerConfig.mlirTransformer = runMLIRPasses; diff --git a/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp b/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp --- a/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp +++ b/mlir/tools/mlir-vulkan-runner/mlir-vulkan-runner.cpp @@ -67,7 +67,6 @@ llvm::InitLLVM y(argc, argv); llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - mlir::initializeLLVMPasses(); mlir::JitRunnerConfig jitRunnerConfig; jitRunnerConfig.mlirTransformer = runMLIRPasses;