[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