-
Notifications
You must be signed in to change notification settings - Fork 11.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flang] Added extension point callbacks to default FIR optimizer pipeline. #90674
Conversation
@llvm/pr-subscribers-flang-driver Author: Vijay Kandiah (VijayKandiah) ChangesThis change inserts a few extension point callbacks in the DefaultFIROptimizerPassPipeline. As an example usage of callbacks in the FIR optimizer pipeline, the FIRInlinerCallback is now used to register the default MLIR inliner pass in flang-new, tco, and bbc compilation flows. Other compilation flows can use these callbacks to add extra passes at different points of the pass pipeline. Full diff: https://github.com/llvm/llvm-project/pull/90674.diff 5 Files Affected:
diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc
index bd60c66b61ad24..d1602cde9ee5fe 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<mlir::OpPassManager> pipelines;
+ // The default inliner pass adds the canonicalizer pass with the default
+ // configuration. Create the inliner pass with tco config.
+ 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<mlir::OpPassManager> 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,7 +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,
+ MLIRToLLVMPassPipelineConfig &config,
llvm::StringRef inputFilename = {}) {
fir::createHLFIRToFIRPassPipeline(pm, config.OptLevel);
diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h
index cebdd6d181c364..f79520707714d7 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<void(mlir::PassManager &, llvm::OptimizationLevel)>
+ &C) {
+ FIROptEarlyEPCallbacks.push_back(C);
+ }
+
+ void registerFIRInlinerCallback(
+ const std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>
+ &C) {
+ FIRInlinerCallback.push_back(C);
+ }
+
+ void registerFIROptLastEPCallbacks(
+ const std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>
+ &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<void(mlir::PassManager &, llvm::OptimizationLevel)>, 1>
+ FIROptEarlyEPCallbacks;
+
+ llvm::SmallVector<
+ std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>, 1>
+ FIRInlinerCallback;
+
+ llvm::SmallVector<
+ std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>, 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 531616e7926aca..36536c77499989 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 a0870d3649c2e4..4c986fb816f06e 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<Fortran::lower::VerifierPass>());
// 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 45284e74f58456..399ea1362fda47 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());
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Looks like you need to run clang-format on your change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Vijay for the patch. I have a couple of minor questions inline.
It might be good to document the avaliability of these callbacks in flang/docs. Is this intended for Drivers (upstream/downstream) to register callbacks statically? Or is the plan to allow drivers to load FIR/MLIR passes dynamically with this feature?
[](mlir::PassManager &pm, llvm::OptimizationLevel level) { | ||
llvm::StringMap<mlir::OpPassManager> pipelines; | ||
// The default inliner pass adds the canonicalizer pass with the default | ||
// configuration. Create the inliner pass with tco config. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If both the flang driver and tco register the pass, can you either mention both the flang driver and tco or drop that line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out, I dropped the line in my latest commit.
@@ -802,6 +802,7 @@ void CodeGenAction::generateLLVMIR() { | |||
pm.enableVerifier(/*verifyPasses=*/true); | |||
|
|||
MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts); | |||
fir::registerDefaultInlinerPass(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the pass always registered and executed (irrespective of the optimization level) with the flang-driver? Is that expected and different from tco?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that was the original behavior to register and execute the inliner pass regardless of optimization level with flang-new, tco, and bbc. The changes preserve this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused by the reference to the O2 optimizer pipelines in both bbc and tco. Thanks for clarifying.
Thanks Kiran for the feedback. Could you please clarify what you mean by statically vs dynamically registering callbacks? I plan to document these callbacks here with the next commit before merging. |
By dynamic I meant something like what is done with the pass-plugin option. This allows to load a pass from a shared object file during compilation and need not be statically listed in the upstream or downstream source code of the compiler. |
Ah I see, thanks for clarifying. These callbacks currently provide a static way to extend the pass pipeline by upstream or downstream driver source code. However, I see this change as a step in the right direction towards having a dynamic way to load passes with something like a FIR/MLIR pass-plugin option that uses these callbacks to do so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
This change inserts a few extension point callbacks in the DefaultFIROptimizerPassPipeline. As an example usage of callbacks in the FIR optimizer pipeline, the FIRInlinerCallback is now used to register the default MLIR inliner pass in flang-new, tco, and bbc compilation flows. Other compilation flows can use these callbacks to add extra passes at different points of the pass pipeline.