xref: /llvm-project/mlir/test/lib/Pass/TestPassManager.cpp (revision 5b21fd298cb4fc2042a95ffb9284b778f8504e04)
1120509a6SRiver Riddle //===- TestPassManager.cpp - Test pass manager functionality --------------===//
2120509a6SRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6120509a6SRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8120509a6SRiver Riddle 
950f82e68SRiver Riddle #include "TestDialect.h"
10e95e94adSJeff Niu #include "TestOps.h"
1136550692SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h"
1265fcddffSRiver Riddle #include "mlir/IR/BuiltinOps.h"
13120509a6SRiver Riddle #include "mlir/Pass/Pass.h"
14120509a6SRiver Riddle #include "mlir/Pass/PassManager.h"
15120509a6SRiver Riddle 
16120509a6SRiver Riddle using namespace mlir;
17120509a6SRiver Riddle 
18120509a6SRiver Riddle namespace {
1980aca1eaSRiver Riddle struct TestModulePass
2080aca1eaSRiver Riddle     : public PassWrapper<TestModulePass, OperationPass<ModuleOp>> {
215e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestModulePass)
225e50dd04SRiver Riddle 
23722f909fSRiver Riddle   void runOnOperation() final {}
24fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-module-pass"; }
25b5e22e6dSMehdi Amini   StringRef getDescription() const final {
26b5e22e6dSMehdi Amini     return "Test a module pass in the pass manager";
27b5e22e6dSMehdi Amini   }
28120509a6SRiver Riddle };
2941574554SRiver Riddle struct TestFunctionPass
3058ceae95SRiver Riddle     : public PassWrapper<TestFunctionPass, OperationPass<func::FuncOp>> {
315e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFunctionPass)
325e50dd04SRiver Riddle 
3341574554SRiver Riddle   void runOnOperation() final {}
34fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-function-pass"; }
35b5e22e6dSMehdi Amini   StringRef getDescription() const final {
36b5e22e6dSMehdi Amini     return "Test a function pass in the pass manager";
37b5e22e6dSMehdi Amini   }
38120509a6SRiver Riddle };
395e50dd04SRiver Riddle struct TestInterfacePass
409c9a4317SRiver Riddle     : public PassWrapper<TestInterfacePass,
419c9a4317SRiver Riddle                          InterfacePass<FunctionOpInterface>> {
425e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInterfacePass)
435e50dd04SRiver Riddle 
449c9a4317SRiver Riddle   void runOnOperation() final {
459c9a4317SRiver Riddle     getOperation()->emitRemark() << "Executing interface pass on operation";
469c9a4317SRiver Riddle   }
479c9a4317SRiver Riddle   StringRef getArgument() const final { return "test-interface-pass"; }
489c9a4317SRiver Riddle   StringRef getDescription() const final {
499c9a4317SRiver Riddle     return "Test an interface pass (running on FunctionOpInterface) in the "
509c9a4317SRiver Riddle            "pass manager";
519c9a4317SRiver Riddle   }
529c9a4317SRiver Riddle };
535e50dd04SRiver Riddle struct TestOptionsPass
5458ceae95SRiver Riddle     : public PassWrapper<TestOptionsPass, OperationPass<func::FuncOp>> {
555e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPass)
565e50dd04SRiver Riddle 
57165c6d12SNikhil Kalra   enum Enum { Zero, One, Two };
58710b5a12SChristian Sigg 
5921610e66SRiver Riddle   struct Options : public PassPipelineOptions<Options> {
6021610e66SRiver Riddle     ListOption<int> listOption{*this, "list",
6174461512SMLIR Team                                llvm::cl::desc("Example list option")};
6221610e66SRiver Riddle     ListOption<std::string> stringListOption{
636edef135SRiver Riddle         *this, "string-list", llvm::cl::desc("Example string list option")};
6474461512SMLIR Team     Option<std::string> stringOption{*this, "string",
6574461512SMLIR Team                                      llvm::cl::desc("Example string option")};
66710b5a12SChristian Sigg     Option<Enum> enumOption{
67710b5a12SChristian Sigg         *this, "enum", llvm::cl::desc("Example enum option"),
68710b5a12SChristian Sigg         llvm::cl::values(clEnumValN(0, "zero", "Example zero value"),
69165c6d12SNikhil Kalra                          clEnumValN(1, "one", "Example one value"),
70165c6d12SNikhil Kalra                          clEnumValN(2, "two", "Example two value"))};
71165c6d12SNikhil Kalra 
72165c6d12SNikhil Kalra     Options() = default;
73165c6d12SNikhil Kalra     Options(const Options &rhs) { *this = rhs; }
74165c6d12SNikhil Kalra     Options &operator=(const Options &rhs) {
75165c6d12SNikhil Kalra       copyOptionValuesFrom(rhs);
76165c6d12SNikhil Kalra       return *this;
77165c6d12SNikhil Kalra     }
7874461512SMLIR Team   };
7921610e66SRiver Riddle   TestOptionsPass() = default;
808919447cSJaved Absar   TestOptionsPass(const TestOptionsPass &) : PassWrapper() {}
8174461512SMLIR Team   TestOptionsPass(const Options &options) {
82400ad6f9SRiver Riddle     listOption = options.listOption;
83400ad6f9SRiver Riddle     stringOption = options.stringOption;
84400ad6f9SRiver Riddle     stringListOption = options.stringListOption;
85710b5a12SChristian Sigg     enumOption = options.enumOption;
8674461512SMLIR Team   }
8774461512SMLIR Team 
8841574554SRiver Riddle   void runOnOperation() final {}
89fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-options-pass"; }
90b5e22e6dSMehdi Amini   StringRef getDescription() const final {
91b5e22e6dSMehdi Amini     return "Test options parsing capabilities";
92b5e22e6dSMehdi Amini   }
9374461512SMLIR Team 
946edef135SRiver Riddle   ListOption<int> listOption{*this, "list",
9521610e66SRiver Riddle                              llvm::cl::desc("Example list option")};
9621610e66SRiver Riddle   ListOption<std::string> stringListOption{
976edef135SRiver Riddle       *this, "string-list", llvm::cl::desc("Example string list option")};
9821610e66SRiver Riddle   Option<std::string> stringOption{*this, "string",
9921610e66SRiver Riddle                                    llvm::cl::desc("Example string option")};
100710b5a12SChristian Sigg   Option<Enum> enumOption{
101710b5a12SChristian Sigg       *this, "enum", llvm::cl::desc("Example enum option"),
102710b5a12SChristian Sigg       llvm::cl::values(clEnumValN(0, "zero", "Example zero value"),
103165c6d12SNikhil Kalra                        clEnumValN(1, "one", "Example one value"),
104165c6d12SNikhil Kalra                        clEnumValN(2, "two", "Example two value"))};
105165c6d12SNikhil Kalra };
106165c6d12SNikhil Kalra 
107165c6d12SNikhil Kalra struct TestOptionsSuperPass
108165c6d12SNikhil Kalra     : public PassWrapper<TestOptionsSuperPass, OperationPass<func::FuncOp>> {
109165c6d12SNikhil Kalra   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsSuperPass)
110165c6d12SNikhil Kalra 
111165c6d12SNikhil Kalra   struct Options : public PassPipelineOptions<Options> {
112165c6d12SNikhil Kalra     ListOption<TestOptionsPass::Options> listOption{
113165c6d12SNikhil Kalra         *this, "super-list",
114165c6d12SNikhil Kalra         llvm::cl::desc("Example list of PassPipelineOptions option")};
115165c6d12SNikhil Kalra 
116165c6d12SNikhil Kalra     Options() = default;
117165c6d12SNikhil Kalra   };
118165c6d12SNikhil Kalra 
119165c6d12SNikhil Kalra   TestOptionsSuperPass() = default;
120165c6d12SNikhil Kalra   TestOptionsSuperPass(const TestOptionsSuperPass &) : PassWrapper() {}
121165c6d12SNikhil Kalra   TestOptionsSuperPass(const Options &options) {
122165c6d12SNikhil Kalra     listOption = options.listOption;
123165c6d12SNikhil Kalra   }
124165c6d12SNikhil Kalra 
125165c6d12SNikhil Kalra   void runOnOperation() final {}
126165c6d12SNikhil Kalra   StringRef getArgument() const final { return "test-options-super-pass"; }
127165c6d12SNikhil Kalra   StringRef getDescription() const final {
128165c6d12SNikhil Kalra     return "Test options of options parsing capabilities";
129165c6d12SNikhil Kalra   }
130165c6d12SNikhil Kalra 
131165c6d12SNikhil Kalra   ListOption<TestOptionsPass::Options> listOption{
132165c6d12SNikhil Kalra       *this, "list",
133165c6d12SNikhil Kalra       llvm::cl::desc("Example list of PassPipelineOptions option")};
13474461512SMLIR Team };
1357a7dcc17SRiver Riddle 
1367a7dcc17SRiver Riddle /// A test pass that always aborts to enable testing the crash recovery
1377a7dcc17SRiver Riddle /// mechanism of the pass manager.
1385e50dd04SRiver Riddle struct TestCrashRecoveryPass
13980aca1eaSRiver Riddle     : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> {
1405e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCrashRecoveryPass)
1415e50dd04SRiver Riddle 
1427a7dcc17SRiver Riddle   void runOnOperation() final { abort(); }
143fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-pass-crash"; }
144b5e22e6dSMehdi Amini   StringRef getDescription() const final {
145b5e22e6dSMehdi Amini     return "Test a pass in the pass manager that always crashes";
146b5e22e6dSMehdi Amini   }
1477a7dcc17SRiver Riddle };
14833a64540SRiver Riddle 
14964ce90e1SRiver Riddle /// A test pass that always fails to enable testing the failure recovery
15064ce90e1SRiver Riddle /// mechanisms of the pass manager.
1515e50dd04SRiver Riddle struct TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> {
1525e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFailurePass)
1535e50dd04SRiver Riddle 
154*5b21fd29SBilly Zhu   TestFailurePass() = default;
155*5b21fd29SBilly Zhu   TestFailurePass(const TestFailurePass &other) : PassWrapper(other) {}
156*5b21fd29SBilly Zhu 
157*5b21fd29SBilly Zhu   void runOnOperation() final {
158*5b21fd29SBilly Zhu     signalPassFailure();
159*5b21fd29SBilly Zhu     if (genDiagnostics)
160*5b21fd29SBilly Zhu       mlir::emitError(getOperation()->getLoc(), "illegal operation");
161*5b21fd29SBilly Zhu   }
162b5e22e6dSMehdi Amini   StringRef getArgument() const final { return "test-pass-failure"; }
163b5e22e6dSMehdi Amini   StringRef getDescription() const final {
164b5e22e6dSMehdi Amini     return "Test a pass in the pass manager that always fails";
165b5e22e6dSMehdi Amini   }
166*5b21fd29SBilly Zhu 
167*5b21fd29SBilly Zhu   Option<bool> genDiagnostics{*this, "gen-diagnostics",
168*5b21fd29SBilly Zhu                               llvm::cl::desc("Generate a diagnostic message")};
16964ce90e1SRiver Riddle };
17064ce90e1SRiver Riddle 
17183892d76SMehdi Amini /// A test pass that creates an invalid operation in a function body.
17283892d76SMehdi Amini struct TestInvalidIRPass
17383892d76SMehdi Amini     : public PassWrapper<TestInvalidIRPass,
17483892d76SMehdi Amini                          InterfacePass<FunctionOpInterface>> {
17583892d76SMehdi Amini   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidIRPass)
17683892d76SMehdi Amini 
17783892d76SMehdi Amini   TestInvalidIRPass() = default;
178b37d158fSMehdi Amini   TestInvalidIRPass(const TestInvalidIRPass &other) : PassWrapper(other) {}
17983892d76SMehdi Amini 
18083892d76SMehdi Amini   StringRef getArgument() const final { return "test-pass-create-invalid-ir"; }
18183892d76SMehdi Amini   StringRef getDescription() const final {
18283892d76SMehdi Amini     return "Test pass that adds an invalid operation in a function body";
18383892d76SMehdi Amini   }
18483892d76SMehdi Amini   void getDependentDialects(DialectRegistry &registry) const final {
18583892d76SMehdi Amini     registry.insert<test::TestDialect>();
18683892d76SMehdi Amini   }
18783892d76SMehdi Amini   void runOnOperation() final {
18883892d76SMehdi Amini     if (signalFailure)
18983892d76SMehdi Amini       signalPassFailure();
19083892d76SMehdi Amini     if (!emitInvalidIR)
19183892d76SMehdi Amini       return;
192ecba7c58SRiver Riddle     OpBuilder b(getOperation().getFunctionBody());
19383892d76SMehdi Amini     OperationState state(b.getUnknownLoc(), "test.any_attr_of_i32_str");
19483892d76SMehdi Amini     b.create(state);
19583892d76SMehdi Amini   }
19683892d76SMehdi Amini   Option<bool> signalFailure{*this, "signal-pass-failure",
19783892d76SMehdi Amini                              llvm::cl::desc("Trigger a pass failure")};
19883892d76SMehdi Amini   Option<bool> emitInvalidIR{*this, "emit-invalid-ir", llvm::cl::init(true),
19983892d76SMehdi Amini                              llvm::cl::desc("Emit invalid IR")};
20083892d76SMehdi Amini };
20183892d76SMehdi Amini 
20250f82e68SRiver Riddle /// A test pass that always fails to enable testing the failure recovery
20350f82e68SRiver Riddle /// mechanisms of the pass manager.
2045e50dd04SRiver Riddle struct TestInvalidParentPass
20550f82e68SRiver Riddle     : public PassWrapper<TestInvalidParentPass,
20650f82e68SRiver Riddle                          InterfacePass<FunctionOpInterface>> {
2075e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass)
2085e50dd04SRiver Riddle 
20950f82e68SRiver Riddle   StringRef getArgument() const final { return "test-pass-invalid-parent"; }
21050f82e68SRiver Riddle   StringRef getDescription() const final {
21150f82e68SRiver Riddle     return "Test a pass in the pass manager that makes the parent operation "
21250f82e68SRiver Riddle            "invalid";
21350f82e68SRiver Riddle   }
21450f82e68SRiver Riddle   void getDependentDialects(DialectRegistry &registry) const final {
21550f82e68SRiver Riddle     registry.insert<test::TestDialect>();
21650f82e68SRiver Riddle   }
21750f82e68SRiver Riddle   void runOnOperation() final {
21850f82e68SRiver Riddle     FunctionOpInterface op = getOperation();
219ecba7c58SRiver Riddle     OpBuilder b(op.getFunctionBody());
22050f82e68SRiver Riddle     b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func",
22150f82e68SRiver Riddle                                ValueRange());
22250f82e68SRiver Riddle   }
22350f82e68SRiver Riddle };
22450f82e68SRiver Riddle 
22533a64540SRiver Riddle /// A test pass that contains a statistic.
22680aca1eaSRiver Riddle struct TestStatisticPass
22780aca1eaSRiver Riddle     : public PassWrapper<TestStatisticPass, OperationPass<>> {
2285e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass)
2295e50dd04SRiver Riddle 
23033a64540SRiver Riddle   TestStatisticPass() = default;
2318919447cSJaved Absar   TestStatisticPass(const TestStatisticPass &) : PassWrapper() {}
232b5e22e6dSMehdi Amini   StringRef getArgument() const final { return "test-stats-pass"; }
233b5e22e6dSMehdi Amini   StringRef getDescription() const final { return "Test pass statistics"; }
23433a64540SRiver Riddle 
23504644a9eSSlava Zakharin   // Use a couple of statistics to verify their ordering
23604644a9eSSlava Zakharin   // in the print out. The statistics are registered in the order
23704644a9eSSlava Zakharin   // of construction, so put "num-ops2" before "num-ops" and
23804644a9eSSlava Zakharin   // make sure that the order is reversed.
23904644a9eSSlava Zakharin   Statistic opCountDuplicate{this, "num-ops2",
24004644a9eSSlava Zakharin                              "Number of operations counted one more time"};
24133a64540SRiver Riddle   Statistic opCount{this, "num-ops", "Number of operations counted"};
24233a64540SRiver Riddle 
24333a64540SRiver Riddle   void runOnOperation() final {
24433a64540SRiver Riddle     getOperation()->walk([&](Operation *) { ++opCount; });
24504644a9eSSlava Zakharin     getOperation()->walk([&](Operation *) { ++opCountDuplicate; });
24633a64540SRiver Riddle   }
24733a64540SRiver Riddle };
248be0a7e9fSMehdi Amini } // namespace
249120509a6SRiver Riddle 
2509274ed66SRiver Riddle static void testNestedPipeline(OpPassManager &pm) {
251120509a6SRiver Riddle   // Nest a module pipeline that contains:
252120509a6SRiver Riddle   /// A module pass.
253120509a6SRiver Riddle   auto &modulePM = pm.nest<ModuleOp>();
254120509a6SRiver Riddle   modulePM.addPass(std::make_unique<TestModulePass>());
255120509a6SRiver Riddle   /// A nested function pass.
25658ceae95SRiver Riddle   auto &nestedFunctionPM = modulePM.nest<func::FuncOp>();
257120509a6SRiver Riddle   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
258120509a6SRiver Riddle 
259120509a6SRiver Riddle   // Nest a function pipeline that contains a single pass.
26058ceae95SRiver Riddle   auto &functionPM = pm.nest<func::FuncOp>();
261120509a6SRiver Riddle   functionPM.addPass(std::make_unique<TestFunctionPass>());
262120509a6SRiver Riddle }
263120509a6SRiver Riddle 
264d780bdefSRiver Riddle static void testNestedPipelineTextual(OpPassManager &pm) {
265d780bdefSRiver Riddle   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
266d780bdefSRiver Riddle }
267d780bdefSRiver Riddle 
268c6477050SMehdi Amini namespace mlir {
269c6477050SMehdi Amini void registerPassManagerTestPass() {
270b5e22e6dSMehdi Amini   PassRegistration<TestOptionsPass>();
271165c6d12SNikhil Kalra   PassRegistration<TestOptionsSuperPass>();
27274461512SMLIR Team 
273b5e22e6dSMehdi Amini   PassRegistration<TestModulePass>();
2749274ed66SRiver Riddle 
275b5e22e6dSMehdi Amini   PassRegistration<TestFunctionPass>();
2767a7dcc17SRiver Riddle 
2779c9a4317SRiver Riddle   PassRegistration<TestInterfacePass>();
2789c9a4317SRiver Riddle 
279b5e22e6dSMehdi Amini   PassRegistration<TestCrashRecoveryPass>();
280b5e22e6dSMehdi Amini   PassRegistration<TestFailurePass>();
28183892d76SMehdi Amini   PassRegistration<TestInvalidIRPass>();
28250f82e68SRiver Riddle   PassRegistration<TestInvalidParentPass>();
283c6477050SMehdi Amini 
284b5e22e6dSMehdi Amini   PassRegistration<TestStatisticPass>();
28533a64540SRiver Riddle 
286c6477050SMehdi Amini   PassPipelineRegistration<>("test-pm-nested-pipeline",
287c6477050SMehdi Amini                              "Test a nested pipeline in the pass manager",
288c6477050SMehdi Amini                              testNestedPipeline);
289c6477050SMehdi Amini   PassPipelineRegistration<>("test-textual-pm-nested-pipeline",
290d780bdefSRiver Riddle                              "Test a nested pipeline in the pass manager",
291d780bdefSRiver Riddle                              testNestedPipelineTextual);
29274461512SMLIR Team 
293c6477050SMehdi Amini   PassPipelineRegistration<TestOptionsPass::Options>
29474461512SMLIR Team       registerOptionsPassPipeline(
29574461512SMLIR Team           "test-options-pass-pipeline",
29674461512SMLIR Team           "Parses options using pass pipeline registration",
29774461512SMLIR Team           [](OpPassManager &pm, const TestOptionsPass::Options &options) {
29874461512SMLIR Team             pm.addPass(std::make_unique<TestOptionsPass>(options));
29974461512SMLIR Team           });
300165c6d12SNikhil Kalra 
301165c6d12SNikhil Kalra   PassPipelineRegistration<TestOptionsSuperPass::Options>
302165c6d12SNikhil Kalra       registerOptionsSuperPassPipeline(
303165c6d12SNikhil Kalra           "test-options-super-pass-pipeline",
304165c6d12SNikhil Kalra           "Parses options of PassPipelineOptions using pass pipeline "
305165c6d12SNikhil Kalra           "registration",
306165c6d12SNikhil Kalra           [](OpPassManager &pm, const TestOptionsSuperPass::Options &options) {
307165c6d12SNikhil Kalra             pm.addPass(std::make_unique<TestOptionsSuperPass>(options));
308165c6d12SNikhil Kalra           });
309c6477050SMehdi Amini }
310c6477050SMehdi Amini } // namespace mlir
311