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