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