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>> {
20   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestModulePass)
21 
22   void runOnOperation() final {}
23   StringRef getArgument() const final { return "test-module-pass"; }
24   StringRef getDescription() const final {
25     return "Test a module pass in the pass manager";
26   }
27 };
28 struct TestFunctionPass
29     : public PassWrapper<TestFunctionPass, OperationPass<FuncOp>> {
30   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFunctionPass)
31 
32   void runOnOperation() final {}
33   StringRef getArgument() const final { return "test-function-pass"; }
34   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>> {
41   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInterfacePass)
42 
43   void runOnOperation() final {
44     getOperation()->emitRemark() << "Executing interface pass on operation";
45   }
46   StringRef getArgument() const final { return "test-interface-pass"; }
47   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<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;
65   TestOptionsPass(const TestOptionsPass &) {}
66   TestOptionsPass(const Options &options) {
67     listOption = options.listOption;
68     stringOption = options.stringOption;
69     stringListOption = options.stringListOption;
70   }
71 
72   void runOnOperation() final {}
73   StringRef getArgument() const final { return "test-options-pass"; }
74   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<>> {
90   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCrashRecoveryPass)
91 
92   void runOnOperation() final { abort(); }
93   StringRef getArgument() const final { return "test-pass-crash"; }
94   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<>> {
102   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFailurePass)
103 
104   void runOnOperation() final { signalPassFailure(); }
105   StringRef getArgument() const final { return "test-pass-failure"; }
106   StringRef getDescription() const final {
107     return "Test a pass in the pass manager that always fails";
108   }
109 };
110 
111 /// A test pass that always fails to enable testing the failure recovery
112 /// mechanisms of the pass manager.
113 struct TestInvalidParentPass
114     : public PassWrapper<TestInvalidParentPass,
115                          InterfacePass<FunctionOpInterface>> {
116   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass)
117 
118   StringRef getArgument() const final { return "test-pass-invalid-parent"; }
119   StringRef getDescription() const final {
120     return "Test a pass in the pass manager that makes the parent operation "
121            "invalid";
122   }
123   void getDependentDialects(DialectRegistry &registry) const final {
124     registry.insert<test::TestDialect>();
125   }
126   void runOnOperation() final {
127     FunctionOpInterface op = getOperation();
128     OpBuilder b(getOperation().getBody());
129     b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func",
130                                ValueRange());
131   }
132 };
133 
134 /// A test pass that contains a statistic.
135 struct TestStatisticPass
136     : public PassWrapper<TestStatisticPass, OperationPass<>> {
137   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass)
138 
139   TestStatisticPass() = default;
140   TestStatisticPass(const TestStatisticPass &) {}
141   StringRef getArgument() const final { return "test-stats-pass"; }
142   StringRef getDescription() const final { return "Test pass statistics"; }
143 
144   Statistic opCount{this, "num-ops", "Number of operations counted"};
145 
146   void runOnOperation() final {
147     getOperation()->walk([&](Operation *) { ++opCount; });
148   }
149 };
150 } // namespace
151 
152 static void testNestedPipeline(OpPassManager &pm) {
153   // Nest a module pipeline that contains:
154   /// A module pass.
155   auto &modulePM = pm.nest<ModuleOp>();
156   modulePM.addPass(std::make_unique<TestModulePass>());
157   /// A nested function pass.
158   auto &nestedFunctionPM = modulePM.nest<FuncOp>();
159   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
160 
161   // Nest a function pipeline that contains a single pass.
162   auto &functionPM = pm.nest<FuncOp>();
163   functionPM.addPass(std::make_unique<TestFunctionPass>());
164 }
165 
166 static void testNestedPipelineTextual(OpPassManager &pm) {
167   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
168 }
169 
170 namespace mlir {
171 void registerPassManagerTestPass() {
172   PassRegistration<TestOptionsPass>();
173 
174   PassRegistration<TestModulePass>();
175 
176   PassRegistration<TestFunctionPass>();
177 
178   PassRegistration<TestInterfacePass>();
179 
180   PassRegistration<TestCrashRecoveryPass>();
181   PassRegistration<TestFailurePass>();
182   PassRegistration<TestInvalidParentPass>();
183 
184   PassRegistration<TestStatisticPass>();
185 
186   PassPipelineRegistration<>("test-pm-nested-pipeline",
187                              "Test a nested pipeline in the pass manager",
188                              testNestedPipeline);
189   PassPipelineRegistration<>("test-textual-pm-nested-pipeline",
190                              "Test a nested pipeline in the pass manager",
191                              testNestedPipelineTextual);
192   PassPipelineRegistration<>(
193       "test-dump-pipeline",
194       "Dumps the pipeline build so far for debugging purposes",
195       [](OpPassManager &pm) {
196         pm.printAsTextualPipeline(llvm::errs());
197         llvm::errs() << "\n";
198       });
199 
200   PassPipelineRegistration<TestOptionsPass::Options>
201       registerOptionsPassPipeline(
202           "test-options-pass-pipeline",
203           "Parses options using pass pipeline registration",
204           [](OpPassManager &pm, const TestOptionsPass::Options &options) {
205             pm.addPass(std::make_unique<TestOptionsPass>(options));
206           });
207 }
208 } // namespace mlir
209