[Mlir-commits] [mlir] b1b84a6 - Pretty print on -dump-pass-pipeline (#143223)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sun Jun 8 12:23:42 PDT 2025


Author: Jeremy Kun
Date: 2025-06-08T12:23:38-07:00
New Revision: b1b84a629d5a6d7ed3d4f05077c1db8b6898115b

URL: https://github.com/llvm/llvm-project/commit/b1b84a629d5a6d7ed3d4f05077c1db8b6898115b
DIFF: https://github.com/llvm/llvm-project/commit/b1b84a629d5a6d7ed3d4f05077c1db8b6898115b.diff

LOG: Pretty print on -dump-pass-pipeline (#143223)

This PR makes `dump-pass-pipeline` pretty-print the dumped pipeline. For
large pipelines the current behavior produces a wall of text that is
hard to visually navigate.

For the command

```bash
mlir-opt --pass-pipeline="builtin.module(flatten-memref, expand-strided-metadata,func.func(arith-expand,func.func(affine-scalrep)))" --dump-pass-pipeline
```

Before:

```bash
Pass Manager with 3 passes:
builtin.module(flatten-memref,expand-strided-metadata,func.func(arith-expand{include-bf16=false include-f8e8m0=false},func.func(affine-scalrep)))
```

After:

```bash
Pass Manager with 3 passes:
builtin.module(
  flatten-memref,
  expand-strided-metadata,
  func.func(
    arith-expand{include-bf16=false include-f8e8m0=false},
    func.func(
      affine-scalrep
    )
  )
)
```

Another nice feature of this is that the pretty-printed string can still
be copy/pasted into `-pass-pipeline` using a quote:

```bash
$ bin/mlir-opt --dump-pass-pipeline test.mlir --pass-pipeline='
builtin.module(
  flatten-memref,
  expand-strided-metadata,
  func.func(
    arith-expand{include-bf16=false include-f8e8m0=false},
    func.func(
      affine-scalrep
    )
  )
)'
```

---------

Co-authored-by: Jeremy Kun <j2kun at users.noreply.github.com>

Added: 
    

Modified: 
    mlir/include/mlir/Pass/Pass.h
    mlir/include/mlir/Pass/PassManager.h
    mlir/lib/Pass/Pass.cpp
    mlir/lib/Pass/PassCrashRecovery.cpp
    mlir/test/Pass/pipeline-options-parsing.mlir
    mlir/test/Pass/pipeline-parsing.mlir
    mlir/test/Pass/run-reproducer.mlir
    mlir/test/Transforms/composite-pass.mlir
    mlir/test/Transforms/inlining-dump-default-pipeline.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Pass/Pass.h b/mlir/include/mlir/Pass/Pass.h
index 9e8ba7158f1b3..16893c6db87b1 100644
--- a/mlir/include/mlir/Pass/Pass.h
+++ b/mlir/include/mlir/Pass/Pass.h
@@ -118,8 +118,9 @@ class Pass {
                     function_ref<LogicalResult(const Twine &)> errorHandler);
 
   /// Prints out the pass in the textual representation of pipelines. If this is
-  /// an adaptor pass, print its pass managers.
-  void printAsTextualPipeline(raw_ostream &os);
+  /// an adaptor pass, print its pass managers. When `pretty` is true, the
+  /// printed pipeline is formatted for readability.
+  void printAsTextualPipeline(raw_ostream &os, bool pretty = false);
 
   //===--------------------------------------------------------------------===//
   // Statistics

diff  --git a/mlir/include/mlir/Pass/PassManager.h b/mlir/include/mlir/Pass/PassManager.h
index 2287b0a33f47d..6e59b0f32ac6f 100644
--- a/mlir/include/mlir/Pass/PassManager.h
+++ b/mlir/include/mlir/Pass/PassManager.h
@@ -140,10 +140,12 @@ class OpPassManager {
   detail::OpPassManagerImpl &getImpl();
 
   /// Prints out the passes of the pass manager as the textual representation
-  /// of pipelines.
+  /// of pipelines. When `pretty` is true, the printed pipeline is formatted
+  /// for readability.
+  ///
   /// Note: The quality of the string representation depends entirely on the
   /// the correctness of per-pass overrides of Pass::printAsTextualPipeline.
-  void printAsTextualPipeline(raw_ostream &os) const;
+  void printAsTextualPipeline(raw_ostream &os, bool pretty = false) const;
 
   /// Raw dump of the pass manager to llvm::errs().
   void dump();

diff  --git a/mlir/lib/Pass/Pass.cpp b/mlir/lib/Pass/Pass.cpp
index e0e9b5f54042a..d1371d2b508f4 100644
--- a/mlir/lib/Pass/Pass.cpp
+++ b/mlir/lib/Pass/Pass.cpp
@@ -18,6 +18,7 @@
 #include "mlir/IR/Threading.h"
 #include "mlir/IR/Verifier.h"
 #include "mlir/Support/FileUtilities.h"
+#include "mlir/Support/IndentedOstream.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
@@ -80,14 +81,19 @@ void Pass::copyOptionValuesFrom(const Pass *other) {
 }
 
 /// Prints out the pass in the textual representation of pipelines. If this is
-/// an adaptor pass, print its pass managers.
-void Pass::printAsTextualPipeline(raw_ostream &os) {
+/// an adaptor pass, print its pass managers. When `pretty` is true, the
+/// printed pipeline is formatted for readability.
+void Pass::printAsTextualPipeline(raw_ostream &os, bool pretty) {
   // Special case for adaptors to print its pass managers.
   if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(this)) {
     llvm::interleave(
         adaptor->getPassManagers(),
-        [&](OpPassManager &pm) { pm.printAsTextualPipeline(os); },
-        [&] { os << ","; });
+        [&](OpPassManager &pm) { pm.printAsTextualPipeline(os, pretty); },
+        [&] {
+          os << ",";
+          if (pretty)
+            os << "\n";
+        });
     return;
   }
   // Otherwise, print the pass argument followed by its options. If the pass
@@ -390,27 +396,51 @@ StringRef OpPassManager::getOpAnchorName() const {
 }
 
 /// Prints out the passes of the pass manager as the textual representation
-/// of pipelines.
+/// of pipelines. When `pretty` is true, the printed pipeline is formatted for
+/// readability.
 void printAsTextualPipeline(
-    raw_ostream &os, StringRef anchorName,
-    const llvm::iterator_range<OpPassManager::pass_iterator> &passes) {
+    raw_indented_ostream &os, StringRef anchorName,
+    const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
+    bool pretty = false) {
   os << anchorName << "(";
+  if (pretty) {
+    os << "\n";
+    os.indent();
+  }
   llvm::interleave(
-      passes, [&](mlir::Pass &pass) { pass.printAsTextualPipeline(os); },
-      [&]() { os << ","; });
+      passes,
+      [&](mlir::Pass &pass) { pass.printAsTextualPipeline(os, pretty); },
+      [&]() {
+        os << ",";
+        if (pretty)
+          os << "\n";
+      });
+  if (pretty) {
+    os << "\n";
+    os.unindent();
+  }
   os << ")";
 }
-void OpPassManager::printAsTextualPipeline(raw_ostream &os) const {
+void printAsTextualPipeline(
+    raw_ostream &os, StringRef anchorName,
+    const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
+    bool pretty) {
+  raw_indented_ostream indentedOS(os);
+  printAsTextualPipeline(indentedOS, anchorName, passes, pretty);
+}
+void OpPassManager::printAsTextualPipeline(raw_ostream &os, bool pretty) const {
   StringRef anchorName = getOpAnchorName();
+  raw_indented_ostream indentedOS(os);
   ::printAsTextualPipeline(
-      os, anchorName,
+      indentedOS, anchorName,
       {MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.begin(),
-       MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end()});
+       MutableArrayRef<std::unique_ptr<Pass>>{impl->passes}.end()},
+      pretty);
 }
 
 void OpPassManager::dump() {
   llvm::errs() << "Pass Manager with " << impl->passes.size() << " passes:\n";
-  printAsTextualPipeline(llvm::errs());
+  printAsTextualPipeline(llvm::errs(), /*pretty=*/true);
   llvm::errs() << "\n";
 }
 
@@ -466,7 +496,6 @@ llvm::hash_code OpPassManager::hash() {
   return hashCode;
 }
 
-
 //===----------------------------------------------------------------------===//
 // OpToOpPassAdaptor
 //===----------------------------------------------------------------------===//
@@ -871,7 +900,8 @@ LogicalResult PassManager::run(Operation *op) {
   // Initialize all of the passes within the pass manager with a new generation.
   llvm::hash_code newInitKey = context->getRegistryHash();
   llvm::hash_code pipelineKey = hash();
-  if (newInitKey != initializationKey || pipelineKey != pipelineInitializationKey) {
+  if (newInitKey != initializationKey ||
+      pipelineKey != pipelineInitializationKey) {
     if (failed(initialize(context, impl->initializationGeneration + 1)))
       return failure();
     initializationKey = newInitKey;

diff  --git a/mlir/lib/Pass/PassCrashRecovery.cpp b/mlir/lib/Pass/PassCrashRecovery.cpp
index 8c6d865cb31dd..b048ff9462392 100644
--- a/mlir/lib/Pass/PassCrashRecovery.cpp
+++ b/mlir/lib/Pass/PassCrashRecovery.cpp
@@ -443,7 +443,8 @@ makeReproducerStreamFactory(StringRef outputFile) {
 
 void printAsTextualPipeline(
     raw_ostream &os, StringRef anchorName,
-    const llvm::iterator_range<OpPassManager::pass_iterator> &passes);
+    const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
+    bool pretty = false);
 
 std::string mlir::makeReproducer(
     StringRef anchorName,

diff  --git a/mlir/test/Pass/pipeline-options-parsing.mlir b/mlir/test/Pass/pipeline-options-parsing.mlir
index b8cd605a83a2b..9385d353faf95 100644
--- a/mlir/test/Pass/pipeline-options-parsing.mlir
+++ b/mlir/test/Pass/pipeline-options-parsing.mlir
@@ -38,11 +38,71 @@
 
 // CHECK_1: test-options-pass{enum=zero list={1,2,3,4,5} string=nested_pipeline{arg1=10 arg2=" {} " arg3=true} string-list={a,b,c,d}}
 // CHECK_2: test-options-pass{enum=one list={1} string= string-list={a,b}}
-// CHECK_3: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list={3} string= }),func.func(test-options-pass{enum=one list={1,2,3,4} string= })))
-// CHECK_4: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list={3} string= }),func.func(test-options-pass{enum=one list={1,2,3,4} string=foobar })))
-// CHECK_5: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list={3} string= }),func.func(test-options-pass{enum=one list={1,2,3,4} string={foo bar baz} })))
-// CHECK_6: builtin.module(builtin.module(func.func(test-options-pass{enum=zero list={3} string= }),func.func(test-options-pass{enum=one list={1,2,3,4} string=foo"bar"baz })))
-// CHECK_7{LITERAL}: builtin.module(func.func(test-options-super-pass{list={{enum=zero list={1} string=foo },{enum=one list={2} string=bar },{enum=two list={3} string=baz }}}))
-// CHECK_8{LITERAL}: builtin.module(func.func(test-options-super-pass{list={{enum=zero list={1} string=foo },{enum=one string=bar }}}))
-// CHECK_9: builtin.module(func.func(test-options-pass{enum=zero  string= string-list={}}))
-// CHECK_10: builtin.module(func.func(test-options-pass{enum=zero  string= string-list={,}}))
+
+// CHECK_3:      builtin.module(
+// CHECK_3-NEXT:   builtin.module(
+// CHECK_3-NEXT:     func.func(
+// CHECK_3-NEXT:       test-options-pass{enum=zero list={3} string= }
+// CHECK_3-NEXT:     ),
+// CHECK_3-NEXT:     func.func(
+// CHECK_3-NEXT:       test-options-pass{enum=one list={1,2,3,4} string= }
+// CHECK_3-NEXT:     )
+// CHECK_3-NEXT:   )
+// CHECK_3-NEXT: )
+
+// CHECK_4:      builtin.module(
+// CHECK_4-NEXT:   builtin.module(
+// CHECK_4-NEXT:     func.func(
+// CHECK_4-NEXT:       test-options-pass{enum=zero list={3} string= }
+// CHECK_4-NEXT:     ),
+// CHECK_4-NEXT:     func.func(
+// CHECK_4-NEXT:       test-options-pass{enum=one list={1,2,3,4} string=foobar }
+// CHECK_4-NEXT:     )
+// CHECK_4-NEXT:   )
+// CHECK_4-NEXT: )
+
+// CHECK_5:      builtin.module(
+// CHECK_5-NEXT:   builtin.module(
+// CHECK_5-NEXT:     func.func(
+// CHECK_5-NEXT:       test-options-pass{enum=zero list={3} string= }
+// CHECK_5-NEXT:     ),
+// CHECK_5-NEXT:     func.func(
+// CHECK_5-NEXT:       test-options-pass{enum=one list={1,2,3,4} string={foo bar baz} }
+// CHECK_5-NEXT:     )
+// CHECK_5-NEXT:   )
+// CHECK_5-NEXT: )
+
+// CHECK_6:      builtin.module(
+// CHECK_6-NEXT:   builtin.module(
+// CHECK_6-NEXT:     func.func(
+// CHECK_6-NEXT:       test-options-pass{enum=zero list={3} string= }
+// CHECK_6-NEXT:     ),
+// CHECK_6-NEXT:     func.func(
+// CHECK_6-NEXT:       test-options-pass{enum=one list={1,2,3,4} string=foo"bar"baz }
+// CHECK_6-NEXT:     )
+// CHECK_6-NEXT:   )
+// CHECK_6-NEXT: )
+
+// CHECK_7{LITERAL}:      builtin.module(
+// CHECK_7{LITERAL}-NEXT:   func.func(
+// CHECK_7{LITERAL}-NEXT:     test-options-super-pass{list={{enum=zero list={1} string=foo },{enum=one list={2} string=bar },{enum=two list={3} string=baz }}}
+// CHECK_7{LITERAL}-NEXT:   )
+// CHECK_7{LITERAL}-NEXT: )
+
+// CHECK_8{LITERAL}:      builtin.module(
+// CHECK_8{LITERAL}-NEXT:   func.func(
+// CHECK_8{LITERAL}-NEXT:     test-options-super-pass{list={{enum=zero list={1} string=foo },{enum=one string=bar }}}
+// CHECK_8{LITERAL}-NEXT:   )
+// CHECK_8{LITERAL}-NEXT: )
+
+// CHECK_9:      builtin.module(
+// CHECK_9-NEXT:   func.func(
+// CHECK_9-NEXT:     test-options-pass{enum=zero  string= string-list={}}
+// CHECK_9-NEXT:   )
+// CHECK_9-NEXT: )
+
+// CHECK_10:      builtin.module(
+// CHECK_10-NEXT:   func.func(
+// CHECK_10-NEXT:     test-options-pass{enum=zero  string= string-list={,}}
+// CHECK_10-NEXT:   )
+// CHECK_10-NEXT: )

diff  --git a/mlir/test/Pass/pipeline-parsing.mlir b/mlir/test/Pass/pipeline-parsing.mlir
index f41553d2669f0..7f368c6df2af5 100644
--- a/mlir/test/Pass/pipeline-parsing.mlir
+++ b/mlir/test/Pass/pipeline-parsing.mlir
@@ -21,7 +21,9 @@
 // CHECK_ERROR_7: can't run 'wrong-op' pass manager on 'builtin.module' op
 
 // RUN: mlir-opt %s -pass-pipeline='any(cse)' -dump-pass-pipeline 2>&1 | FileCheck %s -check-prefix=CHECK_ROUNDTRIP
-// CHECK_ROUNDTRIP: any(cse)
+// CHECK_ROUNDTRIP: any(
+// CHECK_ROUNDTRIP-NEXT: cse
+// CHECK_ROUNDTRIP-NEXT: )
 
 func.func @foo() {
   return

diff  --git a/mlir/test/Pass/run-reproducer.mlir b/mlir/test/Pass/run-reproducer.mlir
index bf3ab2dae2ff8..d2daceab163de 100644
--- a/mlir/test/Pass/run-reproducer.mlir
+++ b/mlir/test/Pass/run-reproducer.mlir
@@ -14,7 +14,12 @@ func.func @bar() {
   external_resources: {
     mlir_reproducer: {
       verify_each: true,
-      // CHECK:  builtin.module(func.func(cse,canonicalize{ max-iterations=1 max-num-rewrites=-1 region-simplify=normal test-convergence=false top-down=false}))
+      // CHECK:       builtin.module(
+      // CHECK-NEXT:    func.func(
+      // CHECK-NEXT:      cse,
+      // CHECK-NEXT:      canonicalize{ max-iterations=1 max-num-rewrites=-1 region-simplify=normal test-convergence=false top-down=false}
+      // CHECK-NEXT:    )
+      // CHECK-NEXT:  )
       pipeline: "builtin.module(func.func(cse,canonicalize{max-iterations=1 max-num-rewrites=-1 region-simplify=normal top-down=false}))",
       disable_threading: true
     }

diff  --git a/mlir/test/Transforms/composite-pass.mlir b/mlir/test/Transforms/composite-pass.mlir
index 75587edd5b96d..65764a96a4016 100644
--- a/mlir/test/Transforms/composite-pass.mlir
+++ b/mlir/test/Transforms/composite-pass.mlir
@@ -2,8 +2,9 @@
 // RUN: mlir-opt %s --log-actions-to=- --composite-fixed-point-pass='name=TestCompositePass pipeline=any(canonicalize,cse)' -split-input-file | FileCheck %s
 
 // Ensure the composite pass correctly prints its options.
-// PIPELINE:      builtin.module(composite-fixed-point-pass{max-iterations=10 name=TestCompositePass
-// PIPELINE-SAME: pipeline=canonicalize{ max-iterations=10 max-num-rewrites=-1 region-simplify=normal test-convergence=false top-down=true},cse})
+// PIPELINE:      builtin.module(
+// PIPELINE-NEXT:    composite-fixed-point-pass{max-iterations=10 name=TestCompositePass
+// PIPELINE-SAME: pipeline=canonicalize{ max-iterations=10 max-num-rewrites=-1 region-simplify=normal test-convergence=false top-down=true},cse}
 
 // CHECK-LABEL: running `TestCompositePass`
 //       CHECK: running `Canonicalizer`

diff  --git a/mlir/test/Transforms/inlining-dump-default-pipeline.mlir b/mlir/test/Transforms/inlining-dump-default-pipeline.mlir
index 4f8638054206e..ef5fac49c6ce2 100644
--- a/mlir/test/Transforms/inlining-dump-default-pipeline.mlir
+++ b/mlir/test/Transforms/inlining-dump-default-pipeline.mlir
@@ -1,2 +1,4 @@
 // RUN: mlir-opt %s -pass-pipeline="builtin.module(inline)" -dump-pass-pipeline 2>&1 | FileCheck %s
-// CHECK: builtin.module(inline{default-pipeline=canonicalize inlining-threshold=4294967295 max-iterations=4 })
+// CHECK:      builtin.module(
+// CHECK-NEXT:   inline{default-pipeline=canonicalize inlining-threshold=4294967295 max-iterations=4 }
+// CHECK-NEXT: )


        


More information about the Mlir-commits mailing list