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