1 //===- RegionPrinter.cpp - Print regions tree pass ------------------------===// 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 // Print out the region tree of a function using dotty/graphviz. 9 //===----------------------------------------------------------------------===// 10 11 #include "llvm/Analysis/RegionPrinter.h" 12 #include "llvm/ADT/DepthFirstIterator.h" 13 #include "llvm/ADT/PostOrderIterator.h" 14 #include "llvm/ADT/Statistic.h" 15 #include "llvm/Analysis/DOTGraphTraitsPass.h" 16 #include "llvm/Analysis/Passes.h" 17 #include "llvm/Analysis/RegionInfo.h" 18 #include "llvm/Analysis/RegionIterator.h" 19 #include "llvm/Support/CommandLine.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/raw_ostream.h" 22 #ifndef NDEBUG 23 #include "llvm/IR/LegacyPassManager.h" 24 #endif 25 26 using namespace llvm; 27 28 //===----------------------------------------------------------------------===// 29 /// onlySimpleRegion - Show only the simple regions in the RegionViewer. 30 static cl::opt<bool> 31 onlySimpleRegions("only-simple-regions", 32 cl::desc("Show only simple regions in the graphviz viewer"), 33 cl::Hidden, 34 cl::init(false)); 35 36 namespace llvm { 37 template<> 38 struct DOTGraphTraits<RegionNode*> : public DefaultDOTGraphTraits { 39 40 DOTGraphTraits (bool isSimple=false) 41 : DefaultDOTGraphTraits(isSimple) {} 42 43 std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) { 44 45 if (!Node->isSubRegion()) { 46 BasicBlock *BB = Node->getNodeAs<BasicBlock>(); 47 48 if (isSimple()) 49 return DOTGraphTraits<const Function*> 50 ::getSimpleNodeLabel(BB, BB->getParent()); 51 else 52 return DOTGraphTraits<const Function*> 53 ::getCompleteNodeLabel(BB, BB->getParent()); 54 } 55 56 return "Not implemented"; 57 } 58 }; 59 60 template <> 61 struct DOTGraphTraits<RegionInfo *> : public DOTGraphTraits<RegionNode *> { 62 63 DOTGraphTraits (bool isSimple = false) 64 : DOTGraphTraits<RegionNode*>(isSimple) {} 65 66 static std::string getGraphName(const RegionInfo *) { return "Region Graph"; } 67 68 std::string getNodeLabel(RegionNode *Node, RegionInfo *G) { 69 return DOTGraphTraits<RegionNode *>::getNodeLabel( 70 Node, reinterpret_cast<RegionNode *>(G->getTopLevelRegion())); 71 } 72 73 std::string getEdgeAttributes(RegionNode *srcNode, 74 GraphTraits<RegionInfo *>::ChildIteratorType CI, 75 RegionInfo *G) { 76 RegionNode *destNode = *CI; 77 78 if (srcNode->isSubRegion() || destNode->isSubRegion()) 79 return ""; 80 81 // In case of a backedge, do not use it to define the layout of the nodes. 82 BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>(); 83 BasicBlock *destBB = destNode->getNodeAs<BasicBlock>(); 84 85 Region *R = G->getRegionFor(destBB); 86 87 while (R && R->getParent()) 88 if (R->getParent()->getEntry() == destBB) 89 R = R->getParent(); 90 else 91 break; 92 93 if (R && R->getEntry() == destBB && R->contains(srcBB)) 94 return "constraint=false"; 95 96 return ""; 97 } 98 99 // Print the cluster of the subregions. This groups the single basic blocks 100 // and adds a different background color for each group. 101 static void printRegionCluster(const Region &R, GraphWriter<RegionInfo *> &GW, 102 unsigned depth = 0) { 103 raw_ostream &O = GW.getOStream(); 104 O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void*>(&R) 105 << " {\n"; 106 O.indent(2 * (depth + 1)) << "label = \"\";\n"; 107 108 if (!onlySimpleRegions || R.isSimple()) { 109 O.indent(2 * (depth + 1)) << "style = filled;\n"; 110 O.indent(2 * (depth + 1)) << "color = " 111 << ((R.getDepth() * 2 % 12) + 1) << "\n"; 112 113 } else { 114 O.indent(2 * (depth + 1)) << "style = solid;\n"; 115 O.indent(2 * (depth + 1)) << "color = " 116 << ((R.getDepth() * 2 % 12) + 2) << "\n"; 117 } 118 119 for (const auto &RI : R) 120 printRegionCluster(*RI, GW, depth + 1); 121 122 const RegionInfo &RI = *static_cast<const RegionInfo*>(R.getRegionInfo()); 123 124 for (auto *BB : R.blocks()) 125 if (RI.getRegionFor(BB) == &R) 126 O.indent(2 * (depth + 1)) << "Node" 127 << static_cast<const void*>(RI.getTopLevelRegion()->getBBNode(BB)) 128 << ";\n"; 129 130 O.indent(2 * depth) << "}\n"; 131 } 132 133 static void addCustomGraphFeatures(const RegionInfo *G, 134 GraphWriter<RegionInfo *> &GW) { 135 raw_ostream &O = GW.getOStream(); 136 O << "\tcolorscheme = \"paired12\"\n"; 137 printRegionCluster(*G->getTopLevelRegion(), GW, 4); 138 } 139 }; 140 } //end namespace llvm 141 142 namespace { 143 144 struct RegionInfoPassGraphTraits { 145 static RegionInfo *getGraph(RegionInfoPass *RIP) { 146 return &RIP->getRegionInfo(); 147 } 148 }; 149 150 struct RegionPrinter 151 : public DOTGraphTraitsPrinter<RegionInfoPass, false, RegionInfo *, 152 RegionInfoPassGraphTraits> { 153 static char ID; 154 RegionPrinter() 155 : DOTGraphTraitsPrinter<RegionInfoPass, false, RegionInfo *, 156 RegionInfoPassGraphTraits>("reg", ID) { 157 initializeRegionPrinterPass(*PassRegistry::getPassRegistry()); 158 } 159 }; 160 char RegionPrinter::ID = 0; 161 162 struct RegionOnlyPrinter 163 : public DOTGraphTraitsPrinter<RegionInfoPass, true, RegionInfo *, 164 RegionInfoPassGraphTraits> { 165 static char ID; 166 RegionOnlyPrinter() 167 : DOTGraphTraitsPrinter<RegionInfoPass, true, RegionInfo *, 168 RegionInfoPassGraphTraits>("reg", ID) { 169 initializeRegionOnlyPrinterPass(*PassRegistry::getPassRegistry()); 170 } 171 }; 172 char RegionOnlyPrinter::ID = 0; 173 174 struct RegionViewer 175 : public DOTGraphTraitsViewer<RegionInfoPass, false, RegionInfo *, 176 RegionInfoPassGraphTraits> { 177 static char ID; 178 RegionViewer() 179 : DOTGraphTraitsViewer<RegionInfoPass, false, RegionInfo *, 180 RegionInfoPassGraphTraits>("reg", ID) { 181 initializeRegionViewerPass(*PassRegistry::getPassRegistry()); 182 } 183 }; 184 char RegionViewer::ID = 0; 185 186 struct RegionOnlyViewer 187 : public DOTGraphTraitsViewer<RegionInfoPass, true, RegionInfo *, 188 RegionInfoPassGraphTraits> { 189 static char ID; 190 RegionOnlyViewer() 191 : DOTGraphTraitsViewer<RegionInfoPass, true, RegionInfo *, 192 RegionInfoPassGraphTraits>("regonly", ID) { 193 initializeRegionOnlyViewerPass(*PassRegistry::getPassRegistry()); 194 } 195 }; 196 char RegionOnlyViewer::ID = 0; 197 198 } //end anonymous namespace 199 200 INITIALIZE_PASS(RegionPrinter, "dot-regions", 201 "Print regions of function to 'dot' file", true, true) 202 203 INITIALIZE_PASS( 204 RegionOnlyPrinter, "dot-regions-only", 205 "Print regions of function to 'dot' file (with no function bodies)", true, 206 true) 207 208 INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function", 209 true, true) 210 211 INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only", 212 "View regions of function (with no function bodies)", 213 true, true) 214 215 FunctionPass *llvm::createRegionPrinterPass() { return new RegionPrinter(); } 216 217 FunctionPass *llvm::createRegionOnlyPrinterPass() { 218 return new RegionOnlyPrinter(); 219 } 220 221 FunctionPass* llvm::createRegionViewerPass() { 222 return new RegionViewer(); 223 } 224 225 FunctionPass* llvm::createRegionOnlyViewerPass() { 226 return new RegionOnlyViewer(); 227 } 228 229 #ifndef NDEBUG 230 static void viewRegionInfo(RegionInfo *RI, bool ShortNames) { 231 assert(RI && "Argument must be non-null"); 232 233 llvm::Function *F = RI->getTopLevelRegion()->getEntry()->getParent(); 234 std::string GraphName = DOTGraphTraits<RegionInfo *>::getGraphName(RI); 235 236 llvm::ViewGraph(RI, "reg", ShortNames, 237 Twine(GraphName) + " for '" + F->getName() + "' function"); 238 } 239 240 static void invokeFunctionPass(const Function *F, FunctionPass *ViewerPass) { 241 assert(F && "Argument must be non-null"); 242 assert(!F->isDeclaration() && "Function must have an implementation"); 243 244 // The viewer and analysis passes do not modify anything, so we can safely 245 // remove the const qualifier 246 auto NonConstF = const_cast<Function *>(F); 247 248 llvm::legacy::FunctionPassManager FPM(NonConstF->getParent()); 249 FPM.add(ViewerPass); 250 FPM.doInitialization(); 251 FPM.run(*NonConstF); 252 FPM.doFinalization(); 253 } 254 255 void llvm::viewRegion(RegionInfo *RI) { viewRegionInfo(RI, false); } 256 257 void llvm::viewRegion(const Function *F) { 258 invokeFunctionPass(F, createRegionViewerPass()); 259 } 260 261 void llvm::viewRegionOnly(RegionInfo *RI) { viewRegionInfo(RI, true); } 262 263 void llvm::viewRegionOnly(const Function *F) { 264 invokeFunctionPass(F, createRegionOnlyViewerPass()); 265 } 266 #endif 267