Line data Source code
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 0 : std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) {
45 :
46 0 : if (!Node->isSubRegion()) {
47 : BasicBlock *BB = Node->getNodeAs<BasicBlock>();
48 :
49 0 : if (isSimple())
50 : return DOTGraphTraits<const Function*>
51 0 : ::getSimpleNodeLabel(BB, BB->getParent());
52 : else
53 : return DOTGraphTraits<const Function*>
54 0 : ::getCompleteNodeLabel(BB, BB->getParent());
55 : }
56 :
57 0 : 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 0 : static std::string getGraphName(const RegionInfo *) { return "Region Graph"; }
68 :
69 0 : std::string getNodeLabel(RegionNode *Node, RegionInfo *G) {
70 : return DOTGraphTraits<RegionNode *>::getNodeLabel(
71 0 : Node, reinterpret_cast<RegionNode *>(G->getTopLevelRegion()));
72 : }
73 :
74 0 : std::string getEdgeAttributes(RegionNode *srcNode,
75 : GraphTraits<RegionInfo *>::ChildIteratorType CI,
76 : RegionInfo *G) {
77 0 : RegionNode *destNode = *CI;
78 :
79 0 : if (srcNode->isSubRegion() || destNode->isSubRegion())
80 0 : 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 0 : Region *R = G->getRegionFor(destBB);
87 :
88 0 : while (R && R->getParent())
89 0 : if (R->getParent()->getEntry() == destBB)
90 : R = R->getParent();
91 : else
92 : break;
93 :
94 0 : if (R && R->getEntry() == destBB && R->contains(srcBB))
95 0 : return "constraint=false";
96 :
97 0 : 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 0 : static void printRegionCluster(const Region &R, GraphWriter<RegionInfo *> &GW,
103 : unsigned depth = 0) {
104 0 : raw_ostream &O = GW.getOStream();
105 0 : O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void*>(&R)
106 0 : << " {\n";
107 0 : O.indent(2 * (depth + 1)) << "label = \"\";\n";
108 :
109 0 : if (!onlySimpleRegions || R.isSimple()) {
110 0 : O.indent(2 * (depth + 1)) << "style = filled;\n";
111 0 : O.indent(2 * (depth + 1)) << "color = "
112 0 : << ((R.getDepth() * 2 % 12) + 1) << "\n";
113 :
114 : } else {
115 0 : O.indent(2 * (depth + 1)) << "style = solid;\n";
116 0 : O.indent(2 * (depth + 1)) << "color = "
117 0 : << ((R.getDepth() * 2 % 12) + 2) << "\n";
118 : }
119 :
120 0 : for (const auto &RI : R)
121 0 : printRegionCluster(*RI, GW, depth + 1);
122 :
123 0 : const RegionInfo &RI = *static_cast<const RegionInfo*>(R.getRegionInfo());
124 :
125 0 : for (auto *BB : R.blocks())
126 0 : if (RI.getRegionFor(BB) == &R)
127 0 : O.indent(2 * (depth + 1)) << "Node"
128 0 : << static_cast<const void*>(RI.getTopLevelRegion()->getBBNode(BB))
129 0 : << ";\n";
130 :
131 0 : O.indent(2 * depth) << "}\n";
132 0 : }
133 :
134 0 : static void addCustomGraphFeatures(const RegionInfo *G,
135 : GraphWriter<RegionInfo *> &GW) {
136 0 : raw_ostream &O = GW.getOStream();
137 0 : O << "\tcolorscheme = \"paired12\"\n";
138 0 : printRegionCluster(*G->getTopLevelRegion(), GW, 4);
139 0 : }
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 0 : RegionPrinter()
156 0 : : DOTGraphTraitsPrinter<RegionInfoPass, false, RegionInfo *,
157 0 : RegionInfoPassGraphTraits>("reg", ID) {
158 0 : initializeRegionPrinterPass(*PassRegistry::getPassRegistry());
159 0 : }
160 : };
161 : char RegionPrinter::ID = 0;
162 :
163 : struct RegionOnlyPrinter
164 : : public DOTGraphTraitsPrinter<RegionInfoPass, true, RegionInfo *,
165 : RegionInfoPassGraphTraits> {
166 : static char ID;
167 0 : RegionOnlyPrinter()
168 0 : : DOTGraphTraitsPrinter<RegionInfoPass, true, RegionInfo *,
169 0 : RegionInfoPassGraphTraits>("reg", ID) {
170 0 : initializeRegionOnlyPrinterPass(*PassRegistry::getPassRegistry());
171 0 : }
172 : };
173 : char RegionOnlyPrinter::ID = 0;
174 :
175 : struct RegionViewer
176 : : public DOTGraphTraitsViewer<RegionInfoPass, false, RegionInfo *,
177 : RegionInfoPassGraphTraits> {
178 : static char ID;
179 0 : RegionViewer()
180 0 : : DOTGraphTraitsViewer<RegionInfoPass, false, RegionInfo *,
181 0 : RegionInfoPassGraphTraits>("reg", ID) {
182 0 : initializeRegionViewerPass(*PassRegistry::getPassRegistry());
183 0 : }
184 : };
185 : char RegionViewer::ID = 0;
186 :
187 : struct RegionOnlyViewer
188 : : public DOTGraphTraitsViewer<RegionInfoPass, true, RegionInfo *,
189 : RegionInfoPassGraphTraits> {
190 : static char ID;
191 0 : RegionOnlyViewer()
192 0 : : DOTGraphTraitsViewer<RegionInfoPass, true, RegionInfo *,
193 0 : RegionInfoPassGraphTraits>("regonly", ID) {
194 0 : initializeRegionOnlyViewerPass(*PassRegistry::getPassRegistry());
195 0 : }
196 : };
197 : char RegionOnlyViewer::ID = 0;
198 :
199 : } //end anonymous namespace
200 :
201 21512 : INITIALIZE_PASS(RegionPrinter, "dot-regions",
202 : "Print regions of function to 'dot' file", true, true)
203 :
204 21512 : INITIALIZE_PASS(
205 : RegionOnlyPrinter, "dot-regions-only",
206 : "Print regions of function to 'dot' file (with no function bodies)", true,
207 : true)
208 :
209 21512 : INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function",
210 : true, true)
211 :
212 21512 : INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only",
213 : "View regions of function (with no function bodies)",
214 : true, true)
215 :
216 0 : FunctionPass *llvm::createRegionPrinterPass() { return new RegionPrinter(); }
217 :
218 0 : FunctionPass *llvm::createRegionOnlyPrinterPass() {
219 0 : return new RegionOnlyPrinter();
220 : }
221 :
222 0 : FunctionPass* llvm::createRegionViewerPass() {
223 0 : return new RegionViewer();
224 : }
225 :
226 0 : FunctionPass* llvm::createRegionOnlyViewerPass() {
227 0 : 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
|