diff --git a/flang/docs/FlangDriver.md b/flang/docs/FlangDriver.md index 351595ac0afdb..e1c1106212502 100644 --- a/flang/docs/FlangDriver.md +++ b/flang/docs/FlangDriver.md @@ -518,6 +518,16 @@ to re-analyze expressions and modify scope or symbols. You can check [Semantics.md](Semantics.md) for more details on how `ParseTree` is edited e.g. during the semantic checks. +## FIR Optimizer Pass Pipeline Extension Points + +The default FIR optimizer pass pipeline `createDefaultFIROptimizerPassPipeline` +in `flang/include/flang/Tools/CLOptions.inc` contains extension point callback +invocations `invokeFIROptEarlyEPCallbacks`, `invokeFIRInlinerCallback`, and +`invokeFIROptLastEPCallbacks` for Flang drivers to be able to insert additonal +passes at different points of the default pass pipeline. An example use of these +extension point callbacks is shown in `registerDefaultInlinerPass` to invoke the +default inliner pass in `flang-new`. + ## LLVM Pass Plugins Pass plugins are dynamic shared objects that consist of one or more LLVM IR diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc index bd60c66b61ad2..d5bcdd04f6fcc 100644 --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -232,12 +232,27 @@ inline void addExternalNameConversionPass( }); } +// Use inliner extension point callback to register the default inliner pass. +inline void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config) { + config.registerFIRInlinerCallback( + [](mlir::PassManager &pm, llvm::OptimizationLevel level) { + llvm::StringMap pipelines; + // The default inliner pass adds the canonicalizer pass with the default + // configuration. + pm.addPass(mlir::createInlinerPass( + pipelines, addCanonicalizerPassWithoutRegionSimplification)); + }); +} + /// Create a pass pipeline for running default optimization passes for /// incremental conversion of FIR. /// /// \param pm - MLIR pass manager that will hold the pipeline definition inline void createDefaultFIROptimizerPassPipeline( - mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &pc) { + mlir::PassManager &pm, MLIRToLLVMPassPipelineConfig &pc) { + // Early Optimizer EP Callback + pc.invokeFIROptEarlyEPCallbacks(pm, pc.OptLevel); + // simplify the IR mlir::GreedyRewriteConfig config; config.enableRegionSimplification = false; @@ -262,11 +277,9 @@ inline void createDefaultFIROptimizerPassPipeline( else fir::addMemoryAllocationOpt(pm); - // The default inliner pass adds the canonicalizer pass with the default - // configuration. Create the inliner pass with tco config. - llvm::StringMap pipelines; - pm.addPass(mlir::createInlinerPass( - pipelines, addCanonicalizerPassWithoutRegionSimplification)); + // FIR Inliner Callback + pc.invokeFIRInlinerCallback(pm, pc.OptLevel); + pm.addPass(fir::createSimplifyRegionLite()); pm.addPass(mlir::createCSEPass()); @@ -283,6 +296,9 @@ inline void createDefaultFIROptimizerPassPipeline( pm.addPass(mlir::createCanonicalizerPass(config)); pm.addPass(fir::createSimplifyRegionLite()); pm.addPass(mlir::createCSEPass()); + + // Last Optimizer EP Callback + pc.invokeFIROptLastEPCallbacks(pm, pc.OptLevel); } /// Create a pass pipeline for lowering from HLFIR to FIR @@ -375,8 +391,7 @@ inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, /// \param optLevel - optimization level used for creating FIR optimization /// passes pipeline inline void createMLIRToLLVMPassPipeline(mlir::PassManager &pm, - const MLIRToLLVMPassPipelineConfig &config, - llvm::StringRef inputFilename = {}) { + MLIRToLLVMPassPipelineConfig &config, llvm::StringRef inputFilename = {}) { fir::createHLFIRToFIRPassPipeline(pm, config.OptLevel); // Add default optimizer pass pipeline. diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index cebdd6d181c36..f79520707714d 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -20,11 +20,66 @@ #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/BuiltinOps.h" +#include "mlir/Pass/PassRegistry.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Passes/OptimizationLevel.h" +// Flang Extension Point Callbacks +class FlangEPCallBacks { +public: + void registerFIROptEarlyEPCallbacks( + const std::function + &C) { + FIROptEarlyEPCallbacks.push_back(C); + } + + void registerFIRInlinerCallback( + const std::function + &C) { + FIRInlinerCallback.push_back(C); + } + + void registerFIROptLastEPCallbacks( + const std::function + &C) { + FIROptLastEPCallbacks.push_back(C); + } + + void invokeFIROptEarlyEPCallbacks( + mlir::PassManager &pm, llvm::OptimizationLevel optLevel) { + for (auto &C : FIROptEarlyEPCallbacks) + C(pm, optLevel); + }; + + void invokeFIRInlinerCallback( + mlir::PassManager &pm, llvm::OptimizationLevel optLevel) { + for (auto &C : FIRInlinerCallback) + C(pm, optLevel); + }; + + void invokeFIROptLastEPCallbacks( + mlir::PassManager &pm, llvm::OptimizationLevel optLevel) { + for (auto &C : FIROptLastEPCallbacks) + C(pm, optLevel); + }; + +private: + llvm::SmallVector< + std::function, 1> + FIROptEarlyEPCallbacks; + + llvm::SmallVector< + std::function, 1> + FIRInlinerCallback; + + llvm::SmallVector< + std::function, 1> + FIROptLastEPCallbacks; +}; + /// Configuriation for the MLIR to LLVM pass pipeline. -struct MLIRToLLVMPassPipelineConfig { +struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks { explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level) { OptLevel = level; } diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 531616e7926ac..36536c7749998 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -802,6 +802,7 @@ void CodeGenAction::generateLLVMIR() { pm.enableVerifier(/*verifyPasses=*/true); MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts); + fir::registerDefaultInlinerPass(config); if (auto vsr = getVScaleRange(ci)) { config.VScaleMin = vsr->first; diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index a0870d3649c2e..4c986fb816f06 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -424,8 +424,9 @@ static mlir::LogicalResult convertFortranSourceToMLIR( pm.addPass(std::make_unique()); // Add O2 optimizer pass pipeline. - fir::createDefaultFIROptimizerPassPipeline( - pm, MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel::O2)); + MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2); + fir::registerDefaultInlinerPass(config); + fir::createDefaultFIROptimizerPassPipeline(pm, config); } if (mlir::succeeded(pm.run(mlirModule))) { diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp index 45284e74f5845..399ea1362fda4 100644 --- a/flang/tools/tco/tco.cpp +++ b/flang/tools/tco/tco.cpp @@ -140,6 +140,7 @@ compileFIR(const mlir::PassPipelineCLParser &passPipeline) { fir::createDefaultFIRCodeGenPassPipeline(pm, config); } else { // Run tco with O2 by default. + fir::registerDefaultInlinerPass(config); fir::createMLIRToLLVMPassPipeline(pm, config); } fir::addLLVMDialectToLLVMPass(pm, out.os());