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