12de6dbdaSDiego Caballero //===- TestIRVisitors.cpp - Pass to test the IR visitors ------------------===//
22de6dbdaSDiego Caballero //
32de6dbdaSDiego Caballero // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42de6dbdaSDiego Caballero // See https://llvm.org/LICENSE.txt for license information.
52de6dbdaSDiego Caballero // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62de6dbdaSDiego Caballero //
72de6dbdaSDiego Caballero //===----------------------------------------------------------------------===//
82de6dbdaSDiego Caballero
936d3efeaSRiver Riddle #include "mlir/IR/BuiltinOps.h"
10b884f4efSMatthias Springer #include "mlir/IR/Iterators.h"
1134a35a8bSMartin Erhart #include "mlir/Interfaces/FunctionInterfaces.h"
122de6dbdaSDiego Caballero #include "mlir/Pass/Pass.h"
132de6dbdaSDiego Caballero
142de6dbdaSDiego Caballero using namespace mlir;
152de6dbdaSDiego Caballero
printRegion(Region * region)162de6dbdaSDiego Caballero static void printRegion(Region *region) {
172de6dbdaSDiego Caballero llvm::outs() << "region " << region->getRegionNumber() << " from operation '"
182de6dbdaSDiego Caballero << region->getParentOp()->getName() << "'";
192de6dbdaSDiego Caballero }
202de6dbdaSDiego Caballero
printBlock(Block * block)212de6dbdaSDiego Caballero static void printBlock(Block *block) {
222de6dbdaSDiego Caballero llvm::outs() << "block ";
232de6dbdaSDiego Caballero block->printAsOperand(llvm::outs(), /*printType=*/false);
242de6dbdaSDiego Caballero llvm::outs() << " from ";
252de6dbdaSDiego Caballero printRegion(block->getParent());
262de6dbdaSDiego Caballero }
272de6dbdaSDiego Caballero
printOperation(Operation * op)282de6dbdaSDiego Caballero static void printOperation(Operation *op) {
292de6dbdaSDiego Caballero llvm::outs() << "op '" << op->getName() << "'";
302de6dbdaSDiego Caballero }
312de6dbdaSDiego Caballero
322de6dbdaSDiego Caballero /// Tests pure callbacks.
testPureCallbacks(Operation * op)332de6dbdaSDiego Caballero static void testPureCallbacks(Operation *op) {
342de6dbdaSDiego Caballero auto opPure = [](Operation *op) {
352de6dbdaSDiego Caballero llvm::outs() << "Visiting ";
362de6dbdaSDiego Caballero printOperation(op);
372de6dbdaSDiego Caballero llvm::outs() << "\n";
382de6dbdaSDiego Caballero };
392de6dbdaSDiego Caballero auto blockPure = [](Block *block) {
402de6dbdaSDiego Caballero llvm::outs() << "Visiting ";
412de6dbdaSDiego Caballero printBlock(block);
422de6dbdaSDiego Caballero llvm::outs() << "\n";
432de6dbdaSDiego Caballero };
442de6dbdaSDiego Caballero auto regionPure = [](Region *region) {
452de6dbdaSDiego Caballero llvm::outs() << "Visiting ";
462de6dbdaSDiego Caballero printRegion(region);
472de6dbdaSDiego Caballero llvm::outs() << "\n";
482de6dbdaSDiego Caballero };
492de6dbdaSDiego Caballero
502de6dbdaSDiego Caballero llvm::outs() << "Op pre-order visits"
512de6dbdaSDiego Caballero << "\n";
522de6dbdaSDiego Caballero op->walk<WalkOrder::PreOrder>(opPure);
532de6dbdaSDiego Caballero llvm::outs() << "Block pre-order visits"
542de6dbdaSDiego Caballero << "\n";
552de6dbdaSDiego Caballero op->walk<WalkOrder::PreOrder>(blockPure);
562de6dbdaSDiego Caballero llvm::outs() << "Region pre-order visits"
572de6dbdaSDiego Caballero << "\n";
582de6dbdaSDiego Caballero op->walk<WalkOrder::PreOrder>(regionPure);
592de6dbdaSDiego Caballero
602de6dbdaSDiego Caballero llvm::outs() << "Op post-order visits"
612de6dbdaSDiego Caballero << "\n";
622de6dbdaSDiego Caballero op->walk<WalkOrder::PostOrder>(opPure);
632de6dbdaSDiego Caballero llvm::outs() << "Block post-order visits"
642de6dbdaSDiego Caballero << "\n";
652de6dbdaSDiego Caballero op->walk<WalkOrder::PostOrder>(blockPure);
662de6dbdaSDiego Caballero llvm::outs() << "Region post-order visits"
672de6dbdaSDiego Caballero << "\n";
682de6dbdaSDiego Caballero op->walk<WalkOrder::PostOrder>(regionPure);
69df067f13SMatthias Springer
70df067f13SMatthias Springer llvm::outs() << "Op reverse post-order visits"
71df067f13SMatthias Springer << "\n";
72df067f13SMatthias Springer op->walk<WalkOrder::PostOrder, ReverseIterator>(opPure);
73df067f13SMatthias Springer llvm::outs() << "Block reverse post-order visits"
74df067f13SMatthias Springer << "\n";
75df067f13SMatthias Springer op->walk<WalkOrder::PostOrder, ReverseIterator>(blockPure);
76df067f13SMatthias Springer llvm::outs() << "Region reverse post-order visits"
77df067f13SMatthias Springer << "\n";
78df067f13SMatthias Springer op->walk<WalkOrder::PostOrder, ReverseIterator>(regionPure);
79b884f4efSMatthias Springer
80b884f4efSMatthias Springer // This test case tests "NoGraphRegions = true", so start the walk with
81b884f4efSMatthias Springer // functions.
82b884f4efSMatthias Springer op->walk([&](FunctionOpInterface funcOp) {
83b884f4efSMatthias Springer llvm::outs() << "Op forward dominance post-order visits"
84b884f4efSMatthias Springer << "\n";
85b884f4efSMatthias Springer funcOp->walk<WalkOrder::PostOrder,
86b884f4efSMatthias Springer ForwardDominanceIterator</*NoGraphRegions=*/true>>(opPure);
87b884f4efSMatthias Springer llvm::outs() << "Block forward dominance post-order visits"
88b884f4efSMatthias Springer << "\n";
89b884f4efSMatthias Springer funcOp->walk<WalkOrder::PostOrder,
90b884f4efSMatthias Springer ForwardDominanceIterator</*NoGraphRegions=*/true>>(blockPure);
91b884f4efSMatthias Springer llvm::outs() << "Region forward dominance post-order visits"
92b884f4efSMatthias Springer << "\n";
93b884f4efSMatthias Springer funcOp->walk<WalkOrder::PostOrder,
94b884f4efSMatthias Springer ForwardDominanceIterator</*NoGraphRegions=*/true>>(regionPure);
959c16eef1SMatthias Springer
969c16eef1SMatthias Springer llvm::outs() << "Op reverse dominance post-order visits"
979c16eef1SMatthias Springer << "\n";
989c16eef1SMatthias Springer funcOp->walk<WalkOrder::PostOrder,
999c16eef1SMatthias Springer ReverseDominanceIterator</*NoGraphRegions=*/true>>(opPure);
1009c16eef1SMatthias Springer llvm::outs() << "Block reverse dominance post-order visits"
1019c16eef1SMatthias Springer << "\n";
1029c16eef1SMatthias Springer funcOp->walk<WalkOrder::PostOrder,
1039c16eef1SMatthias Springer ReverseDominanceIterator</*NoGraphRegions=*/true>>(blockPure);
1049c16eef1SMatthias Springer llvm::outs() << "Region reverse dominance post-order visits"
1059c16eef1SMatthias Springer << "\n";
1069c16eef1SMatthias Springer funcOp->walk<WalkOrder::PostOrder,
1079c16eef1SMatthias Springer ReverseDominanceIterator</*NoGraphRegions=*/true>>(regionPure);
108b884f4efSMatthias Springer });
1092de6dbdaSDiego Caballero }
1102de6dbdaSDiego Caballero
1112de6dbdaSDiego Caballero /// Tests erasure callbacks that skip the walk.
testSkipErasureCallbacks(Operation * op)1122de6dbdaSDiego Caballero static void testSkipErasureCallbacks(Operation *op) {
1132de6dbdaSDiego Caballero auto skipOpErasure = [](Operation *op) {
11487d6bf37SRiver Riddle // Do not erase module and module children operations. Otherwise, there
11587d6bf37SRiver Riddle // wouldn't be too much to test in pre-order.
11687d6bf37SRiver Riddle if (isa<ModuleOp>(op) || isa<ModuleOp>(op->getParentOp()))
1172de6dbdaSDiego Caballero return WalkResult::advance();
1182de6dbdaSDiego Caballero
1192de6dbdaSDiego Caballero llvm::outs() << "Erasing ";
1202de6dbdaSDiego Caballero printOperation(op);
1212de6dbdaSDiego Caballero llvm::outs() << "\n";
1222de6dbdaSDiego Caballero op->dropAllUses();
1232de6dbdaSDiego Caballero op->erase();
1242de6dbdaSDiego Caballero return WalkResult::skip();
1252de6dbdaSDiego Caballero };
1262de6dbdaSDiego Caballero auto skipBlockErasure = [](Block *block) {
12787d6bf37SRiver Riddle // Do not erase module and module children blocks. Otherwise there wouldn't
12887d6bf37SRiver Riddle // be too much to test in pre-order.
1292de6dbdaSDiego Caballero Operation *parentOp = block->getParentOp();
13087d6bf37SRiver Riddle if (isa<ModuleOp>(parentOp) || isa<ModuleOp>(parentOp->getParentOp()))
1312de6dbdaSDiego Caballero return WalkResult::advance();
1322de6dbdaSDiego Caballero
133b884f4efSMatthias Springer if (block->use_empty()) {
1342de6dbdaSDiego Caballero llvm::outs() << "Erasing ";
1352de6dbdaSDiego Caballero printBlock(block);
1362de6dbdaSDiego Caballero llvm::outs() << "\n";
1372de6dbdaSDiego Caballero block->erase();
1382de6dbdaSDiego Caballero return WalkResult::skip();
139*6b72c379SMehdi Amini }
140b884f4efSMatthias Springer llvm::outs() << "Cannot erase ";
141b884f4efSMatthias Springer printBlock(block);
142b884f4efSMatthias Springer llvm::outs() << ", still has uses\n";
143b884f4efSMatthias Springer return WalkResult::advance();
144*6b72c379SMehdi Amini
1452de6dbdaSDiego Caballero };
1462de6dbdaSDiego Caballero
1472de6dbdaSDiego Caballero llvm::outs() << "Op pre-order erasures (skip)"
1482de6dbdaSDiego Caballero << "\n";
1492de6dbdaSDiego Caballero Operation *cloned = op->clone();
1502de6dbdaSDiego Caballero cloned->walk<WalkOrder::PreOrder>(skipOpErasure);
1512de6dbdaSDiego Caballero cloned->erase();
1522de6dbdaSDiego Caballero
1532de6dbdaSDiego Caballero llvm::outs() << "Block pre-order erasures (skip)"
1542de6dbdaSDiego Caballero << "\n";
1552de6dbdaSDiego Caballero cloned = op->clone();
1562de6dbdaSDiego Caballero cloned->walk<WalkOrder::PreOrder>(skipBlockErasure);
1572de6dbdaSDiego Caballero cloned->erase();
1582de6dbdaSDiego Caballero
1592de6dbdaSDiego Caballero llvm::outs() << "Op post-order erasures (skip)"
1602de6dbdaSDiego Caballero << "\n";
1612de6dbdaSDiego Caballero cloned = op->clone();
1622de6dbdaSDiego Caballero cloned->walk<WalkOrder::PostOrder>(skipOpErasure);
1632de6dbdaSDiego Caballero cloned->erase();
1642de6dbdaSDiego Caballero
1652de6dbdaSDiego Caballero llvm::outs() << "Block post-order erasures (skip)"
1662de6dbdaSDiego Caballero << "\n";
1672de6dbdaSDiego Caballero cloned = op->clone();
1682de6dbdaSDiego Caballero cloned->walk<WalkOrder::PostOrder>(skipBlockErasure);
1692de6dbdaSDiego Caballero cloned->erase();
1702de6dbdaSDiego Caballero }
1712de6dbdaSDiego Caballero
1722de6dbdaSDiego Caballero /// Tests callbacks that erase the op or block but don't return 'Skip'. This
1732de6dbdaSDiego Caballero /// callbacks are only valid in post-order.
testNoSkipErasureCallbacks(Operation * op)1742de6dbdaSDiego Caballero static void testNoSkipErasureCallbacks(Operation *op) {
1752de6dbdaSDiego Caballero auto noSkipOpErasure = [](Operation *op) {
1762de6dbdaSDiego Caballero llvm::outs() << "Erasing ";
1772de6dbdaSDiego Caballero printOperation(op);
1782de6dbdaSDiego Caballero llvm::outs() << "\n";
1792de6dbdaSDiego Caballero op->dropAllUses();
1802de6dbdaSDiego Caballero op->erase();
1812de6dbdaSDiego Caballero };
1822de6dbdaSDiego Caballero auto noSkipBlockErasure = [](Block *block) {
183b884f4efSMatthias Springer if (block->use_empty()) {
1842de6dbdaSDiego Caballero llvm::outs() << "Erasing ";
1852de6dbdaSDiego Caballero printBlock(block);
1862de6dbdaSDiego Caballero llvm::outs() << "\n";
1872de6dbdaSDiego Caballero block->erase();
188b884f4efSMatthias Springer } else {
189b884f4efSMatthias Springer llvm::outs() << "Cannot erase ";
190b884f4efSMatthias Springer printBlock(block);
191b884f4efSMatthias Springer llvm::outs() << ", still has uses\n";
192b884f4efSMatthias Springer }
1932de6dbdaSDiego Caballero };
1942de6dbdaSDiego Caballero
1952de6dbdaSDiego Caballero llvm::outs() << "Op post-order erasures (no skip)"
1962de6dbdaSDiego Caballero << "\n";
1972de6dbdaSDiego Caballero Operation *cloned = op->clone();
1982de6dbdaSDiego Caballero cloned->walk<WalkOrder::PostOrder>(noSkipOpErasure);
1992de6dbdaSDiego Caballero
2002de6dbdaSDiego Caballero llvm::outs() << "Block post-order erasures (no skip)"
2012de6dbdaSDiego Caballero << "\n";
2022de6dbdaSDiego Caballero cloned = op->clone();
2032de6dbdaSDiego Caballero cloned->walk<WalkOrder::PostOrder>(noSkipBlockErasure);
2042de6dbdaSDiego Caballero cloned->erase();
2052de6dbdaSDiego Caballero }
2062de6dbdaSDiego Caballero
207c4457e10SMatthias Springer /// Invoke region/block walks on regions/blocks.
testBlockAndRegionWalkers(Operation * op)208c4457e10SMatthias Springer static void testBlockAndRegionWalkers(Operation *op) {
209c4457e10SMatthias Springer auto blockPure = [](Block *block) {
210c4457e10SMatthias Springer llvm::outs() << "Visiting ";
211c4457e10SMatthias Springer printBlock(block);
212c4457e10SMatthias Springer llvm::outs() << "\n";
213c4457e10SMatthias Springer };
214c4457e10SMatthias Springer auto regionPure = [](Region *region) {
215c4457e10SMatthias Springer llvm::outs() << "Visiting ";
216c4457e10SMatthias Springer printRegion(region);
217c4457e10SMatthias Springer llvm::outs() << "\n";
218c4457e10SMatthias Springer };
219c4457e10SMatthias Springer
220c4457e10SMatthias Springer llvm::outs() << "Invoke block pre-order visits on blocks\n";
221c4457e10SMatthias Springer op->walk([&](Operation *op) {
222c4457e10SMatthias Springer if (!op->hasAttr("walk_blocks"))
223c4457e10SMatthias Springer return;
224c4457e10SMatthias Springer for (Region ®ion : op->getRegions()) {
225c4457e10SMatthias Springer for (Block &block : region.getBlocks()) {
226c4457e10SMatthias Springer block.walk<WalkOrder::PreOrder>(blockPure);
227c4457e10SMatthias Springer }
228c4457e10SMatthias Springer }
229c4457e10SMatthias Springer });
230c4457e10SMatthias Springer
231c4457e10SMatthias Springer llvm::outs() << "Invoke block post-order visits on blocks\n";
232c4457e10SMatthias Springer op->walk([&](Operation *op) {
233c4457e10SMatthias Springer if (!op->hasAttr("walk_blocks"))
234c4457e10SMatthias Springer return;
235c4457e10SMatthias Springer for (Region ®ion : op->getRegions()) {
236c4457e10SMatthias Springer for (Block &block : region.getBlocks()) {
237c4457e10SMatthias Springer block.walk<WalkOrder::PostOrder>(blockPure);
238c4457e10SMatthias Springer }
239c4457e10SMatthias Springer }
240c4457e10SMatthias Springer });
241c4457e10SMatthias Springer
242c4457e10SMatthias Springer llvm::outs() << "Invoke region pre-order visits on region\n";
243c4457e10SMatthias Springer op->walk([&](Operation *op) {
244c4457e10SMatthias Springer if (!op->hasAttr("walk_regions"))
245c4457e10SMatthias Springer return;
246c4457e10SMatthias Springer for (Region ®ion : op->getRegions()) {
247c4457e10SMatthias Springer region.walk<WalkOrder::PreOrder>(regionPure);
248c4457e10SMatthias Springer }
249c4457e10SMatthias Springer });
250c4457e10SMatthias Springer
251c4457e10SMatthias Springer llvm::outs() << "Invoke region post-order visits on region\n";
252c4457e10SMatthias Springer op->walk([&](Operation *op) {
253c4457e10SMatthias Springer if (!op->hasAttr("walk_regions"))
254c4457e10SMatthias Springer return;
255c4457e10SMatthias Springer for (Region ®ion : op->getRegions()) {
256c4457e10SMatthias Springer region.walk<WalkOrder::PostOrder>(regionPure);
257c4457e10SMatthias Springer }
258c4457e10SMatthias Springer });
259c4457e10SMatthias Springer }
260c4457e10SMatthias Springer
2612de6dbdaSDiego Caballero namespace {
2622de6dbdaSDiego Caballero /// This pass exercises the different configurations of the IR visitors.
2632de6dbdaSDiego Caballero struct TestIRVisitorsPass
2642de6dbdaSDiego Caballero : public PassWrapper<TestIRVisitorsPass, OperationPass<>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID__anon0b4d01b80f11::TestIRVisitorsPass2655e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestIRVisitorsPass)
2665e50dd04SRiver Riddle
267b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-ir-visitors"; }
getDescription__anon0b4d01b80f11::TestIRVisitorsPass268b5e22e6dSMehdi Amini StringRef getDescription() const final { return "Test various visitors."; }
runOnOperation__anon0b4d01b80f11::TestIRVisitorsPass2692de6dbdaSDiego Caballero void runOnOperation() override {
2702de6dbdaSDiego Caballero Operation *op = getOperation();
2712de6dbdaSDiego Caballero testPureCallbacks(op);
272c4457e10SMatthias Springer testBlockAndRegionWalkers(op);
2732de6dbdaSDiego Caballero testSkipErasureCallbacks(op);
2742de6dbdaSDiego Caballero testNoSkipErasureCallbacks(op);
2752de6dbdaSDiego Caballero }
2762de6dbdaSDiego Caballero };
277be0a7e9fSMehdi Amini } // namespace
2782de6dbdaSDiego Caballero
2792de6dbdaSDiego Caballero namespace mlir {
2802de6dbdaSDiego Caballero namespace test {
registerTestIRVisitorsPass()281b5e22e6dSMehdi Amini void registerTestIRVisitorsPass() { PassRegistration<TestIRVisitorsPass>(); }
2822de6dbdaSDiego Caballero } // namespace test
2832de6dbdaSDiego Caballero } // namespace mlir
284