Skip to content

Pretty print on -dump-pass-pipeline #143223

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

Merged
merged 5 commits into from
Jun 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions mlir/include/mlir/Pass/Pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions mlir/include/mlir/Pass/PassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
60 changes: 45 additions & 15 deletions mlir/lib/Pass/Pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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";
}

Expand Down Expand Up @@ -466,7 +496,6 @@ llvm::hash_code OpPassManager::hash() {
return hashCode;
}


//===----------------------------------------------------------------------===//
// OpToOpPassAdaptor
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion mlir/lib/Pass/PassCrashRecovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
76 changes: 68 additions & 8 deletions mlir/test/Pass/pipeline-options-parsing.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -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: )
4 changes: 3 additions & 1 deletion mlir/test/Pass/pipeline-parsing.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion mlir/test/Pass/run-reproducer.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
5 changes: 3 additions & 2 deletions mlir/test/Transforms/composite-pass.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
4 changes: 3 additions & 1 deletion mlir/test/Transforms/inlining-dump-default-pipeline.mlir
Original file line number Diff line number Diff line change
@@ -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: )
Loading