From c32d2d1f2951ee21c1b675405fd8de11dd25f986 Mon Sep 17 00:00:00 2001 From: tedj Date: Thu, 23 Apr 2026 08:19:22 -0600 Subject: [PATCH] [flang] Add the MLIR pass pipelines for dumping (#183144) The flang driver never registered passes in the MLIR pass registry, so --mlir-print-ir-before= always failed with `Cannot find option`. This commit adds pass registration calls before CLI option parsing in the -mmlir handler such that all ~30 pipeline passes are now selectable. --- flang/docs/Overview.md | 9 +++++- .../flang/Optimizer/Passes/Pipelines.h | 4 +++ flang/lib/FrontendTool/CMakeLists.txt | 1 + .../ExecuteCompilerInvocation.cpp | 3 ++ flang/lib/Optimizer/Passes/CMakeLists.txt | 5 ++++ flang/lib/Optimizer/Passes/Pipelines.cpp | 30 +++++++++++++++++++ flang/test/Driver/mmlir-print-ir.f90 | 13 ++++++++ flang/test/Fir/print-ir-pass.fir | 15 ++++++++++ flang/tools/fir-opt/CMakeLists.txt | 1 + flang/tools/fir-opt/fir-opt.cpp | 11 +++---- 10 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 flang/test/Driver/mmlir-print-ir.f90 create mode 100644 flang/test/Fir/print-ir-pass.fir diff --git a/flang/docs/Overview.md b/flang/docs/Overview.md index 77ed21c021f8..64df20efd189 100644 --- a/flang/docs/Overview.md +++ b/flang/docs/Overview.md @@ -180,8 +180,15 @@ perform various optimizations and transformations. The final pass creates an LLVM IR representation of the program. **Commands:** - - `flang -mmlir --mlir-print-ir-after-all -S src.f90` dumps the FIR code after each pass to standard error - `flang -fc1 -emit-llvm src.f90` dumps the LLVM IR to src.ll + - `flang -mmlir --mlir-print-ir-after-all -S src.f90` dumps the FIR code after each pass to standard error + - `flang -mmlir --mlir-print-ir-before= -S src.f90` dumps the FIR code before a specific pass to standard error + - `flang -mmlir --mlir-print-ir-after= -S src.f90` dumps the FIR code after a specific pass to standard error + +Note: The exact set of passes depends on compilation options. For example, +`stack-arrays` only appears when `-fstack-arrays` is enabled. To see the +complete list for a given compilation, use `--mlir-print-ir-before-all` and +look at the `IR Dump Before` headers. ## Object code generation and linking diff --git a/flang/include/flang/Optimizer/Passes/Pipelines.h b/flang/include/flang/Optimizer/Passes/Pipelines.h index 04eca81daf05..63fbdc37073b 100644 --- a/flang/include/flang/Optimizer/Passes/Pipelines.h +++ b/flang/include/flang/Optimizer/Passes/Pipelines.h @@ -117,6 +117,10 @@ void addLLVMDialectToLLVMPass(mlir::PassManager &pm, llvm::raw_ostream &output); /// Use inliner extension point callback to register the default inliner pass. void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config); +/// Register the passes used in Flang's MLIR pass pipeline +/// e.g. --mlir-print-ir-before= and similar. +void registerFlangPipelinePasses(); + /// Create a pass pipeline for running default optimization passes for /// incremental conversion of FIR. /// diff --git a/flang/lib/FrontendTool/CMakeLists.txt b/flang/lib/FrontendTool/CMakeLists.txt index 666fab1a6e2c..323d2e73e9a3 100644 --- a/flang/lib/FrontendTool/CMakeLists.txt +++ b/flang/lib/FrontendTool/CMakeLists.txt @@ -8,6 +8,7 @@ add_flang_library(flangFrontendTool LINK_LIBS flangFrontend + flangPasses LINK_COMPONENTS Option diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 429a98416daf..a807b86eaaa6 100644 --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -18,6 +18,7 @@ #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendActions.h" #include "flang/Frontend/FrontendPluginRegistry.h" +#include "flang/Optimizer/Passes/Pipelines.h" #include "mlir/IR/AsmState.h" #include "mlir/IR/MLIRContext.h" @@ -207,6 +208,8 @@ bool executeCompilerInvocation(CompilerInstance *flang) { // Honor -mmlir. This should happen AFTER plugins have been loaded! if (!flang->getFrontendOpts().mlirArgs.empty()) { + fir::registerFlangPipelinePasses(); // Must be called before + // mlir::registerPassManagerCLOptions() mlir::registerMLIRContextCLOptions(); mlir::registerPassManagerCLOptions(); mlir::registerAsmPrinterCLOptions(); diff --git a/flang/lib/Optimizer/Passes/CMakeLists.txt b/flang/lib/Optimizer/Passes/CMakeLists.txt index 1c19a5765aff..8d3c4f5cd05a 100644 --- a/flang/lib/Optimizer/Passes/CMakeLists.txt +++ b/flang/lib/Optimizer/Passes/CMakeLists.txt @@ -7,6 +7,7 @@ add_flang_library(flangPasses LINK_LIBS FIRCodeGen + FIROpenACCTransforms FIRTransforms FlangOpenMPTransforms FortranSupport @@ -18,6 +19,10 @@ add_flang_library(flangPasses MLIR_LIBS ${dialect_libs} ${extension_libs} + MLIRComplexToStandard + MLIRLLVMIRTransforms + MLIRMathToFuncs + MLIRMathToLLVM MLIRPass MLIRReconcileUnrealizedCasts MLIRSCFToControlFlow diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 4c48b7a75d83..54a8ba5dde0c 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -10,6 +10,9 @@ /// common to flang and the test tools. #include "flang/Optimizer/Passes/Pipelines.h" +#include "flang/Optimizer/OpenACC/Passes.h" +#include "mlir/Conversion/Passes.h" +#include "mlir/Dialect/LLVMIR/Transforms/Passes.h" #include "llvm/Support/CommandLine.h" /// Force setting the no-alias attribute on fuction arguments when possible. @@ -459,4 +462,31 @@ void createMLIRToLLVMPassPipeline(mlir::PassManager &pm, }); } +/// Register the passes used in flang's MLIR pass pipeline so that +/// --mlir-print-ir-before= and --mlir-print-ir-after= work. +/// Must be called BEFORE mlir::registerPassManagerCLOptions() because +/// that function creates the PassNameCLParser which snapshots the pass +/// registry during initialization. +void registerFlangPipelinePasses() { + // MLIR core passes used in the pipeline. + mlir::registerCSEPass(); + mlir::registerCanonicalizerPass(); + mlir::registerInlinerPass(); + + // MLIR conversion passes used in the pipeline. + mlir::registerSCFToControlFlowPass(); + mlir::registerConvertMathToFuncs(); + mlir::registerConvertComplexToStandardPass(); + mlir::registerConvertMathToLLVMPass(); + mlir::LLVM::registerLLVMAddComdats(); + mlir::registerReconcileUnrealizedCastsPass(); + + // FIR, HLFIR, and OpenMP passes. + fir::registerOptCodeGenPasses(); + fir::registerOptTransformPasses(); + hlfir::registerHLFIRPasses(); + flangomp::registerFlangOpenMPPasses(); + fir::acc::registerFIROpenACCPasses(); +} + } // namespace fir diff --git a/flang/test/Driver/mmlir-print-ir.f90 b/flang/test/Driver/mmlir-print-ir.f90 new file mode 100644 index 000000000000..140fef10710c --- /dev/null +++ b/flang/test/Driver/mmlir-print-ir.f90 @@ -0,0 +1,13 @@ +! Verify that --mlir-print-ir-before= and --mlir-print-ir-after= +! work for registered passes. + +! RUN: %flang_fc1 -emit-llvm -mmlir --mlir-print-ir-before=cse -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=BEFORE +! RUN: %flang_fc1 -emit-llvm -mmlir --mlir-print-ir-after=cse -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=AFTER + +! BEFORE: IR Dump Before CSE +! BEFORE: func.func @_QQmain + +! AFTER: IR Dump After CSE +! AFTER: func.func @_QQmain + +end program diff --git a/flang/test/Fir/print-ir-pass.fir b/flang/test/Fir/print-ir-pass.fir new file mode 100644 index 000000000000..6c308570a293 --- /dev/null +++ b/flang/test/Fir/print-ir-pass.fir @@ -0,0 +1,15 @@ +// Verify that --mlir-print-ir-before and --mlir-print-ir-after work in fir-opt +// for FIR/HLFIR-specific passes registered by registerFlangPipelinePasses(). + +// RUN: fir-opt --convert-hlfir-to-fir --mlir-print-ir-before=convert-hlfir-to-fir %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=BEFORE +// RUN: fir-opt --convert-hlfir-to-fir --mlir-print-ir-after=convert-hlfir-to-fir %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=AFTER + +// BEFORE: IR Dump Before ConvertHLFIRtoFIR +// BEFORE: func.func @dummy() + +// AFTER: IR Dump After ConvertHLFIRtoFIR +// AFTER: func.func @dummy() + +func.func @dummy() { + return +} diff --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt index e735c2c2ff1a..2697f74c2f0b 100644 --- a/flang/tools/fir-opt/CMakeLists.txt +++ b/flang/tools/fir-opt/CMakeLists.txt @@ -28,6 +28,7 @@ target_link_libraries(fir-opt PRIVATE FlangOpenMPTransforms FIRAnalysis MIFDialect + flangPasses ${test_libs} ) diff --git a/flang/tools/fir-opt/fir-opt.cpp b/flang/tools/fir-opt/fir-opt.cpp index 67d07eee1f4f..7789d396f6e5 100644 --- a/flang/tools/fir-opt/fir-opt.cpp +++ b/flang/tools/fir-opt/fir-opt.cpp @@ -16,6 +16,7 @@ #include "flang/Optimizer/HLFIR/Passes.h" #include "flang/Optimizer/OpenACC/Passes.h" #include "flang/Optimizer/OpenMP/Passes.h" +#include "flang/Optimizer/Passes/Pipelines.h" #include "flang/Optimizer/Support/InitFIR.h" #include "flang/Optimizer/Transforms/Passes.h" @@ -37,11 +38,7 @@ void registerTestOpenACC(); int main(int argc, char **argv) { fir::support::registerMLIRPassesForFortranTools(); - fir::registerOptCodeGenPasses(); - fir::registerOptTransformPasses(); - hlfir::registerHLFIRPasses(); - flangomp::registerFlangOpenMPPasses(); - fir::acc::registerFIROpenACCPasses(); + fir::registerFlangPipelinePasses(); #ifdef FLANG_INCLUDE_TESTS fir::test::registerTestFIRAliasAnalysisPass(); fir::test::registerTestFIROpenACCInterfacesPass(); @@ -52,6 +49,6 @@ int main(int argc, char **argv) { fir::support::registerDialects(registry); registry.insert(); fir::support::addFIRExtensions(registry); - return failed(MlirOptMain(argc, argv, "FIR modular optimizer driver\n", - registry)); + return failed( + MlirOptMain(argc, argv, "FIR modular optimizer driver\n", registry)); }