1 //===- TestPrintNesting.cpp - Passes to illustrate the IR nesting ---------===//
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 "mlir/Dialect/StandardOps/IR/Ops.h"
10 #include "mlir/IR/BuiltinOps.h"
11 #include "mlir/Pass/Pass.h"
12 
13 using namespace mlir;
14 
15 namespace {
16 /// This pass illustrates the IR nesting through printing.
17 struct TestPrintNestingPass
18     : public PassWrapper<TestPrintNestingPass, OperationPass<>> {
19   StringRef getArgument() const final { return "test-print-nesting"; }
20   StringRef getDescription() const final { return "Test various printing."; }
21   // Entry point for the pass.
22   void runOnOperation() override {
23     Operation *op = getOperation();
24     resetIndent();
25     printOperation(op);
26   }
27 
28   /// The three methods below are mutually recursive and follow the nesting of
29   /// the IR: operation->region->block->operation->...
30 
31   void printOperation(Operation *op) {
32     // Print the operation itself and some of its properties
33     printIndent() << "visiting op: '" << op->getName() << "' with "
34                   << op->getNumOperands() << " operands and "
35                   << op->getNumResults() << " results\n";
36     // Print the operation attributes
37     if (!op->getAttrs().empty()) {
38       printIndent() << op->getAttrs().size() << " attributes:\n";
39       for (NamedAttribute attr : op->getAttrs())
40         printIndent() << " - '" << attr.first << "' : '" << attr.second
41                       << "'\n";
42     }
43 
44     // Recurse into each of the regions attached to the operation.
45     printIndent() << " " << op->getNumRegions() << " nested regions:\n";
46     auto indent = pushIndent();
47     for (Region &region : op->getRegions())
48       printRegion(region);
49   }
50 
51   void printRegion(Region &region) {
52     // A region does not hold anything by itself other than a list of blocks.
53     printIndent() << "Region with " << region.getBlocks().size()
54                   << " blocks:\n";
55     auto indent = pushIndent();
56     for (Block &block : region.getBlocks())
57       printBlock(block);
58   }
59 
60   void printBlock(Block &block) {
61     // Print the block intrinsics properties (basically: argument list)
62     printIndent()
63         << "Block with " << block.getNumArguments() << " arguments, "
64         << block.getNumSuccessors()
65         << " successors, and "
66         // Note, this `.size()` is traversing a linked-list and is O(n).
67         << block.getOperations().size() << " operations\n";
68 
69     // Block main role is to hold a list of Operations: let's recurse.
70     auto indent = pushIndent();
71     for (Operation &op : block.getOperations())
72       printOperation(&op);
73   }
74 
75   /// Manages the indentation as we traverse the IR nesting.
76   int indent;
77   struct IdentRAII {
78     int &indent;
79     IdentRAII(int &indent) : indent(indent) {}
80     ~IdentRAII() { --indent; }
81   };
82   void resetIndent() { indent = 0; }
83   IdentRAII pushIndent() { return IdentRAII(++indent); }
84 
85   llvm::raw_ostream &printIndent() {
86     for (int i = 0; i < indent; ++i)
87       llvm::outs() << "  ";
88     return llvm::outs();
89   }
90 };
91 } // end anonymous namespace
92 
93 namespace mlir {
94 void registerTestPrintNestingPass() {
95   PassRegistration<TestPrintNestingPass>();
96 }
97 } // namespace mlir
98