| //===- RegionPrinter.cpp - Print regions tree pass ------------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // Print out the region tree of a function using dotty/graphviz. | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Analysis/RegionInfo.h" | |
| #include "llvm/Analysis/RegionIterator.h" | |
| #include "llvm/Analysis/RegionPrinter.h" | |
| #include "llvm/Analysis/Passes.h" | |
| #include "llvm/Analysis/DOTGraphTraitsPass.h" | |
| #include "llvm/ADT/Statistic.h" | |
| #include "llvm/ADT/PostOrderIterator.h" | |
| #include "llvm/ADT/DepthFirstIterator.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| //===----------------------------------------------------------------------===// | |
| /// onlySimpleRegion - Show only the simple regions in the RegionViewer. | |
| static cl::opt<bool> | |
| onlySimpleRegions("only-simple-regions", | |
| cl::desc("Show only simple regions in the graphviz viewer"), | |
| cl::Hidden, | |
| cl::init(false)); | |
| namespace llvm { | |
| template<> | |
| struct DOTGraphTraits<RegionNode*> : public DefaultDOTGraphTraits { | |
| DOTGraphTraits (bool isSimple=false) | |
| : DefaultDOTGraphTraits(isSimple) {} | |
| std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) { | |
| if (!Node->isSubRegion()) { | |
| BasicBlock *BB = Node->getNodeAs<BasicBlock>(); | |
| if (isSimple()) | |
| return DOTGraphTraits<const Function*> | |
| ::getSimpleNodeLabel(BB, BB->getParent()); | |
| else | |
| return DOTGraphTraits<const Function*> | |
| ::getCompleteNodeLabel(BB, BB->getParent()); | |
| } | |
| return "Not implemented"; | |
| } | |
| }; | |
| template<> | |
| struct DOTGraphTraits<RegionInfo*> : public DOTGraphTraits<RegionNode*> { | |
| DOTGraphTraits (bool isSimple=false) | |
| : DOTGraphTraits<RegionNode*>(isSimple) {} | |
| static std::string getGraphName(RegionInfo *DT) { | |
| return "Region Graph"; | |
| } | |
| std::string getNodeLabel(RegionNode *Node, RegionInfo *G) { | |
| return DOTGraphTraits<RegionNode*>::getNodeLabel(Node, | |
| G->getTopLevelRegion()); | |
| } | |
| std::string getEdgeAttributes(RegionNode *srcNode, | |
| GraphTraits<RegionInfo*>::ChildIteratorType CI, RegionInfo *RI) { | |
| RegionNode *destNode = *CI; | |
| if (srcNode->isSubRegion() || destNode->isSubRegion()) | |
| return ""; | |
| // In case of a backedge, do not use it to define the layout of the nodes. | |
| BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>(); | |
| BasicBlock *destBB = destNode->getNodeAs<BasicBlock>(); | |
| Region *R = RI->getRegionFor(destBB); | |
| while (R && R->getParent()) | |
| if (R->getParent()->getEntry() == destBB) | |
| R = R->getParent(); | |
| else | |
| break; | |
| if (R->getEntry() == destBB && R->contains(srcBB)) | |
| return "constraint=false"; | |
| return ""; | |
| } | |
| // Print the cluster of the subregions. This groups the single basic blocks | |
| // and adds a different background color for each group. | |
| static void printRegionCluster(const Region *R, GraphWriter<RegionInfo*> &GW, | |
| unsigned depth = 0) { | |
| raw_ostream &O = GW.getOStream(); | |
| O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void*>(R) | |
| << " {\n"; | |
| O.indent(2 * (depth + 1)) << "label = \"\";\n"; | |
| if (!onlySimpleRegions || R->isSimple()) { | |
| O.indent(2 * (depth + 1)) << "style = filled;\n"; | |
| O.indent(2 * (depth + 1)) << "color = " | |
| << ((R->getDepth() * 2 % 12) + 1) << "\n"; | |
| } else { | |
| O.indent(2 * (depth + 1)) << "style = solid;\n"; | |
| O.indent(2 * (depth + 1)) << "color = " | |
| << ((R->getDepth() * 2 % 12) + 2) << "\n"; | |
| } | |
| for (Region::const_iterator RI = R->begin(), RE = R->end(); RI != RE; ++RI) | |
| printRegionCluster(*RI, GW, depth + 1); | |
| RegionInfo *RI = R->getRegionInfo(); | |
| for (Region::const_block_iterator BI = R->block_begin(), | |
| BE = R->block_end(); BI != BE; ++BI) { | |
| BasicBlock *BB = (*BI)->getNodeAs<BasicBlock>(); | |
| if (RI->getRegionFor(BB) == R) | |
| O.indent(2 * (depth + 1)) << "Node" | |
| << static_cast<const void*>(RI->getTopLevelRegion()->getBBNode(BB)) | |
| << ";\n"; | |
| } | |
| O.indent(2 * depth) << "}\n"; | |
| } | |
| static void addCustomGraphFeatures(const RegionInfo* RI, | |
| GraphWriter<RegionInfo*> &GW) { | |
| raw_ostream &O = GW.getOStream(); | |
| O << "\tcolorscheme = \"paired12\"\n"; | |
| printRegionCluster(RI->getTopLevelRegion(), GW, 4); | |
| } | |
| }; | |
| } //end namespace llvm | |
| namespace { | |
| struct RegionViewer | |
| : public DOTGraphTraitsViewer<RegionInfo, false> { | |
| static char ID; | |
| RegionViewer() : DOTGraphTraitsViewer<RegionInfo, false>("reg", ID){ | |
| initializeRegionViewerPass(*PassRegistry::getPassRegistry()); | |
| } | |
| }; | |
| char RegionViewer::ID = 0; | |
| struct RegionOnlyViewer | |
| : public DOTGraphTraitsViewer<RegionInfo, true> { | |
| static char ID; | |
| RegionOnlyViewer() : DOTGraphTraitsViewer<RegionInfo, true>("regonly", ID) { | |
| initializeRegionOnlyViewerPass(*PassRegistry::getPassRegistry()); | |
| } | |
| }; | |
| char RegionOnlyViewer::ID = 0; | |
| struct RegionPrinter | |
| : public DOTGraphTraitsPrinter<RegionInfo, false> { | |
| static char ID; | |
| RegionPrinter() : | |
| DOTGraphTraitsPrinter<RegionInfo, false>("reg", ID) { | |
| initializeRegionPrinterPass(*PassRegistry::getPassRegistry()); | |
| } | |
| }; | |
| char RegionPrinter::ID = 0; | |
| } //end anonymous namespace | |
| INITIALIZE_PASS(RegionPrinter, "dot-regions", | |
| "Print regions of function to 'dot' file", true, true) | |
| INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function", | |
| true, true) | |
| INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only", | |
| "View regions of function (with no function bodies)", | |
| true, true) | |
| namespace { | |
| struct RegionOnlyPrinter | |
| : public DOTGraphTraitsPrinter<RegionInfo, true> { | |
| static char ID; | |
| RegionOnlyPrinter() : | |
| DOTGraphTraitsPrinter<RegionInfo, true>("reg", ID) { | |
| initializeRegionOnlyPrinterPass(*PassRegistry::getPassRegistry()); | |
| } | |
| }; | |
| } | |
| char RegionOnlyPrinter::ID = 0; | |
| INITIALIZE_PASS(RegionOnlyPrinter, "dot-regions-only", | |
| "Print regions of function to 'dot' file " | |
| "(with no function bodies)", | |
| true, true) | |
| FunctionPass* llvm::createRegionViewerPass() { | |
| return new RegionViewer(); | |
| } | |
| FunctionPass* llvm::createRegionOnlyViewerPass() { | |
| return new RegionOnlyViewer(); | |
| } | |
| FunctionPass* llvm::createRegionPrinterPass() { | |
| return new RegionPrinter(); | |
| } | |
| FunctionPass* llvm::createRegionOnlyPrinterPass() { | |
| return new RegionOnlyPrinter(); | |
| } | |