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