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"
1036550692SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h"
1165fcddffSRiver Riddle #include "mlir/IR/BuiltinOps.h"
12120509a6SRiver Riddle #include "mlir/Pass/Pass.h"
13120509a6SRiver Riddle #include "mlir/Pass/PassManager.h"
14120509a6SRiver Riddle 
15120509a6SRiver Riddle using namespace mlir;
16120509a6SRiver Riddle 
17120509a6SRiver Riddle namespace {
1880aca1eaSRiver Riddle struct TestModulePass
1980aca1eaSRiver Riddle     : public PassWrapper<TestModulePass, OperationPass<ModuleOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestModulePass205e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestModulePass)
215e50dd04SRiver Riddle 
22722f909fSRiver Riddle   void runOnOperation() final {}
getArgument__anon0807c3400111::TestModulePass23fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-module-pass"; }
getDescription__anon0807c3400111::TestModulePass24b5e22e6dSMehdi Amini   StringRef getDescription() const final {
25b5e22e6dSMehdi Amini     return "Test a module pass in the pass manager";
26b5e22e6dSMehdi Amini   }
27120509a6SRiver Riddle };
2841574554SRiver Riddle struct TestFunctionPass
2958ceae95SRiver Riddle     : public PassWrapper<TestFunctionPass, OperationPass<func::FuncOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestFunctionPass305e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFunctionPass)
315e50dd04SRiver Riddle 
3241574554SRiver Riddle   void runOnOperation() final {}
getArgument__anon0807c3400111::TestFunctionPass33fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-function-pass"; }
getDescription__anon0807c3400111::TestFunctionPass34b5e22e6dSMehdi Amini   StringRef getDescription() const final {
35b5e22e6dSMehdi Amini     return "Test a function pass in the pass manager";
36b5e22e6dSMehdi Amini   }
37120509a6SRiver Riddle };
385e50dd04SRiver Riddle struct TestInterfacePass
399c9a4317SRiver Riddle     : public PassWrapper<TestInterfacePass,
409c9a4317SRiver Riddle                          InterfacePass<FunctionOpInterface>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestInterfacePass415e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInterfacePass)
425e50dd04SRiver Riddle 
439c9a4317SRiver Riddle   void runOnOperation() final {
449c9a4317SRiver Riddle     getOperation()->emitRemark() << "Executing interface pass on operation";
459c9a4317SRiver Riddle   }
getArgument__anon0807c3400111::TestInterfacePass469c9a4317SRiver Riddle   StringRef getArgument() const final { return "test-interface-pass"; }
getDescription__anon0807c3400111::TestInterfacePass479c9a4317SRiver Riddle   StringRef getDescription() const final {
489c9a4317SRiver Riddle     return "Test an interface pass (running on FunctionOpInterface) in the "
499c9a4317SRiver Riddle            "pass manager";
509c9a4317SRiver Riddle   }
519c9a4317SRiver Riddle };
525e50dd04SRiver Riddle struct TestOptionsPass
5358ceae95SRiver Riddle     : public PassWrapper<TestOptionsPass, OperationPass<func::FuncOp>> {
545e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPass)
555e50dd04SRiver Riddle 
5621610e66SRiver Riddle   struct Options : public PassPipelineOptions<Options> {
5721610e66SRiver Riddle     ListOption<int> listOption{*this, "list",
5874461512SMLIR Team                                llvm::cl::desc("Example list option")};
5921610e66SRiver Riddle     ListOption<std::string> stringListOption{
606edef135SRiver Riddle         *this, "string-list", llvm::cl::desc("Example string list option")};
6174461512SMLIR Team     Option<std::string> stringOption{*this, "string",
6274461512SMLIR Team                                      llvm::cl::desc("Example string option")};
6374461512SMLIR Team   };
6421610e66SRiver Riddle   TestOptionsPass() = default;
TestOptionsPass__anon0807c3400111::TestOptionsPass658919447cSJaved Absar   TestOptionsPass(const TestOptionsPass &) : PassWrapper() {}
TestOptionsPass__anon0807c3400111::TestOptionsPass6674461512SMLIR Team   TestOptionsPass(const Options &options) {
67400ad6f9SRiver Riddle     listOption = options.listOption;
68400ad6f9SRiver Riddle     stringOption = options.stringOption;
69400ad6f9SRiver Riddle     stringListOption = options.stringListOption;
7074461512SMLIR Team   }
7174461512SMLIR Team 
runOnOperation__anon0807c3400111::TestOptionsPass7241574554SRiver Riddle   void runOnOperation() final {}
getArgument__anon0807c3400111::TestOptionsPass73fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-options-pass"; }
getDescription__anon0807c3400111::TestOptionsPass74b5e22e6dSMehdi Amini   StringRef getDescription() const final {
75b5e22e6dSMehdi Amini     return "Test options parsing capabilities";
76b5e22e6dSMehdi Amini   }
7774461512SMLIR Team 
786edef135SRiver Riddle   ListOption<int> listOption{*this, "list",
7921610e66SRiver Riddle                              llvm::cl::desc("Example list option")};
8021610e66SRiver Riddle   ListOption<std::string> stringListOption{
816edef135SRiver Riddle       *this, "string-list", llvm::cl::desc("Example string list option")};
8221610e66SRiver Riddle   Option<std::string> stringOption{*this, "string",
8321610e66SRiver Riddle                                    llvm::cl::desc("Example string option")};
8474461512SMLIR Team };
857a7dcc17SRiver Riddle 
867a7dcc17SRiver Riddle /// A test pass that always aborts to enable testing the crash recovery
877a7dcc17SRiver Riddle /// mechanism of the pass manager.
885e50dd04SRiver Riddle struct TestCrashRecoveryPass
8980aca1eaSRiver Riddle     : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestCrashRecoveryPass905e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCrashRecoveryPass)
915e50dd04SRiver Riddle 
927a7dcc17SRiver Riddle   void runOnOperation() final { abort(); }
getArgument__anon0807c3400111::TestCrashRecoveryPass93fa51c5afSRiver Riddle   StringRef getArgument() const final { return "test-pass-crash"; }
getDescription__anon0807c3400111::TestCrashRecoveryPass94b5e22e6dSMehdi Amini   StringRef getDescription() const final {
95b5e22e6dSMehdi Amini     return "Test a pass in the pass manager that always crashes";
96b5e22e6dSMehdi Amini   }
977a7dcc17SRiver Riddle };
9833a64540SRiver Riddle 
9964ce90e1SRiver Riddle /// A test pass that always fails to enable testing the failure recovery
10064ce90e1SRiver Riddle /// mechanisms of the pass manager.
1015e50dd04SRiver Riddle struct TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestFailurePass1025e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFailurePass)
1035e50dd04SRiver Riddle 
10464ce90e1SRiver Riddle   void runOnOperation() final { signalPassFailure(); }
getArgument__anon0807c3400111::TestFailurePass105b5e22e6dSMehdi Amini   StringRef getArgument() const final { return "test-pass-failure"; }
getDescription__anon0807c3400111::TestFailurePass106b5e22e6dSMehdi Amini   StringRef getDescription() const final {
107b5e22e6dSMehdi Amini     return "Test a pass in the pass manager that always fails";
108b5e22e6dSMehdi Amini   }
10964ce90e1SRiver Riddle };
11064ce90e1SRiver Riddle 
11183892d76SMehdi Amini /// A test pass that creates an invalid operation in a function body.
11283892d76SMehdi Amini struct TestInvalidIRPass
11383892d76SMehdi Amini     : public PassWrapper<TestInvalidIRPass,
11483892d76SMehdi Amini                          InterfacePass<FunctionOpInterface>> {
11583892d76SMehdi Amini   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidIRPass)
11683892d76SMehdi Amini 
11783892d76SMehdi Amini   TestInvalidIRPass() = default;
TestInvalidIRPass__anon0807c3400111::TestInvalidIRPass118b37d158fSMehdi Amini   TestInvalidIRPass(const TestInvalidIRPass &other) : PassWrapper(other) {}
11983892d76SMehdi Amini 
getArgument__anon0807c3400111::TestInvalidIRPass12083892d76SMehdi Amini   StringRef getArgument() const final { return "test-pass-create-invalid-ir"; }
getDescription__anon0807c3400111::TestInvalidIRPass12183892d76SMehdi Amini   StringRef getDescription() const final {
12283892d76SMehdi Amini     return "Test pass that adds an invalid operation in a function body";
12383892d76SMehdi Amini   }
getDependentDialects__anon0807c3400111::TestInvalidIRPass12483892d76SMehdi Amini   void getDependentDialects(DialectRegistry &registry) const final {
12583892d76SMehdi Amini     registry.insert<test::TestDialect>();
12683892d76SMehdi Amini   }
runOnOperation__anon0807c3400111::TestInvalidIRPass12783892d76SMehdi Amini   void runOnOperation() final {
12883892d76SMehdi Amini     if (signalFailure)
12983892d76SMehdi Amini       signalPassFailure();
13083892d76SMehdi Amini     if (!emitInvalidIR)
13183892d76SMehdi Amini       return;
13283892d76SMehdi Amini     OpBuilder b(getOperation().getBody());
13383892d76SMehdi Amini     OperationState state(b.getUnknownLoc(), "test.any_attr_of_i32_str");
13483892d76SMehdi Amini     b.create(state);
13583892d76SMehdi Amini   }
13683892d76SMehdi Amini   Option<bool> signalFailure{*this, "signal-pass-failure",
13783892d76SMehdi Amini                              llvm::cl::desc("Trigger a pass failure")};
13883892d76SMehdi Amini   Option<bool> emitInvalidIR{*this, "emit-invalid-ir", llvm::cl::init(true),
13983892d76SMehdi Amini                              llvm::cl::desc("Emit invalid IR")};
14083892d76SMehdi Amini };
14183892d76SMehdi Amini 
14250f82e68SRiver Riddle /// A test pass that always fails to enable testing the failure recovery
14350f82e68SRiver Riddle /// mechanisms of the pass manager.
1445e50dd04SRiver Riddle struct TestInvalidParentPass
14550f82e68SRiver Riddle     : public PassWrapper<TestInvalidParentPass,
14650f82e68SRiver Riddle                          InterfacePass<FunctionOpInterface>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestInvalidParentPass1475e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass)
1485e50dd04SRiver Riddle 
14950f82e68SRiver Riddle   StringRef getArgument() const final { return "test-pass-invalid-parent"; }
getDescription__anon0807c3400111::TestInvalidParentPass15050f82e68SRiver Riddle   StringRef getDescription() const final {
15150f82e68SRiver Riddle     return "Test a pass in the pass manager that makes the parent operation "
15250f82e68SRiver Riddle            "invalid";
15350f82e68SRiver Riddle   }
getDependentDialects__anon0807c3400111::TestInvalidParentPass15450f82e68SRiver Riddle   void getDependentDialects(DialectRegistry &registry) const final {
15550f82e68SRiver Riddle     registry.insert<test::TestDialect>();
15650f82e68SRiver Riddle   }
runOnOperation__anon0807c3400111::TestInvalidParentPass15750f82e68SRiver Riddle   void runOnOperation() final {
15850f82e68SRiver Riddle     FunctionOpInterface op = getOperation();
15950f82e68SRiver Riddle     OpBuilder b(getOperation().getBody());
16050f82e68SRiver Riddle     b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func",
16150f82e68SRiver Riddle                                ValueRange());
16250f82e68SRiver Riddle   }
16350f82e68SRiver Riddle };
16450f82e68SRiver Riddle 
16533a64540SRiver Riddle /// A test pass that contains a statistic.
16680aca1eaSRiver Riddle struct TestStatisticPass
16780aca1eaSRiver Riddle     : public PassWrapper<TestStatisticPass, OperationPass<>> {
1685e50dd04SRiver Riddle   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass)
1695e50dd04SRiver Riddle 
17033a64540SRiver Riddle   TestStatisticPass() = default;
TestStatisticPass__anon0807c3400111::TestStatisticPass1718919447cSJaved Absar   TestStatisticPass(const TestStatisticPass &) : PassWrapper() {}
getArgument__anon0807c3400111::TestStatisticPass172b5e22e6dSMehdi Amini   StringRef getArgument() const final { return "test-stats-pass"; }
getDescription__anon0807c3400111::TestStatisticPass173b5e22e6dSMehdi Amini   StringRef getDescription() const final { return "Test pass statistics"; }
17433a64540SRiver Riddle 
175*04644a9eSSlava Zakharin   // Use a couple of statistics to verify their ordering
176*04644a9eSSlava Zakharin   // in the print out. The statistics are registered in the order
177*04644a9eSSlava Zakharin   // of construction, so put "num-ops2" before "num-ops" and
178*04644a9eSSlava Zakharin   // make sure that the order is reversed.
179*04644a9eSSlava Zakharin   Statistic opCountDuplicate{this, "num-ops2",
180*04644a9eSSlava Zakharin                              "Number of operations counted one more time"};
18133a64540SRiver Riddle   Statistic opCount{this, "num-ops", "Number of operations counted"};
18233a64540SRiver Riddle 
runOnOperation__anon0807c3400111::TestStatisticPass18333a64540SRiver Riddle   void runOnOperation() final {
18433a64540SRiver Riddle     getOperation()->walk([&](Operation *) { ++opCount; });
185*04644a9eSSlava Zakharin     getOperation()->walk([&](Operation *) { ++opCountDuplicate; });
18633a64540SRiver Riddle   }
18733a64540SRiver Riddle };
188be0a7e9fSMehdi Amini } // namespace
189120509a6SRiver Riddle 
testNestedPipeline(OpPassManager & pm)1909274ed66SRiver Riddle static void testNestedPipeline(OpPassManager &pm) {
191120509a6SRiver Riddle   // Nest a module pipeline that contains:
192120509a6SRiver Riddle   /// A module pass.
193120509a6SRiver Riddle   auto &modulePM = pm.nest<ModuleOp>();
194120509a6SRiver Riddle   modulePM.addPass(std::make_unique<TestModulePass>());
195120509a6SRiver Riddle   /// A nested function pass.
19658ceae95SRiver Riddle   auto &nestedFunctionPM = modulePM.nest<func::FuncOp>();
197120509a6SRiver Riddle   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
198120509a6SRiver Riddle 
199120509a6SRiver Riddle   // Nest a function pipeline that contains a single pass.
20058ceae95SRiver Riddle   auto &functionPM = pm.nest<func::FuncOp>();
201120509a6SRiver Riddle   functionPM.addPass(std::make_unique<TestFunctionPass>());
202120509a6SRiver Riddle }
203120509a6SRiver Riddle 
testNestedPipelineTextual(OpPassManager & pm)204d780bdefSRiver Riddle static void testNestedPipelineTextual(OpPassManager &pm) {
205d780bdefSRiver Riddle   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
206d780bdefSRiver Riddle }
207d780bdefSRiver Riddle 
208c6477050SMehdi Amini namespace mlir {
registerPassManagerTestPass()209c6477050SMehdi Amini void registerPassManagerTestPass() {
210b5e22e6dSMehdi Amini   PassRegistration<TestOptionsPass>();
21174461512SMLIR Team 
212b5e22e6dSMehdi Amini   PassRegistration<TestModulePass>();
2139274ed66SRiver Riddle 
214b5e22e6dSMehdi Amini   PassRegistration<TestFunctionPass>();
2157a7dcc17SRiver Riddle 
2169c9a4317SRiver Riddle   PassRegistration<TestInterfacePass>();
2179c9a4317SRiver Riddle 
218b5e22e6dSMehdi Amini   PassRegistration<TestCrashRecoveryPass>();
219b5e22e6dSMehdi Amini   PassRegistration<TestFailurePass>();
22083892d76SMehdi Amini   PassRegistration<TestInvalidIRPass>();
22150f82e68SRiver Riddle   PassRegistration<TestInvalidParentPass>();
222c6477050SMehdi Amini 
223b5e22e6dSMehdi Amini   PassRegistration<TestStatisticPass>();
22433a64540SRiver Riddle 
225c6477050SMehdi Amini   PassPipelineRegistration<>("test-pm-nested-pipeline",
226c6477050SMehdi Amini                              "Test a nested pipeline in the pass manager",
227c6477050SMehdi Amini                              testNestedPipeline);
228c6477050SMehdi Amini   PassPipelineRegistration<>("test-textual-pm-nested-pipeline",
229d780bdefSRiver Riddle                              "Test a nested pipeline in the pass manager",
230d780bdefSRiver Riddle                              testNestedPipelineTextual);
231c6477050SMehdi Amini   PassPipelineRegistration<>(
232c6477050SMehdi Amini       "test-dump-pipeline",
233ae6946ecSMLIR Team       "Dumps the pipeline build so far for debugging purposes",
234ae6946ecSMLIR Team       [](OpPassManager &pm) {
235ae6946ecSMLIR Team         pm.printAsTextualPipeline(llvm::errs());
236ae6946ecSMLIR Team         llvm::errs() << "\n";
237ae6946ecSMLIR Team       });
23874461512SMLIR Team 
239c6477050SMehdi Amini   PassPipelineRegistration<TestOptionsPass::Options>
24074461512SMLIR Team       registerOptionsPassPipeline(
24174461512SMLIR Team           "test-options-pass-pipeline",
24274461512SMLIR Team           "Parses options using pass pipeline registration",
24374461512SMLIR Team           [](OpPassManager &pm, const TestOptionsPass::Options &options) {
24474461512SMLIR Team             pm.addPass(std::make_unique<TestOptionsPass>(options));
24574461512SMLIR Team           });
246c6477050SMehdi Amini }
247c6477050SMehdi Amini } // namespace mlir
248