1120509a6SRiver Riddle //===- TestPassManager.cpp - Test pass manager functionality --------------===// 2120509a6SRiver Riddle // 330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information. 556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6120509a6SRiver Riddle // 756222a06SMehdi Amini //===----------------------------------------------------------------------===// 8120509a6SRiver Riddle 950f82e68SRiver Riddle #include "TestDialect.h" 10e95e94adSJeff Niu #include "TestOps.h" 1136550692SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h" 1265fcddffSRiver Riddle #include "mlir/IR/BuiltinOps.h" 13120509a6SRiver Riddle #include "mlir/Pass/Pass.h" 14120509a6SRiver Riddle #include "mlir/Pass/PassManager.h" 15120509a6SRiver Riddle 16120509a6SRiver Riddle using namespace mlir; 17120509a6SRiver Riddle 18120509a6SRiver Riddle namespace { 1980aca1eaSRiver Riddle struct TestModulePass 2080aca1eaSRiver Riddle : public PassWrapper<TestModulePass, OperationPass<ModuleOp>> { 215e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestModulePass) 225e50dd04SRiver Riddle 23722f909fSRiver Riddle void runOnOperation() final {} 24fa51c5afSRiver Riddle StringRef getArgument() const final { return "test-module-pass"; } 25b5e22e6dSMehdi Amini StringRef getDescription() const final { 26b5e22e6dSMehdi Amini return "Test a module pass in the pass manager"; 27b5e22e6dSMehdi Amini } 28120509a6SRiver Riddle }; 2941574554SRiver Riddle struct TestFunctionPass 3058ceae95SRiver Riddle : public PassWrapper<TestFunctionPass, OperationPass<func::FuncOp>> { 315e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFunctionPass) 325e50dd04SRiver Riddle 3341574554SRiver Riddle void runOnOperation() final {} 34fa51c5afSRiver Riddle StringRef getArgument() const final { return "test-function-pass"; } 35b5e22e6dSMehdi Amini StringRef getDescription() const final { 36b5e22e6dSMehdi Amini return "Test a function pass in the pass manager"; 37b5e22e6dSMehdi Amini } 38120509a6SRiver Riddle }; 395e50dd04SRiver Riddle struct TestInterfacePass 409c9a4317SRiver Riddle : public PassWrapper<TestInterfacePass, 419c9a4317SRiver Riddle InterfacePass<FunctionOpInterface>> { 425e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInterfacePass) 435e50dd04SRiver Riddle 449c9a4317SRiver Riddle void runOnOperation() final { 459c9a4317SRiver Riddle getOperation()->emitRemark() << "Executing interface pass on operation"; 469c9a4317SRiver Riddle } 479c9a4317SRiver Riddle StringRef getArgument() const final { return "test-interface-pass"; } 489c9a4317SRiver Riddle StringRef getDescription() const final { 499c9a4317SRiver Riddle return "Test an interface pass (running on FunctionOpInterface) in the " 509c9a4317SRiver Riddle "pass manager"; 519c9a4317SRiver Riddle } 529c9a4317SRiver Riddle }; 535e50dd04SRiver Riddle struct TestOptionsPass 5458ceae95SRiver Riddle : public PassWrapper<TestOptionsPass, OperationPass<func::FuncOp>> { 555e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPass) 565e50dd04SRiver Riddle 57165c6d12SNikhil Kalra enum Enum { Zero, One, Two }; 58710b5a12SChristian Sigg 5921610e66SRiver Riddle struct Options : public PassPipelineOptions<Options> { 6021610e66SRiver Riddle ListOption<int> listOption{*this, "list", 6174461512SMLIR Team llvm::cl::desc("Example list option")}; 6221610e66SRiver Riddle ListOption<std::string> stringListOption{ 636edef135SRiver Riddle *this, "string-list", llvm::cl::desc("Example string list option")}; 6474461512SMLIR Team Option<std::string> stringOption{*this, "string", 6574461512SMLIR Team llvm::cl::desc("Example string option")}; 66710b5a12SChristian Sigg Option<Enum> enumOption{ 67710b5a12SChristian Sigg *this, "enum", llvm::cl::desc("Example enum option"), 68710b5a12SChristian Sigg llvm::cl::values(clEnumValN(0, "zero", "Example zero value"), 69165c6d12SNikhil Kalra clEnumValN(1, "one", "Example one value"), 70165c6d12SNikhil Kalra clEnumValN(2, "two", "Example two value"))}; 71165c6d12SNikhil Kalra 72165c6d12SNikhil Kalra Options() = default; 73165c6d12SNikhil Kalra Options(const Options &rhs) { *this = rhs; } 74165c6d12SNikhil Kalra Options &operator=(const Options &rhs) { 75165c6d12SNikhil Kalra copyOptionValuesFrom(rhs); 76165c6d12SNikhil Kalra return *this; 77165c6d12SNikhil Kalra } 7874461512SMLIR Team }; 7921610e66SRiver Riddle TestOptionsPass() = default; 808919447cSJaved Absar TestOptionsPass(const TestOptionsPass &) : PassWrapper() {} 8174461512SMLIR Team TestOptionsPass(const Options &options) { 82400ad6f9SRiver Riddle listOption = options.listOption; 83400ad6f9SRiver Riddle stringOption = options.stringOption; 84400ad6f9SRiver Riddle stringListOption = options.stringListOption; 85710b5a12SChristian Sigg enumOption = options.enumOption; 8674461512SMLIR Team } 8774461512SMLIR Team 8841574554SRiver Riddle void runOnOperation() final {} 89fa51c5afSRiver Riddle StringRef getArgument() const final { return "test-options-pass"; } 90b5e22e6dSMehdi Amini StringRef getDescription() const final { 91b5e22e6dSMehdi Amini return "Test options parsing capabilities"; 92b5e22e6dSMehdi Amini } 9374461512SMLIR Team 946edef135SRiver Riddle ListOption<int> listOption{*this, "list", 9521610e66SRiver Riddle llvm::cl::desc("Example list option")}; 9621610e66SRiver Riddle ListOption<std::string> stringListOption{ 976edef135SRiver Riddle *this, "string-list", llvm::cl::desc("Example string list option")}; 9821610e66SRiver Riddle Option<std::string> stringOption{*this, "string", 9921610e66SRiver Riddle llvm::cl::desc("Example string option")}; 100710b5a12SChristian Sigg Option<Enum> enumOption{ 101710b5a12SChristian Sigg *this, "enum", llvm::cl::desc("Example enum option"), 102710b5a12SChristian Sigg llvm::cl::values(clEnumValN(0, "zero", "Example zero value"), 103165c6d12SNikhil Kalra clEnumValN(1, "one", "Example one value"), 104165c6d12SNikhil Kalra clEnumValN(2, "two", "Example two value"))}; 105165c6d12SNikhil Kalra }; 106165c6d12SNikhil Kalra 107165c6d12SNikhil Kalra struct TestOptionsSuperPass 108165c6d12SNikhil Kalra : public PassWrapper<TestOptionsSuperPass, OperationPass<func::FuncOp>> { 109165c6d12SNikhil Kalra MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsSuperPass) 110165c6d12SNikhil Kalra 111165c6d12SNikhil Kalra struct Options : public PassPipelineOptions<Options> { 112165c6d12SNikhil Kalra ListOption<TestOptionsPass::Options> listOption{ 113165c6d12SNikhil Kalra *this, "super-list", 114165c6d12SNikhil Kalra llvm::cl::desc("Example list of PassPipelineOptions option")}; 115165c6d12SNikhil Kalra 116165c6d12SNikhil Kalra Options() = default; 117165c6d12SNikhil Kalra }; 118165c6d12SNikhil Kalra 119165c6d12SNikhil Kalra TestOptionsSuperPass() = default; 120165c6d12SNikhil Kalra TestOptionsSuperPass(const TestOptionsSuperPass &) : PassWrapper() {} 121165c6d12SNikhil Kalra TestOptionsSuperPass(const Options &options) { 122165c6d12SNikhil Kalra listOption = options.listOption; 123165c6d12SNikhil Kalra } 124165c6d12SNikhil Kalra 125165c6d12SNikhil Kalra void runOnOperation() final {} 126165c6d12SNikhil Kalra StringRef getArgument() const final { return "test-options-super-pass"; } 127165c6d12SNikhil Kalra StringRef getDescription() const final { 128165c6d12SNikhil Kalra return "Test options of options parsing capabilities"; 129165c6d12SNikhil Kalra } 130165c6d12SNikhil Kalra 131165c6d12SNikhil Kalra ListOption<TestOptionsPass::Options> listOption{ 132165c6d12SNikhil Kalra *this, "list", 133165c6d12SNikhil Kalra llvm::cl::desc("Example list of PassPipelineOptions option")}; 13474461512SMLIR Team }; 1357a7dcc17SRiver Riddle 1367a7dcc17SRiver Riddle /// A test pass that always aborts to enable testing the crash recovery 1377a7dcc17SRiver Riddle /// mechanism of the pass manager. 1385e50dd04SRiver Riddle struct TestCrashRecoveryPass 13980aca1eaSRiver Riddle : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> { 1405e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCrashRecoveryPass) 1415e50dd04SRiver Riddle 1427a7dcc17SRiver Riddle void runOnOperation() final { abort(); } 143fa51c5afSRiver Riddle StringRef getArgument() const final { return "test-pass-crash"; } 144b5e22e6dSMehdi Amini StringRef getDescription() const final { 145b5e22e6dSMehdi Amini return "Test a pass in the pass manager that always crashes"; 146b5e22e6dSMehdi Amini } 1477a7dcc17SRiver Riddle }; 14833a64540SRiver Riddle 14964ce90e1SRiver Riddle /// A test pass that always fails to enable testing the failure recovery 15064ce90e1SRiver Riddle /// mechanisms of the pass manager. 1515e50dd04SRiver Riddle struct TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> { 1525e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFailurePass) 1535e50dd04SRiver Riddle 154*5b21fd29SBilly Zhu TestFailurePass() = default; 155*5b21fd29SBilly Zhu TestFailurePass(const TestFailurePass &other) : PassWrapper(other) {} 156*5b21fd29SBilly Zhu 157*5b21fd29SBilly Zhu void runOnOperation() final { 158*5b21fd29SBilly Zhu signalPassFailure(); 159*5b21fd29SBilly Zhu if (genDiagnostics) 160*5b21fd29SBilly Zhu mlir::emitError(getOperation()->getLoc(), "illegal operation"); 161*5b21fd29SBilly Zhu } 162b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-pass-failure"; } 163b5e22e6dSMehdi Amini StringRef getDescription() const final { 164b5e22e6dSMehdi Amini return "Test a pass in the pass manager that always fails"; 165b5e22e6dSMehdi Amini } 166*5b21fd29SBilly Zhu 167*5b21fd29SBilly Zhu Option<bool> genDiagnostics{*this, "gen-diagnostics", 168*5b21fd29SBilly Zhu llvm::cl::desc("Generate a diagnostic message")}; 16964ce90e1SRiver Riddle }; 17064ce90e1SRiver Riddle 17183892d76SMehdi Amini /// A test pass that creates an invalid operation in a function body. 17283892d76SMehdi Amini struct TestInvalidIRPass 17383892d76SMehdi Amini : public PassWrapper<TestInvalidIRPass, 17483892d76SMehdi Amini InterfacePass<FunctionOpInterface>> { 17583892d76SMehdi Amini MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidIRPass) 17683892d76SMehdi Amini 17783892d76SMehdi Amini TestInvalidIRPass() = default; 178b37d158fSMehdi Amini TestInvalidIRPass(const TestInvalidIRPass &other) : PassWrapper(other) {} 17983892d76SMehdi Amini 18083892d76SMehdi Amini StringRef getArgument() const final { return "test-pass-create-invalid-ir"; } 18183892d76SMehdi Amini StringRef getDescription() const final { 18283892d76SMehdi Amini return "Test pass that adds an invalid operation in a function body"; 18383892d76SMehdi Amini } 18483892d76SMehdi Amini void getDependentDialects(DialectRegistry ®istry) const final { 18583892d76SMehdi Amini registry.insert<test::TestDialect>(); 18683892d76SMehdi Amini } 18783892d76SMehdi Amini void runOnOperation() final { 18883892d76SMehdi Amini if (signalFailure) 18983892d76SMehdi Amini signalPassFailure(); 19083892d76SMehdi Amini if (!emitInvalidIR) 19183892d76SMehdi Amini return; 192ecba7c58SRiver Riddle OpBuilder b(getOperation().getFunctionBody()); 19383892d76SMehdi Amini OperationState state(b.getUnknownLoc(), "test.any_attr_of_i32_str"); 19483892d76SMehdi Amini b.create(state); 19583892d76SMehdi Amini } 19683892d76SMehdi Amini Option<bool> signalFailure{*this, "signal-pass-failure", 19783892d76SMehdi Amini llvm::cl::desc("Trigger a pass failure")}; 19883892d76SMehdi Amini Option<bool> emitInvalidIR{*this, "emit-invalid-ir", llvm::cl::init(true), 19983892d76SMehdi Amini llvm::cl::desc("Emit invalid IR")}; 20083892d76SMehdi Amini }; 20183892d76SMehdi Amini 20250f82e68SRiver Riddle /// A test pass that always fails to enable testing the failure recovery 20350f82e68SRiver Riddle /// mechanisms of the pass manager. 2045e50dd04SRiver Riddle struct TestInvalidParentPass 20550f82e68SRiver Riddle : public PassWrapper<TestInvalidParentPass, 20650f82e68SRiver Riddle InterfacePass<FunctionOpInterface>> { 2075e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass) 2085e50dd04SRiver Riddle 20950f82e68SRiver Riddle StringRef getArgument() const final { return "test-pass-invalid-parent"; } 21050f82e68SRiver Riddle StringRef getDescription() const final { 21150f82e68SRiver Riddle return "Test a pass in the pass manager that makes the parent operation " 21250f82e68SRiver Riddle "invalid"; 21350f82e68SRiver Riddle } 21450f82e68SRiver Riddle void getDependentDialects(DialectRegistry ®istry) const final { 21550f82e68SRiver Riddle registry.insert<test::TestDialect>(); 21650f82e68SRiver Riddle } 21750f82e68SRiver Riddle void runOnOperation() final { 21850f82e68SRiver Riddle FunctionOpInterface op = getOperation(); 219ecba7c58SRiver Riddle OpBuilder b(op.getFunctionBody()); 22050f82e68SRiver Riddle b.create<test::TestCallOp>(op.getLoc(), TypeRange(), "some_unknown_func", 22150f82e68SRiver Riddle ValueRange()); 22250f82e68SRiver Riddle } 22350f82e68SRiver Riddle }; 22450f82e68SRiver Riddle 22533a64540SRiver Riddle /// A test pass that contains a statistic. 22680aca1eaSRiver Riddle struct TestStatisticPass 22780aca1eaSRiver Riddle : public PassWrapper<TestStatisticPass, OperationPass<>> { 2285e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass) 2295e50dd04SRiver Riddle 23033a64540SRiver Riddle TestStatisticPass() = default; 2318919447cSJaved Absar TestStatisticPass(const TestStatisticPass &) : PassWrapper() {} 232b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-stats-pass"; } 233b5e22e6dSMehdi Amini StringRef getDescription() const final { return "Test pass statistics"; } 23433a64540SRiver Riddle 23504644a9eSSlava Zakharin // Use a couple of statistics to verify their ordering 23604644a9eSSlava Zakharin // in the print out. The statistics are registered in the order 23704644a9eSSlava Zakharin // of construction, so put "num-ops2" before "num-ops" and 23804644a9eSSlava Zakharin // make sure that the order is reversed. 23904644a9eSSlava Zakharin Statistic opCountDuplicate{this, "num-ops2", 24004644a9eSSlava Zakharin "Number of operations counted one more time"}; 24133a64540SRiver Riddle Statistic opCount{this, "num-ops", "Number of operations counted"}; 24233a64540SRiver Riddle 24333a64540SRiver Riddle void runOnOperation() final { 24433a64540SRiver Riddle getOperation()->walk([&](Operation *) { ++opCount; }); 24504644a9eSSlava Zakharin getOperation()->walk([&](Operation *) { ++opCountDuplicate; }); 24633a64540SRiver Riddle } 24733a64540SRiver Riddle }; 248be0a7e9fSMehdi Amini } // namespace 249120509a6SRiver Riddle 2509274ed66SRiver Riddle static void testNestedPipeline(OpPassManager &pm) { 251120509a6SRiver Riddle // Nest a module pipeline that contains: 252120509a6SRiver Riddle /// A module pass. 253120509a6SRiver Riddle auto &modulePM = pm.nest<ModuleOp>(); 254120509a6SRiver Riddle modulePM.addPass(std::make_unique<TestModulePass>()); 255120509a6SRiver Riddle /// A nested function pass. 25658ceae95SRiver Riddle auto &nestedFunctionPM = modulePM.nest<func::FuncOp>(); 257120509a6SRiver Riddle nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>()); 258120509a6SRiver Riddle 259120509a6SRiver Riddle // Nest a function pipeline that contains a single pass. 26058ceae95SRiver Riddle auto &functionPM = pm.nest<func::FuncOp>(); 261120509a6SRiver Riddle functionPM.addPass(std::make_unique<TestFunctionPass>()); 262120509a6SRiver Riddle } 263120509a6SRiver Riddle 264d780bdefSRiver Riddle static void testNestedPipelineTextual(OpPassManager &pm) { 265d780bdefSRiver Riddle (void)parsePassPipeline("test-pm-nested-pipeline", pm); 266d780bdefSRiver Riddle } 267d780bdefSRiver Riddle 268c6477050SMehdi Amini namespace mlir { 269c6477050SMehdi Amini void registerPassManagerTestPass() { 270b5e22e6dSMehdi Amini PassRegistration<TestOptionsPass>(); 271165c6d12SNikhil Kalra PassRegistration<TestOptionsSuperPass>(); 27274461512SMLIR Team 273b5e22e6dSMehdi Amini PassRegistration<TestModulePass>(); 2749274ed66SRiver Riddle 275b5e22e6dSMehdi Amini PassRegistration<TestFunctionPass>(); 2767a7dcc17SRiver Riddle 2779c9a4317SRiver Riddle PassRegistration<TestInterfacePass>(); 2789c9a4317SRiver Riddle 279b5e22e6dSMehdi Amini PassRegistration<TestCrashRecoveryPass>(); 280b5e22e6dSMehdi Amini PassRegistration<TestFailurePass>(); 28183892d76SMehdi Amini PassRegistration<TestInvalidIRPass>(); 28250f82e68SRiver Riddle PassRegistration<TestInvalidParentPass>(); 283c6477050SMehdi Amini 284b5e22e6dSMehdi Amini PassRegistration<TestStatisticPass>(); 28533a64540SRiver Riddle 286c6477050SMehdi Amini PassPipelineRegistration<>("test-pm-nested-pipeline", 287c6477050SMehdi Amini "Test a nested pipeline in the pass manager", 288c6477050SMehdi Amini testNestedPipeline); 289c6477050SMehdi Amini PassPipelineRegistration<>("test-textual-pm-nested-pipeline", 290d780bdefSRiver Riddle "Test a nested pipeline in the pass manager", 291d780bdefSRiver Riddle testNestedPipelineTextual); 29274461512SMLIR Team 293c6477050SMehdi Amini PassPipelineRegistration<TestOptionsPass::Options> 29474461512SMLIR Team registerOptionsPassPipeline( 29574461512SMLIR Team "test-options-pass-pipeline", 29674461512SMLIR Team "Parses options using pass pipeline registration", 29774461512SMLIR Team [](OpPassManager &pm, const TestOptionsPass::Options &options) { 29874461512SMLIR Team pm.addPass(std::make_unique<TestOptionsPass>(options)); 29974461512SMLIR Team }); 300165c6d12SNikhil Kalra 301165c6d12SNikhil Kalra PassPipelineRegistration<TestOptionsSuperPass::Options> 302165c6d12SNikhil Kalra registerOptionsSuperPassPipeline( 303165c6d12SNikhil Kalra "test-options-super-pass-pipeline", 304165c6d12SNikhil Kalra "Parses options of PassPipelineOptions using pass pipeline " 305165c6d12SNikhil Kalra "registration", 306165c6d12SNikhil Kalra [](OpPassManager &pm, const TestOptionsSuperPass::Options &options) { 307165c6d12SNikhil Kalra pm.addPass(std::make_unique<TestOptionsSuperPass>(options)); 308165c6d12SNikhil Kalra }); 309c6477050SMehdi Amini } 310c6477050SMehdi Amini } // namespace mlir 311