Add ::printAsTextualPipeline to Pass and OpPassManager.

Allow printing out pipelines in a format that is as close as possible to the
textual pass pipeline format. Individual passes can override the print function
in order to format any options that may have been used to construct that pass.

PiperOrigin-RevId: 273813627
This commit is contained in:
MLIR Team 2019-10-09 13:48:38 -07:00 committed by A. Unique TensorFlower
parent 35bb732032
commit ae6946ec11
6 changed files with 53 additions and 10 deletions

View File

@ -427,6 +427,11 @@ Can also be specified as (via the `-pass-pipeline` flag):
$ mlir-opt foo.mlir -pass-pipeline='func(cse, canonicalize), lower-to-llvm'
```
In order to support round-tripping your pass to the textual representation using
`OpPassManager::printAsTextualPipeline(raw_ostream&)`, override
`Pass::printAsTextualPipeline(raw_ostream&)` to format your pass-name and
options in the format described above.
### Instance Specific Pass Options
Options may be specified for a parametric pass. Individual options are defined

View File

@ -69,6 +69,13 @@ public:
/// this is a generic OperationPass.
llvm::Optional<StringRef> getOpName() const { return opName; }
/// Prints out the pass in the textual representation of pipelines. If this is
/// an adaptor pass, print with the op_name(sub_pass,...) format.
/// Note: The default implementation uses the class name and does not respect
/// options used to construct the pass. Override this method to allow for your
/// pass to be to be round-trippable to the textual format.
virtual void printAsTextualPipeline(raw_ostream &os);
protected:
explicit Pass(const PassID *passID,
llvm::Optional<StringRef> opName = llvm::None)

View File

@ -80,6 +80,12 @@ public:
/// Returns the internal implementation instance.
detail::OpPassManagerImpl &getImpl();
/// Prints out the passes of the pass mangager as the textual representation
/// of pipelines.
/// 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);
private:
OpPassManager(OperationName name, bool disableThreads, bool verifyPasses);

View File

@ -42,6 +42,21 @@ using namespace mlir::detail;
/// single .o file.
void Pass::anchor() {}
/// Prints out the pass in the textual representation of pipelines. If this is
/// an adaptor pass, print with the op_name(sub_pass,...) format.
void Pass::printAsTextualPipeline(raw_ostream &os) {
// Special case for adaptors to use the 'op_name(sub_passes)' format.
if (auto *adaptor = getAdaptorPassBase(this)) {
interleaveComma(adaptor->getPassManagers(), os, [&](OpPassManager &pm) {
os << pm.getOpName() << "(";
pm.printAsTextualPipeline(os);
os << ")";
});
} else {
os << getName();
}
}
/// Forwarding function to execute this pass.
LogicalResult Pass::run(Operation *op, AnalysisManager am) {
passState.emplace(op, am);
@ -254,6 +269,14 @@ MLIRContext *OpPassManager::getContext() const {
/// Return the operation name that this pass manager operates on.
const OperationName &OpPassManager::getOpName() const { return impl->name; }
/// Prints out the passes of the pass mangager as the textual representation
/// of pipelines.
void OpPassManager::printAsTextualPipeline(raw_ostream &os) {
interleaveComma(impl->passes, os, [&](const std::unique_ptr<Pass> &pass) {
pass->printAsTextualPipeline(os);
});
}
//===----------------------------------------------------------------------===//
// OpToOpPassAdaptor
//===----------------------------------------------------------------------===//

View File

@ -3,9 +3,9 @@
// RUN: not mlir-opt %s -pass-pipeline='module(test-options-pass{list=3}, test-module-pass{invalid-option=3})' 2>&1 | FileCheck --check-prefix=CHECK_ERROR_3 %s
// RUN: not mlir-opt %s -pass-pipeline='test-options-pass{list=3 list=notaninteger}' 2>&1 | FileCheck --check-prefix=CHECK_ERROR_4 %s
// RUN: not mlir-opt %s -pass-pipeline='func(test-options-pass{list=1,2,3,4 list=5 string=value1 string=value2})' 2>&1 | FileCheck --check-prefix=CHECK_ERROR_5 %s
// RUN: mlir-opt %s -pass-pipeline='func(test-options-pass{string-list=a list=1,2,3,4 string-list=b,c list=5 string-list=d string=some_value})' 2>&1 | FileCheck --check-prefix=CHECK_1 %s
// RUN: mlir-opt %s -test-options-pass-pipeline='list=1 string-list=a,b' 2>&1 | FileCheck --check-prefix=CHECK_2 %s
// RUN: mlir-opt %s -pass-pipeline='module(test-options-pass{list=3}, test-options-pass{list=1,2,3,4})' 2>&1 | FileCheck --check-prefix=CHECK_3 %s
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='func(test-options-pass{string-list=a list=1,2,3,4 string-list=b,c list=5 string-list=d string=some_value})' -test-dump-pipeline 2>&1 | FileCheck --check-prefix=CHECK_1 %s
// RUN: mlir-opt %s -verify-each=false -test-options-pass-pipeline='list=1 string-list=a,b' -test-dump-pipeline 2>&1 | FileCheck --check-prefix=CHECK_2 %s
// RUN: mlir-opt %s -verify-each=false -pass-pipeline='module(test-options-pass{list=3}, test-options-pass{list=1,2,3,4})' -test-dump-pipeline 2>&1 | FileCheck --check-prefix=CHECK_3 %s
// CHECK_ERROR_1: missing closing '}' while processing pass options
// CHECK_ERROR_2: no such option test-option
@ -15,5 +15,4 @@
// CHECK_1: test-options-pass{list=1,2,3,4,5 string-list=a,b,c,d string=some_value}
// CHECK_2: test-options-pass{list=1 string-list=a,b}
// CHECK_3: test-options-pass{list=3}
// CHECK_3-NEXT: test-options-pass{list=1,2,3,4}
// CHECK_3: module(func(test-options-pass{list=3}), func(test-options-pass{list=1,2,3,4}))

View File

@ -45,13 +45,9 @@ public:
stringOption = options.stringOption;
stringListOption.assign(options.stringListOption.begin(),
options.stringListOption.end());
// Print out a debug representation of the pass in order to allow FileCheck
// testing of options parsing.
print(llvm::errs());
llvm::errs() << "\n";
}
void print(raw_ostream &os) {
void printAsTextualPipeline(raw_ostream &os) final {
os << "test-options-pass{";
if (!listOption.empty()) {
os << "list=";
@ -108,6 +104,13 @@ static PassPipelineRegistration<>
unusedTextual("test-textual-pm-nested-pipeline",
"Test a nested pipeline in the pass manager",
testNestedPipelineTextual);
static PassPipelineRegistration<>
unusedDump("test-dump-pipeline",
"Dumps the pipeline build so far for debugging purposes",
[](OpPassManager &pm) {
pm.printAsTextualPipeline(llvm::errs());
llvm::errs() << "\n";
});
static PassPipelineRegistration<TestOptionsPass::Options>
registerOptionsPassPipeline(