1 //===- TestPassManager.cpp - Test pass manager functionality --------------===//
2 //
3 // Copyright 2019 The MLIR Authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // =============================================================================
17 
18 #include "mlir/IR/Function.h"
19 #include "mlir/Pass/Pass.h"
20 #include "mlir/Pass/PassManager.h"
21 
22 using namespace mlir;
23 
24 namespace {
25 struct TestModulePass : public ModulePass<TestModulePass> {
26   void runOnModule() final {}
27 };
28 struct TestFunctionPass : public FunctionPass<TestFunctionPass> {
29   void runOnFunction() final {}
30 };
31 class TestOptionsPass : public FunctionPass<TestOptionsPass> {
32 public:
33   struct Options : public PassOptions<Options> {
34     List<int> listOption{*this, "list", llvm::cl::MiscFlags::CommaSeparated,
35                          llvm::cl::desc("Example list option")};
36     List<std::string> stringListOption{
37         *this, "string-list", llvm::cl::MiscFlags::CommaSeparated,
38         llvm::cl::desc("Example string list option")};
39     Option<std::string> stringOption{*this, "string",
40                                      llvm::cl::desc("Example string option")};
41   };
42   TestOptionsPass(const Options &options) {
43     listOption.assign(options.listOption.begin(), options.listOption.end());
44     stringOption = options.stringOption;
45     stringListOption.assign(options.stringListOption.begin(),
46                             options.stringListOption.end());
47   }
48 
49   void printAsTextualPipeline(raw_ostream &os) final {
50     os << "test-options-pass{";
51     if (!listOption.empty()) {
52       os << "list=";
53       // Not interleaveComma to avoid spaces between the elements.
54       interleave(listOption, os, ",");
55     }
56     if (!stringListOption.empty()) {
57       os << " string-list=";
58       interleave(stringListOption, os, ",");
59     }
60     if (!stringOption.empty())
61       os << " string=" << stringOption;
62     os << "}";
63   }
64 
65   void runOnFunction() final {}
66 
67   SmallVector<int64_t, 4> listOption;
68   SmallVector<std::string, 4> stringListOption;
69   std::string stringOption;
70 };
71 
72 /// A test pass that always aborts to enable testing the crash recovery
73 /// mechanism of the pass manager.
74 class TestCrashRecoveryPass : public OperationPass<TestCrashRecoveryPass> {
75   void runOnOperation() final { abort(); }
76 };
77 
78 /// A test pass that contains a statistic.
79 struct TestStatisticPass : public OperationPass<TestStatisticPass> {
80   TestStatisticPass() = default;
81   TestStatisticPass(const TestStatisticPass &) {}
82 
83   Statistic opCount{this, "num-ops", "Number of operations counted"};
84 
85   void runOnOperation() final {
86     getOperation()->walk([&](Operation *) { ++opCount; });
87   }
88 };
89 } // end anonymous namespace
90 
91 static void testNestedPipeline(OpPassManager &pm) {
92   // Nest a module pipeline that contains:
93   /// A module pass.
94   auto &modulePM = pm.nest<ModuleOp>();
95   modulePM.addPass(std::make_unique<TestModulePass>());
96   /// A nested function pass.
97   auto &nestedFunctionPM = modulePM.nest<FuncOp>();
98   nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());
99 
100   // Nest a function pipeline that contains a single pass.
101   auto &functionPM = pm.nest<FuncOp>();
102   functionPM.addPass(std::make_unique<TestFunctionPass>());
103 }
104 
105 static void testNestedPipelineTextual(OpPassManager &pm) {
106   (void)parsePassPipeline("test-pm-nested-pipeline", pm);
107 }
108 
109 static PassRegistration<TestOptionsPass, TestOptionsPass::Options>
110     reg("test-options-pass", "Test options parsing capabilities");
111 
112 static PassRegistration<TestModulePass>
113     unusedMP("test-module-pass", "Test a module pass in the pass manager");
114 static PassRegistration<TestFunctionPass>
115     unusedFP("test-function-pass", "Test a function pass in the pass manager");
116 
117 static PassRegistration<TestCrashRecoveryPass>
118     unusedCrashP("test-pass-crash",
119                  "Test a pass in the pass manager that always crashes");
120 
121 static PassRegistration<TestStatisticPass> unusedStatP("test-stats-pass",
122                                                        "Test pass statistics");
123 
124 static PassPipelineRegistration<>
125     unused("test-pm-nested-pipeline",
126            "Test a nested pipeline in the pass manager", testNestedPipeline);
127 static PassPipelineRegistration<>
128     unusedTextual("test-textual-pm-nested-pipeline",
129                   "Test a nested pipeline in the pass manager",
130                   testNestedPipelineTextual);
131 static PassPipelineRegistration<>
132     unusedDump("test-dump-pipeline",
133                "Dumps the pipeline build so far for debugging purposes",
134                [](OpPassManager &pm) {
135                  pm.printAsTextualPipeline(llvm::errs());
136                  llvm::errs() << "\n";
137                });
138 
139 static PassPipelineRegistration<TestOptionsPass::Options>
140     registerOptionsPassPipeline(
141         "test-options-pass-pipeline",
142         "Parses options using pass pipeline registration",
143         [](OpPassManager &pm, const TestOptionsPass::Options &options) {
144           pm.addPass(std::make_unique<TestOptionsPass>(options));
145         });
146