1 //===- TestPassManager.cpp - Test pass manager functionality --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "TestDialect.h"
10 #include "mlir/Dialect/Func/IR/FuncOps.h"
11 #include "mlir/IR/BuiltinOps.h"
12 #include "mlir/Pass/Pass.h"
13 #include "mlir/Pass/PassManager.h"
14 
15 using namespace mlir;
16 
17 namespace {
18 struct TestModulePass
19     : public PassWrapper<TestModulePass, OperationPass<ModuleOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestModulePass20   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestModulePass)
21 
22   void runOnOperation() final {}
getArgument__anon0807c3400111::TestModulePass23   StringRef getArgument() const final { return "test-module-pass"; }
getDescription__anon0807c3400111::TestModulePass24   StringRef getDescription() const final {
25     return "Test a module pass in the pass manager";
26   }
27 };
28 struct TestFunctionPass
29     : public PassWrapper<TestFunctionPass, OperationPass<func::FuncOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestFunctionPass30   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFunctionPass)
31 
32   void runOnOperation() final {}
getArgument__anon0807c3400111::TestFunctionPass33   StringRef getArgument() const final { return "test-function-pass"; }
getDescription__anon0807c3400111::TestFunctionPass34   StringRef getDescription() const final {
35     return "Test a function pass in the pass manager";
36   }
37 };
38 struct TestInterfacePass
39     : public PassWrapper<TestInterfacePass,
40                          InterfacePass<FunctionOpInterface>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestInterfacePass41   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInterfacePass)
42 
43   void runOnOperation() final {
44     getOperation()->emitRemark() << "Executing interface pass on operation";
45   }
getArgument__anon0807c3400111::TestInterfacePass46   StringRef getArgument() const final { return "test-interface-pass"; }
getDescription__anon0807c3400111::TestInterfacePass47   StringRef getDescription() const final {
48     return "Test an interface pass (running on FunctionOpInterface) in the "
49            "pass manager";
50   }
51 };
52 struct TestOptionsPass
53     : public PassWrapper<TestOptionsPass, OperationPass<func::FuncOp>> {
54   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPass)
55 
56   struct Options : public PassPipelineOptions<Options> {
57     ListOption<int> listOption{*this, "list",
58                                llvm::cl::desc("Example list option")};
59     ListOption<std::string> stringListOption{
60         *this, "string-list", llvm::cl::desc("Example string list option")};
61     Option<std::string> stringOption{*this, "string",
62                                      llvm::cl::desc("Example string option")};
63   };
64   TestOptionsPass() = default;
TestOptionsPass__anon0807c3400111::TestOptionsPass65   TestOptionsPass(const TestOptionsPass &) : PassWrapper() {}
TestOptionsPass__anon0807c3400111::TestOptionsPass66   TestOptionsPass(const Options &options) {
67     listOption = options.listOption;
68     stringOption = options.stringOption;
69     stringListOption = options.stringListOption;
70   }
71 
runOnOperation__anon0807c3400111::TestOptionsPass72   void runOnOperation() final {}
getArgument__anon0807c3400111::TestOptionsPass73   StringRef getArgument() const final { return "test-options-pass"; }
getDescription__anon0807c3400111::TestOptionsPass74   StringRef getDescription() const final {
75     return "Test options parsing capabilities";
76   }
77 
78   ListOption<int> listOption{*this, "list",
79                              llvm::cl::desc("Example list option")};
80   ListOption<std::string> stringListOption{
81       *this, "string-list", llvm::cl::desc("Example string list option")};
82   Option<std::string> stringOption{*this, "string",
83                                    llvm::cl::desc("Example string option")};
84 };
85 
86 /// A test pass that always aborts to enable testing the crash recovery
87 /// mechanism of the pass manager.
88 struct TestCrashRecoveryPass
89     : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestCrashRecoveryPass90   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCrashRecoveryPass)
91 
92   void runOnOperation() final { abort(); }
getArgument__anon0807c3400111::TestCrashRecoveryPass93   StringRef getArgument() const final { return "test-pass-crash"; }
getDescription__anon0807c3400111::TestCrashRecoveryPass94   StringRef getDescription() const final {
95     return "Test a pass in the pass manager that always crashes";
96   }
97 };
98 
99 /// A test pass that always fails to enable testing the failure recovery
100 /// mechanisms of the pass manager.
101 struct TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestFailurePass102   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFailurePass)
103 
104   void runOnOperation() final { signalPassFailure(); }
getArgument__anon0807c3400111::TestFailurePass105   StringRef getArgument() const final { return "test-pass-failure"; }
getDescription__anon0807c3400111::TestFailurePass106   StringRef getDescription() const final {
107     return "Test a pass in the pass manager that always fails";
108   }
109 };
110 
111 /// A test pass that creates an invalid operation in a function body.
112 struct TestInvalidIRPass
113     : public PassWrapper<TestInvalidIRPass,
114                          InterfacePass<FunctionOpInterface>> {
115   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidIRPass)
116 
117   TestInvalidIRPass() = default;
TestInvalidIRPass__anon0807c3400111::TestInvalidIRPass118   TestInvalidIRPass(const TestInvalidIRPass &other) : PassWrapper(other) {}
119 
getArgument__anon0807c3400111::TestInvalidIRPass120   StringRef getArgument() const final { return "test-pass-create-invalid-ir"; }
getDescription__anon0807c3400111::TestInvalidIRPass121   StringRef getDescription() const final {
122     return "Test pass that adds an invalid operation in a function body";
123   }
getDependentDialects__anon0807c3400111::TestInvalidIRPass124   void getDependentDialects(DialectRegistry &registry) const final {
125     registry.insert<test::TestDialect>();
126   }
runOnOperation__anon0807c3400111::TestInvalidIRPass127   void runOnOperation() final {
128     if (signalFailure)
129       signalPassFailure();
130     if (!emitInvalidIR)
131       return;
132     OpBuilder b(getOperation().getBody());
133     OperationState state(b.getUnknownLoc(), "test.any_attr_of_i32_str");
134     b.create(state);
135   }
136   Option<bool> signalFailure{*this, "signal-pass-failure",
137                              llvm::cl::desc("Trigger a pass failure")};
138   Option<bool> emitInvalidIR{*this, "emit-invalid-ir", llvm::cl::init(true),
139                              llvm::cl::desc("Emit invalid IR")};
140 };
141 
142 /// A test pass that always fails to enable testing the failure recovery
143 /// mechanisms of the pass manager.
144 struct TestInvalidParentPass
145     : public PassWrapper<TestInvalidParentPass,
146                          InterfacePass<FunctionOpInterface>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0807c3400111::TestInvalidParentPass147   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass)
148 
149   StringRef getArgument() const final { return "test-pass-invalid-parent"; }
getDescription__anon0807c3400111::TestInvalidParentPass150   StringRef getDescription() const final {
151     return "Test a pass in the pass manager that makes the parent operation "
152            "invalid";
153   }
getDependentDialects__anon0807c3400111::TestInvalidParentPass154   void getDependentDialects(DialectRegistry &registry) const final {
155     registry.insert<test::TestDialect>();
156   }
runOnOperation__anon0807c3400111::TestInvalidParentPass157   void runOnOperation() final {
158     FunctionOpInterface op = getOperation();
159     OpBuilder b(getOperation().getBody());
160     b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func",
161                                ValueRange());
162   }
163 };
164 
165 /// A test pass that contains a statistic.
166 struct TestStatisticPass
167     : public PassWrapper<TestStatisticPass, OperationPass<>> {
168   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass)
169 
170   TestStatisticPass() = default;
TestStatisticPass__anon0807c3400111::TestStatisticPass171   TestStatisticPass(const TestStatisticPass &) : PassWrapper() {}
getArgument__anon0807c3400111::TestStatisticPass172   StringRef getArgument() const final { return "test-stats-pass"; }
getDescription__anon0807c3400111::TestStatisticPass173   StringRef getDescription() const final { return "Test pass statistics"; }
174 
175   // Use a couple of statistics to verify their ordering
176   // in the print out. The statistics are registered in the order
177   // of construction, so put "num-ops2" before "num-ops" and
178   // make sure that the order is reversed.
179   Statistic opCountDuplicate{this, "num-ops2",
180                              "Number of operations counted one more time"};
181   Statistic opCount{this, "num-ops", "Number of operations counted"};
182 
runOnOperation__anon0807c3400111::TestStatisticPass183   void runOnOperation() final {
184     getOperation()->walk([&](Operation *) { ++opCount; });
185     getOperation()->walk([&](Operation *) { ++opCountDuplicate; });
186   }
187 };
188 } // namespace
189 
testNestedPipeline(OpPassManager & pm)190 static void testNestedPipeline(OpPassManager &pm) {
191   // Nest a module pipeline that contains:
192   /// A module pass.
193   auto &modulePM = pm.nest<ModuleOp>();
194   modulePM.addPass(std::make_unique<TestModulePass>());
195   /// A nested function pass.
196   auto &nestedFunctionPM = modulePM.nest<func::FuncOp>();
197   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
198 
199   // Nest a function pipeline that contains a single pass.
200   auto &functionPM = pm.nest<func::FuncOp>();
201   functionPM.addPass(std::make_unique<TestFunctionPass>());
202 }
203 
testNestedPipelineTextual(OpPassManager & pm)204 static void testNestedPipelineTextual(OpPassManager &pm) {
205   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
206 }
207 
208 namespace mlir {
registerPassManagerTestPass()209 void registerPassManagerTestPass() {
210   PassRegistration<TestOptionsPass>();
211 
212   PassRegistration<TestModulePass>();
213 
214   PassRegistration<TestFunctionPass>();
215 
216   PassRegistration<TestInterfacePass>();
217 
218   PassRegistration<TestCrashRecoveryPass>();
219   PassRegistration<TestFailurePass>();
220   PassRegistration<TestInvalidIRPass>();
221   PassRegistration<TestInvalidParentPass>();
222 
223   PassRegistration<TestStatisticPass>();
224 
225   PassPipelineRegistration<>("test-pm-nested-pipeline",
226                              "Test a nested pipeline in the pass manager",
227                              testNestedPipeline);
228   PassPipelineRegistration<>("test-textual-pm-nested-pipeline",
229                              "Test a nested pipeline in the pass manager",
230                              testNestedPipelineTextual);
231   PassPipelineRegistration<>(
232       "test-dump-pipeline",
233       "Dumps the pipeline build so far for debugging purposes",
234       [](OpPassManager &pm) {
235         pm.printAsTextualPipeline(llvm::errs());
236         llvm::errs() << "\n";
237       });
238 
239   PassPipelineRegistration<TestOptionsPass::Options>
240       registerOptionsPassPipeline(
241           "test-options-pass-pipeline",
242           "Parses options using pass pipeline registration",
243           [](OpPassManager &pm, const TestOptionsPass::Options &options) {
244             pm.addPass(std::make_unique<TestOptionsPass>(options));
245           });
246 }
247 } // namespace mlir
248