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<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<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 &) {} 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 always fails to enable testing the failure recovery 112 /// mechanisms of the pass manager. 113 struct TestInvalidParentPass 114 : public PassWrapper<TestInvalidParentPass, 115 InterfacePass<FunctionOpInterface>> { 116 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass) 117 118 StringRef getArgument() const final { return "test-pass-invalid-parent"; } 119 StringRef getDescription() const final { 120 return "Test a pass in the pass manager that makes the parent operation " 121 "invalid"; 122 } 123 void getDependentDialects(DialectRegistry ®istry) const final { 124 registry.insert<test::TestDialect>(); 125 } 126 void runOnOperation() final { 127 FunctionOpInterface op = getOperation(); 128 OpBuilder b(getOperation().getBody()); 129 b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func", 130 ValueRange()); 131 } 132 }; 133 134 /// A test pass that contains a statistic. 135 struct TestStatisticPass 136 : public PassWrapper<TestStatisticPass, OperationPass<>> { 137 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass) 138 139 TestStatisticPass() = default; 140 TestStatisticPass(const TestStatisticPass &) {} 141 StringRef getArgument() const final { return "test-stats-pass"; } 142 StringRef getDescription() const final { return "Test pass statistics"; } 143 144 Statistic opCount{this, "num-ops", "Number of operations counted"}; 145 146 void runOnOperation() final { 147 getOperation()->walk([&](Operation *) { ++opCount; }); 148 } 149 }; 150 } // namespace 151 152 static void testNestedPipeline(OpPassManager &pm) { 153 // Nest a module pipeline that contains: 154 /// A module pass. 155 auto &modulePM = pm.nest<ModuleOp>(); 156 modulePM.addPass(std::make_unique<TestModulePass>()); 157 /// A nested function pass. 158 auto &nestedFunctionPM = modulePM.nest<FuncOp>(); 159 nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>()); 160 161 // Nest a function pipeline that contains a single pass. 162 auto &functionPM = pm.nest<FuncOp>(); 163 functionPM.addPass(std::make_unique<TestFunctionPass>()); 164 } 165 166 static void testNestedPipelineTextual(OpPassManager &pm) { 167 (void)parsePassPipeline("test-pm-nested-pipeline", pm); 168 } 169 170 namespace mlir { 171 void registerPassManagerTestPass() { 172 PassRegistration<TestOptionsPass>(); 173 174 PassRegistration<TestModulePass>(); 175 176 PassRegistration<TestFunctionPass>(); 177 178 PassRegistration<TestInterfacePass>(); 179 180 PassRegistration<TestCrashRecoveryPass>(); 181 PassRegistration<TestFailurePass>(); 182 PassRegistration<TestInvalidParentPass>(); 183 184 PassRegistration<TestStatisticPass>(); 185 186 PassPipelineRegistration<>("test-pm-nested-pipeline", 187 "Test a nested pipeline in the pass manager", 188 testNestedPipeline); 189 PassPipelineRegistration<>("test-textual-pm-nested-pipeline", 190 "Test a nested pipeline in the pass manager", 191 testNestedPipelineTextual); 192 PassPipelineRegistration<>( 193 "test-dump-pipeline", 194 "Dumps the pipeline build so far for debugging purposes", 195 [](OpPassManager &pm) { 196 pm.printAsTextualPipeline(llvm::errs()); 197 llvm::errs() << "\n"; 198 }); 199 200 PassPipelineRegistration<TestOptionsPass::Options> 201 registerOptionsPassPipeline( 202 "test-options-pass-pipeline", 203 "Parses options using pass pipeline registration", 204 [](OpPassManager &pm, const TestOptionsPass::Options &options) { 205 pm.addPass(std::make_unique<TestOptionsPass>(options)); 206 }); 207 } 208 } // namespace mlir 209