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 ®istry) 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 ®istry) 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