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 "mlir/IR/BuiltinOps.h"
10 #include "mlir/Pass/Pass.h"
11 #include "mlir/Pass/PassManager.h"
12 
13 using namespace mlir;
14 
15 namespace {
16 struct TestModulePass
17     : public PassWrapper<TestModulePass, OperationPass<ModuleOp>> {
18   void runOnOperation() final {}
19 };
20 struct TestFunctionPass : public PassWrapper<TestFunctionPass, FunctionPass> {
21   void runOnFunction() final {}
22 };
23 class TestOptionsPass : public PassWrapper<TestOptionsPass, FunctionPass> {
24 public:
25   struct Options : public PassPipelineOptions<Options> {
26     ListOption<int> listOption{*this, "list",
27                                llvm::cl::MiscFlags::CommaSeparated,
28                                llvm::cl::desc("Example list option")};
29     ListOption<std::string> stringListOption{
30         *this, "string-list", llvm::cl::MiscFlags::CommaSeparated,
31         llvm::cl::desc("Example string list option")};
32     Option<std::string> stringOption{*this, "string",
33                                      llvm::cl::desc("Example string option")};
34   };
35   TestOptionsPass() = default;
36   TestOptionsPass(const TestOptionsPass &) {}
37   TestOptionsPass(const Options &options) {
38     listOption = options.listOption;
39     stringOption = options.stringOption;
40     stringListOption = options.stringListOption;
41   }
42 
43   void runOnFunction() final {}
44 
45   ListOption<int> listOption{*this, "list", llvm::cl::MiscFlags::CommaSeparated,
46                              llvm::cl::desc("Example list option")};
47   ListOption<std::string> stringListOption{
48       *this, "string-list", llvm::cl::MiscFlags::CommaSeparated,
49       llvm::cl::desc("Example string list option")};
50   Option<std::string> stringOption{*this, "string",
51                                    llvm::cl::desc("Example string option")};
52 };
53 
54 /// A test pass that always aborts to enable testing the crash recovery
55 /// mechanism of the pass manager.
56 class TestCrashRecoveryPass
57     : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> {
58   void runOnOperation() final { abort(); }
59 };
60 
61 /// A test pass that always fails to enable testing the failure recovery
62 /// mechanisms of the pass manager.
63 class TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> {
64   void runOnOperation() final { signalPassFailure(); }
65 };
66 
67 /// A test pass that contains a statistic.
68 struct TestStatisticPass
69     : public PassWrapper<TestStatisticPass, OperationPass<>> {
70   TestStatisticPass() = default;
71   TestStatisticPass(const TestStatisticPass &) {}
72 
73   Statistic opCount{this, "num-ops", "Number of operations counted"};
74 
75   void runOnOperation() final {
76     getOperation()->walk([&](Operation *) { ++opCount; });
77   }
78 };
79 } // end anonymous namespace
80 
81 static void testNestedPipeline(OpPassManager &pm) {
82   // Nest a module pipeline that contains:
83   /// A module pass.
84   auto &modulePM = pm.nest<ModuleOp>();
85   modulePM.addPass(std::make_unique<TestModulePass>());
86   /// A nested function pass.
87   auto &nestedFunctionPM = modulePM.nest<FuncOp>();
88   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
89 
90   // Nest a function pipeline that contains a single pass.
91   auto &functionPM = pm.nest<FuncOp>();
92   functionPM.addPass(std::make_unique<TestFunctionPass>());
93 }
94 
95 static void testNestedPipelineTextual(OpPassManager &pm) {
96   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
97 }
98 
99 namespace mlir {
100 void registerPassManagerTestPass() {
101   PassRegistration<TestOptionsPass>("test-options-pass",
102                                     "Test options parsing capabilities");
103 
104   PassRegistration<TestModulePass>("test-module-pass",
105                                    "Test a module pass in the pass manager");
106 
107   PassRegistration<TestFunctionPass>(
108       "test-function-pass", "Test a function pass in the pass manager");
109 
110   PassRegistration<TestCrashRecoveryPass>(
111       "test-pass-crash", "Test a pass in the pass manager that always crashes");
112   PassRegistration<TestFailurePass>(
113       "test-pass-failure", "Test a pass in the pass manager that always fails");
114 
115   PassRegistration<TestStatisticPass> unusedStatP("test-stats-pass",
116                                                   "Test pass statistics");
117 
118   PassPipelineRegistration<>("test-pm-nested-pipeline",
119                              "Test a nested pipeline in the pass manager",
120                              testNestedPipeline);
121   PassPipelineRegistration<>("test-textual-pm-nested-pipeline",
122                              "Test a nested pipeline in the pass manager",
123                              testNestedPipelineTextual);
124   PassPipelineRegistration<>(
125       "test-dump-pipeline",
126       "Dumps the pipeline build so far for debugging purposes",
127       [](OpPassManager &pm) {
128         pm.printAsTextualPipeline(llvm::errs());
129         llvm::errs() << "\n";
130       });
131 
132   PassPipelineRegistration<TestOptionsPass::Options>
133       registerOptionsPassPipeline(
134           "test-options-pass-pipeline",
135           "Parses options using pass pipeline registration",
136           [](OpPassManager &pm, const TestOptionsPass::Options &options) {
137             pm.addPass(std::make_unique<TestOptionsPass>(options));
138           });
139 }
140 } // namespace mlir
141