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