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 ®istry) 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