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   void runOnOperation() final {}
21   StringRef getArgument() const final { return "test-module-pass"; }
22   StringRef getDescription() const final {
23     return "Test a module pass in the pass manager";
24   }
25 };
26 struct TestFunctionPass
27     : public PassWrapper<TestFunctionPass, OperationPass<FuncOp>> {
28   void runOnOperation() final {}
29   StringRef getArgument() const final { return "test-function-pass"; }
30   StringRef getDescription() const final {
31     return "Test a function pass in the pass manager";
32   }
33 };
34 class TestInterfacePass
35     : public PassWrapper<TestInterfacePass,
36                          InterfacePass<FunctionOpInterface>> {
37   void runOnOperation() final {
38     getOperation()->emitRemark() << "Executing interface pass on operation";
39   }
40   StringRef getArgument() const final { return "test-interface-pass"; }
41   StringRef getDescription() const final {
42     return "Test an interface pass (running on FunctionOpInterface) in the "
43            "pass manager";
44   }
45 };
46 class TestOptionsPass
47     : public PassWrapper<TestOptionsPass, OperationPass<FuncOp>> {
48 public:
49   struct Options : public PassPipelineOptions<Options> {
50     ListOption<int> listOption{*this, "list",
51                                llvm::cl::MiscFlags::CommaSeparated,
52                                llvm::cl::desc("Example list option")};
53     ListOption<std::string> stringListOption{
54         *this, "string-list", llvm::cl::MiscFlags::CommaSeparated,
55         llvm::cl::desc("Example string list option")};
56     Option<std::string> stringOption{*this, "string",
57                                      llvm::cl::desc("Example string option")};
58   };
59   TestOptionsPass() = default;
60   TestOptionsPass(const TestOptionsPass &) {}
61   TestOptionsPass(const Options &options) {
62     listOption = options.listOption;
63     stringOption = options.stringOption;
64     stringListOption = options.stringListOption;
65   }
66 
67   void runOnOperation() final {}
68   StringRef getArgument() const final { return "test-options-pass"; }
69   StringRef getDescription() const final {
70     return "Test options parsing capabilities";
71   }
72 
73   ListOption<int> listOption{*this, "list", llvm::cl::MiscFlags::CommaSeparated,
74                              llvm::cl::desc("Example list option")};
75   ListOption<std::string> stringListOption{
76       *this, "string-list", llvm::cl::MiscFlags::CommaSeparated,
77       llvm::cl::desc("Example string list option")};
78   Option<std::string> stringOption{*this, "string",
79                                    llvm::cl::desc("Example string option")};
80 };
81 
82 /// A test pass that always aborts to enable testing the crash recovery
83 /// mechanism of the pass manager.
84 class TestCrashRecoveryPass
85     : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> {
86   void runOnOperation() final { abort(); }
87   StringRef getArgument() const final { return "test-pass-crash"; }
88   StringRef getDescription() const final {
89     return "Test a pass in the pass manager that always crashes";
90   }
91 };
92 
93 /// A test pass that always fails to enable testing the failure recovery
94 /// mechanisms of the pass manager.
95 class TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> {
96   void runOnOperation() final { signalPassFailure(); }
97   StringRef getArgument() const final { return "test-pass-failure"; }
98   StringRef getDescription() const final {
99     return "Test a pass in the pass manager that always fails";
100   }
101 };
102 
103 /// A test pass that always fails to enable testing the failure recovery
104 /// mechanisms of the pass manager.
105 class TestInvalidParentPass
106     : public PassWrapper<TestInvalidParentPass,
107                          InterfacePass<FunctionOpInterface>> {
108   StringRef getArgument() const final { return "test-pass-invalid-parent"; }
109   StringRef getDescription() const final {
110     return "Test a pass in the pass manager that makes the parent operation "
111            "invalid";
112   }
113   void getDependentDialects(DialectRegistry &registry) const final {
114     registry.insert<test::TestDialect>();
115   }
116   void runOnOperation() final {
117     FunctionOpInterface op = getOperation();
118     OpBuilder b(getOperation().getBody());
119     b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func",
120                                ValueRange());
121   }
122 };
123 
124 /// A test pass that contains a statistic.
125 struct TestStatisticPass
126     : public PassWrapper<TestStatisticPass, OperationPass<>> {
127   TestStatisticPass() = default;
128   TestStatisticPass(const TestStatisticPass &) {}
129   StringRef getArgument() const final { return "test-stats-pass"; }
130   StringRef getDescription() const final { return "Test pass statistics"; }
131 
132   Statistic opCount{this, "num-ops", "Number of operations counted"};
133 
134   void runOnOperation() final {
135     getOperation()->walk([&](Operation *) { ++opCount; });
136   }
137 };
138 } // namespace
139 
140 static void testNestedPipeline(OpPassManager &pm) {
141   // Nest a module pipeline that contains:
142   /// A module pass.
143   auto &modulePM = pm.nest<ModuleOp>();
144   modulePM.addPass(std::make_unique<TestModulePass>());
145   /// A nested function pass.
146   auto &nestedFunctionPM = modulePM.nest<FuncOp>();
147   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
148 
149   // Nest a function pipeline that contains a single pass.
150   auto &functionPM = pm.nest<FuncOp>();
151   functionPM.addPass(std::make_unique<TestFunctionPass>());
152 }
153 
154 static void testNestedPipelineTextual(OpPassManager &pm) {
155   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
156 }
157 
158 namespace mlir {
159 void registerPassManagerTestPass() {
160   PassRegistration<TestOptionsPass>();
161 
162   PassRegistration<TestModulePass>();
163 
164   PassRegistration<TestFunctionPass>();
165 
166   PassRegistration<TestInterfacePass>();
167 
168   PassRegistration<TestCrashRecoveryPass>();
169   PassRegistration<TestFailurePass>();
170   PassRegistration<TestInvalidParentPass>();
171 
172   PassRegistration<TestStatisticPass>();
173 
174   PassPipelineRegistration<>("test-pm-nested-pipeline",
175                              "Test a nested pipeline in the pass manager",
176                              testNestedPipeline);
177   PassPipelineRegistration<>("test-textual-pm-nested-pipeline",
178                              "Test a nested pipeline in the pass manager",
179                              testNestedPipelineTextual);
180   PassPipelineRegistration<>(
181       "test-dump-pipeline",
182       "Dumps the pipeline build so far for debugging purposes",
183       [](OpPassManager &pm) {
184         pm.printAsTextualPipeline(llvm::errs());
185         llvm::errs() << "\n";
186       });
187 
188   PassPipelineRegistration<TestOptionsPass::Options>
189       registerOptionsPassPipeline(
190           "test-options-pass-pipeline",
191           "Parses options using pass pipeline registration",
192           [](OpPassManager &pm, const TestOptionsPass::Options &options) {
193             pm.addPass(std::make_unique<TestOptionsPass>(options));
194           });
195 }
196 } // namespace mlir
197