Home | History | Annotate | Download | only in Analysis
      1 //===- RegionPrinter.cpp - Print regions tree pass ------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 // Print out the region tree of a function using dotty/graphviz.
     10 //===----------------------------------------------------------------------===//
     11 
     12 #include "llvm/Analysis/RegionPrinter.h"
     13 #include "llvm/ADT/DepthFirstIterator.h"
     14 #include "llvm/ADT/PostOrderIterator.h"
     15 #include "llvm/ADT/Statistic.h"
     16 #include "llvm/Analysis/DOTGraphTraitsPass.h"
     17 #include "llvm/Analysis/Passes.h"
     18 #include "llvm/Analysis/RegionInfo.h"
     19 #include "llvm/Analysis/RegionIterator.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<const Function*>
     51           ::getSimpleNodeLabel(BB, BB->getParent());
     52       else
     53         return DOTGraphTraits<const Function*>
     54           ::getCompleteNodeLabel(BB, BB->getParent());
     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