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