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