249 lines · cpp
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-exception6//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 NDEBUG19#include "llvm/IR/LegacyPassManager.h"20#endif21 22using namespace llvm;23 24//===----------------------------------------------------------------------===//25/// onlySimpleRegion - Show only the simple regions in the RegionViewer.26static cl::opt<bool>27onlySimpleRegions("only-simple-regions",28 cl::desc("Show only simple regions in the graphviz viewer"),29 cl::Hidden,30 cl::init(false));31 32std::string33llvm::DOTGraphTraits<RegionNode *>::getNodeLabel(RegionNode *Node,34 RegionNode *Graph) {35 if (!Node->isSubRegion()) {36 BasicBlock *BB = Node->getNodeAs<BasicBlock>();37 38 if (isSimple())39 return DOTGraphTraits<DOTFuncInfo *>::getSimpleNodeLabel(BB, nullptr);40 else41 return DOTGraphTraits<DOTFuncInfo *>::getCompleteNodeLabel(BB, nullptr);42 }43 44 return "Not implemented";45}46 47template <>48struct llvm::DOTGraphTraits<RegionInfo *>49 : public llvm::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 else79 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 blocks88 // 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 129namespace {130 131struct RegionInfoPassGraphTraits {132 static RegionInfo *getGraph(RegionInfoPass *RIP) {133 return &RIP->getRegionInfo();134 }135};136 137struct RegionPrinter138 : public DOTGraphTraitsPrinterWrapperPass<139 RegionInfoPass, false, RegionInfo *, RegionInfoPassGraphTraits> {140 static char ID;141 RegionPrinter()142 : DOTGraphTraitsPrinterWrapperPass<RegionInfoPass, false, RegionInfo *,143 RegionInfoPassGraphTraits>("reg", ID) {144 }145};146char RegionPrinter::ID = 0;147 148struct RegionOnlyPrinter149 : public DOTGraphTraitsPrinterWrapperPass<150 RegionInfoPass, true, RegionInfo *, RegionInfoPassGraphTraits> {151 static char ID;152 RegionOnlyPrinter()153 : DOTGraphTraitsPrinterWrapperPass<RegionInfoPass, true, RegionInfo *,154 RegionInfoPassGraphTraits>("reg", ID) {155 }156};157char RegionOnlyPrinter::ID = 0;158 159struct RegionViewer160 : public DOTGraphTraitsViewerWrapperPass<161 RegionInfoPass, false, RegionInfo *, RegionInfoPassGraphTraits> {162 static char ID;163 RegionViewer()164 : DOTGraphTraitsViewerWrapperPass<RegionInfoPass, false, RegionInfo *,165 RegionInfoPassGraphTraits>("reg", ID) {}166};167char RegionViewer::ID = 0;168 169struct RegionOnlyViewer170 : public DOTGraphTraitsViewerWrapperPass<RegionInfoPass, true, RegionInfo *,171 RegionInfoPassGraphTraits> {172 static char ID;173 RegionOnlyViewer()174 : DOTGraphTraitsViewerWrapperPass<RegionInfoPass, true, RegionInfo *,175 RegionInfoPassGraphTraits>("regonly",176 ID) {}177};178char RegionOnlyViewer::ID = 0;179 180} //end anonymous namespace181 182INITIALIZE_PASS(RegionPrinter, "dot-regions",183 "Print regions of function to 'dot' file", true, true)184 185INITIALIZE_PASS(186 RegionOnlyPrinter, "dot-regions-only",187 "Print regions of function to 'dot' file (with no function bodies)", true,188 true)189 190INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function",191 true, true)192 193INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only",194 "View regions of function (with no function bodies)",195 true, true)196 197FunctionPass *llvm::createRegionPrinterPass() { return new RegionPrinter(); }198 199FunctionPass *llvm::createRegionOnlyPrinterPass() {200 return new RegionOnlyPrinter();201}202 203FunctionPass* llvm::createRegionViewerPass() {204 return new RegionViewer();205}206 207FunctionPass* llvm::createRegionOnlyViewerPass() {208 return new RegionOnlyViewer();209}210 211#ifndef NDEBUG212static void viewRegionInfo(RegionInfo *RI, bool ShortNames) {213 assert(RI && "Argument must be non-null");214 215 llvm::Function *F = RI->getTopLevelRegion()->getEntry()->getParent();216 std::string GraphName = DOTGraphTraits<RegionInfo *>::getGraphName(RI);217 218 llvm::ViewGraph(RI, "reg", ShortNames,219 Twine(GraphName) + " for '" + F->getName() + "' function");220}221 222static void invokeFunctionPass(const Function *F, FunctionPass *ViewerPass) {223 assert(F && "Argument must be non-null");224 assert(!F->isDeclaration() && "Function must have an implementation");225 226 // The viewer and analysis passes do not modify anything, so we can safely227 // remove the const qualifier228 auto NonConstF = const_cast<Function *>(F);229 230 llvm::legacy::FunctionPassManager FPM(NonConstF->getParent());231 FPM.add(ViewerPass);232 FPM.doInitialization();233 FPM.run(*NonConstF);234 FPM.doFinalization();235}236 237void llvm::viewRegion(RegionInfo *RI) { viewRegionInfo(RI, false); }238 239void llvm::viewRegion(const Function *F) {240 invokeFunctionPass(F, createRegionViewerPass());241}242 243void llvm::viewRegionOnly(RegionInfo *RI) { viewRegionInfo(RI, true); }244 245void llvm::viewRegionOnly(const Function *F) {246 invokeFunctionPass(F, createRegionOnlyViewerPass());247}248#endif249