370 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "TestDialect.h"10#include "TestOps.h"11#include "mlir/Dialect/Func/IR/FuncOps.h"12#include "mlir/IR/BuiltinOps.h"13#include "mlir/Pass/Pass.h"14#include "mlir/Pass/PassManager.h"15 16using namespace mlir;17 18namespace {19struct TestModulePass20 : public PassWrapper<TestModulePass, OperationPass<ModuleOp>> {21 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestModulePass)22 23 void runOnOperation() final {}24 StringRef getArgument() const final { return "test-module-pass"; }25 StringRef getDescription() const final {26 return "Test a module pass in the pass manager";27 }28};29struct TestFunctionPass30 : public PassWrapper<TestFunctionPass, OperationPass<func::FuncOp>> {31 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFunctionPass)32 33 void runOnOperation() final {}34 StringRef getArgument() const final { return "test-function-pass"; }35 StringRef getDescription() const final {36 return "Test a function pass in the pass manager";37 }38};39struct TestInterfacePass40 : public PassWrapper<TestInterfacePass,41 InterfacePass<FunctionOpInterface>> {42 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInterfacePass)43 44 void runOnOperation() final {45 getOperation()->emitRemark() << "Executing interface pass on operation";46 }47 StringRef getArgument() const final { return "test-interface-pass"; }48 StringRef getDescription() const final {49 return "Test an interface pass (running on FunctionOpInterface) in the "50 "pass manager";51 }52};53struct TestOptionsPass54 : public PassWrapper<TestOptionsPass, OperationPass<func::FuncOp>> {55 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPass)56 57 enum Enum { Zero, One, Two };58 59 struct Options : public PassPipelineOptions<Options> {60 ListOption<int> listOption{*this, "list",61 llvm::cl::desc("Example list option")};62 ListOption<std::string> stringListOption{63 *this, "string-list", llvm::cl::desc("Example string list option")};64 Option<std::string> stringOption{*this, "string",65 llvm::cl::desc("Example string option")};66 Option<Enum> enumOption{67 *this, "enum", llvm::cl::desc("Example enum option"),68 llvm::cl::values(clEnumValN(0, "zero", "Example zero value"),69 clEnumValN(1, "one", "Example one value"),70 clEnumValN(2, "two", "Example two value"))};71 72 Options() = default;73 Options(const Options &rhs) { *this = rhs; }74 Options &operator=(const Options &rhs) {75 copyOptionValuesFrom(rhs);76 return *this;77 }78 };79 TestOptionsPass() = default;80 TestOptionsPass(const TestOptionsPass &) : PassWrapper() {}81 TestOptionsPass(const Options &options) {82 listOption = options.listOption;83 stringOption = options.stringOption;84 stringListOption = options.stringListOption;85 enumOption = options.enumOption;86 }87 88 void runOnOperation() final {}89 StringRef getArgument() const final { return "test-options-pass"; }90 StringRef getDescription() const final {91 return "Test options parsing capabilities";92 }93 94 ListOption<int> listOption{*this, "list",95 llvm::cl::desc("Example list option")};96 ListOption<std::string> stringListOption{97 *this, "string-list", llvm::cl::desc("Example string list option")};98 Option<std::string> stringOption{*this, "string",99 llvm::cl::desc("Example string option")};100 Option<Enum> enumOption{101 *this, "enum", llvm::cl::desc("Example enum option"),102 llvm::cl::values(clEnumValN(0, "zero", "Example zero value"),103 clEnumValN(1, "one", "Example one value"),104 clEnumValN(2, "two", "Example two value"))};105};106 107struct TestOptionsSuperPass108 : public PassWrapper<TestOptionsSuperPass, OperationPass<func::FuncOp>> {109 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsSuperPass)110 111 struct Options : public PassPipelineOptions<Options> {112 ListOption<TestOptionsPass::Options> listOption{113 *this, "super-list",114 llvm::cl::desc("Example list of PassPipelineOptions option")};115 116 Options() = default;117 };118 119 TestOptionsSuperPass() = default;120 TestOptionsSuperPass(const TestOptionsSuperPass &) : PassWrapper() {}121 TestOptionsSuperPass(const Options &options) {122 listOption = options.listOption;123 }124 125 void runOnOperation() final {}126 StringRef getArgument() const final { return "test-options-super-pass"; }127 StringRef getDescription() const final {128 return "Test options of options parsing capabilities";129 }130 131 ListOption<TestOptionsPass::Options> listOption{132 *this, "list",133 llvm::cl::desc("Example list of PassPipelineOptions option")};134};135 136struct TestOptionsPassA137 : public PassWrapper<TestOptionsPassA, OperationPass<func::FuncOp>> {138 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPassA)139 140 struct Options : public PassPipelineOptions<Options> {141 Option<bool> foo{*this, "foo", llvm::cl::desc("Example boolean option")};142 };143 144 TestOptionsPassA() = default;145 TestOptionsPassA(const TestOptionsPassA &) : PassWrapper() {}146 TestOptionsPassA(const Options &options) { this->options.foo = options.foo; }147 148 void runOnOperation() final {}149 StringRef getArgument() const final { return "test-options-pass-a"; }150 StringRef getDescription() const final {151 return "Test superset options parsing capabilities - subset A";152 }153 154 Options options;155};156 157struct TestOptionsPassB158 : public PassWrapper<TestOptionsPassB, OperationPass<func::FuncOp>> {159 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOptionsPassB)160 161 struct Options : public PassPipelineOptions<Options> {162 Option<bool> bar{*this, "bar", llvm::cl::desc("Example boolean option")};163 };164 165 TestOptionsPassB() = default;166 TestOptionsPassB(const TestOptionsPassB &) : PassWrapper() {}167 TestOptionsPassB(const Options &options) { this->options.bar = options.bar; }168 169 void runOnOperation() final {}170 StringRef getArgument() const final { return "test-options-pass-b"; }171 StringRef getDescription() const final {172 return "Test superset options parsing capabilities - subset B";173 }174 175 Options options;176};177 178struct TestPipelineOptionsSuperSetAB : TestOptionsPassA::Options,179 TestOptionsPassB::Options {};180 181/// A test pass that always aborts to enable testing the crash recovery182/// mechanism of the pass manager.183struct TestCrashRecoveryPass184 : public PassWrapper<TestCrashRecoveryPass, OperationPass<>> {185 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCrashRecoveryPass)186 187 void runOnOperation() final { abort(); }188 StringRef getArgument() const final { return "test-pass-crash"; }189 StringRef getDescription() const final {190 return "Test a pass in the pass manager that always crashes";191 }192};193 194/// A test pass that always fails to enable testing the failure recovery195/// mechanisms of the pass manager.196struct TestFailurePass : public PassWrapper<TestFailurePass, OperationPass<>> {197 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestFailurePass)198 199 TestFailurePass() = default;200 TestFailurePass(const TestFailurePass &other) : PassWrapper(other) {}201 202 void runOnOperation() final {203 signalPassFailure();204 if (genDiagnostics)205 mlir::emitError(getOperation()->getLoc(), "illegal operation");206 }207 StringRef getArgument() const final { return "test-pass-failure"; }208 StringRef getDescription() const final {209 return "Test a pass in the pass manager that always fails";210 }211 212 Option<bool> genDiagnostics{*this, "gen-diagnostics",213 llvm::cl::desc("Generate a diagnostic message")};214};215 216/// A test pass that creates an invalid operation in a function body.217struct TestInvalidIRPass218 : public PassWrapper<TestInvalidIRPass,219 InterfacePass<FunctionOpInterface>> {220 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidIRPass)221 222 TestInvalidIRPass() = default;223 TestInvalidIRPass(const TestInvalidIRPass &other) : PassWrapper(other) {}224 225 StringRef getArgument() const final { return "test-pass-create-invalid-ir"; }226 StringRef getDescription() const final {227 return "Test pass that adds an invalid operation in a function body";228 }229 void getDependentDialects(DialectRegistry ®istry) const final {230 registry.insert<test::TestDialect>();231 }232 void runOnOperation() final {233 if (signalFailure)234 signalPassFailure();235 if (!emitInvalidIR)236 return;237 OpBuilder b(getOperation().getFunctionBody());238 OperationState state(b.getUnknownLoc(), "test.any_attr_of_i32_str");239 b.create(state);240 }241 Option<bool> signalFailure{*this, "signal-pass-failure",242 llvm::cl::desc("Trigger a pass failure")};243 Option<bool> emitInvalidIR{*this, "emit-invalid-ir", llvm::cl::init(true),244 llvm::cl::desc("Emit invalid IR")};245};246 247/// A test pass that always fails to enable testing the failure recovery248/// mechanisms of the pass manager.249struct TestInvalidParentPass250 : public PassWrapper<TestInvalidParentPass,251 InterfacePass<FunctionOpInterface>> {252 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestInvalidParentPass)253 254 StringRef getArgument() const final { return "test-pass-invalid-parent"; }255 StringRef getDescription() const final {256 return "Test a pass in the pass manager that makes the parent operation "257 "invalid";258 }259 void getDependentDialects(DialectRegistry ®istry) const final {260 registry.insert<test::TestDialect>();261 }262 void runOnOperation() final {263 FunctionOpInterface op = getOperation();264 OpBuilder b(op.getFunctionBody());265 test::TestCallOp::create(b, op.getLoc(), TypeRange(), "some_unknown_func",266 ValueRange());267 }268};269 270/// A test pass that contains a statistic.271struct TestStatisticPass272 : public PassWrapper<TestStatisticPass, OperationPass<>> {273 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestStatisticPass)274 275 TestStatisticPass() = default;276 TestStatisticPass(const TestStatisticPass &) : PassWrapper() {}277 StringRef getArgument() const final { return "test-stats-pass"; }278 StringRef getDescription() const final { return "Test pass statistics"; }279 280 // Use a couple of statistics to verify their ordering281 // in the print out. The statistics are registered in the order282 // of construction, so put "num-ops2" before "num-ops" and283 // make sure that the order is reversed.284 Statistic opCountDuplicate{this, "num-ops2",285 "Number of operations counted one more time"};286 Statistic opCount{this, "num-ops", "Number of operations counted"};287 288 void runOnOperation() final {289 getOperation()->walk([&](Operation *) { ++opCount; });290 getOperation()->walk([&](Operation *) { ++opCountDuplicate; });291 }292};293} // namespace294 295static void testNestedPipeline(OpPassManager &pm) {296 // Nest a module pipeline that contains:297 /// A module pass.298 auto &modulePM = pm.nest<ModuleOp>();299 modulePM.addPass(std::make_unique<TestModulePass>());300 /// A nested function pass.301 auto &nestedFunctionPM = modulePM.nest<func::FuncOp>();302 nestedFunctionPM.addPass(std::make_unique<TestFunctionPass>());303 304 // Nest a function pipeline that contains a single pass.305 auto &functionPM = pm.nest<func::FuncOp>();306 functionPM.addPass(std::make_unique<TestFunctionPass>());307}308 309static void testNestedPipelineTextual(OpPassManager &pm) {310 (void)parsePassPipeline("test-pm-nested-pipeline", pm);311}312 313namespace mlir {314void registerPassManagerTestPass() {315 PassRegistration<TestOptionsPass>();316 PassRegistration<TestOptionsSuperPass>();317 318 PassRegistration<TestOptionsPassA>();319 PassRegistration<TestOptionsPassB>();320 321 PassRegistration<TestModulePass>();322 323 PassRegistration<TestFunctionPass>();324 325 PassRegistration<TestInterfacePass>();326 327 PassRegistration<TestCrashRecoveryPass>();328 PassRegistration<TestFailurePass>();329 PassRegistration<TestInvalidIRPass>();330 PassRegistration<TestInvalidParentPass>();331 332 PassRegistration<TestStatisticPass>();333 334 PassPipelineRegistration<>("test-pm-nested-pipeline",335 "Test a nested pipeline in the pass manager",336 testNestedPipeline);337 PassPipelineRegistration<>("test-textual-pm-nested-pipeline",338 "Test a nested pipeline in the pass manager",339 testNestedPipelineTextual);340 341 PassPipelineRegistration<TestOptionsPass::Options>342 registerOptionsPassPipeline(343 "test-options-pass-pipeline",344 "Parses options using pass pipeline registration",345 [](OpPassManager &pm, const TestOptionsPass::Options &options) {346 pm.addPass(std::make_unique<TestOptionsPass>(options));347 });348 349 PassPipelineRegistration<TestOptionsSuperPass::Options>350 registerOptionsSuperPassPipeline(351 "test-options-super-pass-pipeline",352 "Parses options of PassPipelineOptions using pass pipeline "353 "registration",354 [](OpPassManager &pm, const TestOptionsSuperPass::Options &options) {355 pm.addPass(std::make_unique<TestOptionsSuperPass>(options));356 });357 358 PassPipelineRegistration<TestPipelineOptionsSuperSetAB>359 registerPipelineOptionsSuperSetABPipeline(360 "test-options-super-set-ab-pipeline",361 "Parses options of PassPipelineOptions using pass pipeline "362 "registration",363 [](OpPassManager &pm, const TestPipelineOptionsSuperSetAB &options) {364 // Pass superset AB options to subset options A and B365 pm.addPass(std::make_unique<TestOptionsPassA>(options));366 pm.addPass(std::make_unique<TestOptionsPassB>(options));367 });368}369} // namespace mlir370