1//===- GraphPrinter.cpp - Create a DOT output describing the Scop. --------===//
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//
9// Create a DOT output describing the Scop.
10//
11// For each function a dot file is created that shows the control flow graph of
12// the function and highlights the detected Scops.
13//
14//===----------------------------------------------------------------------===//
15
16#include "polly/ScopGraphPrinter.h"
17#include "polly/LinkAllPasses.h"
18#include "polly/ScopDetection.h"
19#include "llvm/Support/CommandLine.h"
20
21using namespace polly;
22using namespace llvm;
23static cl::opt<std::string>
24 ViewFilter("polly-view-only",
25 cl::desc("Only view functions that match this pattern"),
26 cl::Hidden, cl::init(Val: ""));
27
28static cl::opt<bool> ViewAll("polly-view-all",
29 cl::desc("Also show functions without any scops"),
30 cl::Hidden, cl::init(Val: false));
31
32namespace llvm {
33
34std::string DOTGraphTraits<ScopDetection *>::getEdgeAttributes(
35 RegionNode *srcNode, GraphTraits<RegionInfo *>::ChildIteratorType CI,
36 ScopDetection *SD) {
37 RegionNode *destNode = *CI;
38
39 if (srcNode->isSubRegion() || destNode->isSubRegion())
40 return "";
41
42 // In case of a backedge, do not use it to define the layout of the nodes.
43 BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>();
44 BasicBlock *destBB = destNode->getNodeAs<BasicBlock>();
45
46 RegionInfo *RI = SD->getRI();
47 Region *R = RI->getRegionFor(BB: destBB);
48
49 while (R && R->getParent())
50 if (R->getParent()->getEntry() == destBB)
51 R = R->getParent();
52 else
53 break;
54
55 if (R && R->getEntry() == destBB && R->contains(BB: srcBB))
56 return "constraint=false";
57
58 return "";
59}
60
61std::string
62DOTGraphTraits<ScopDetection *>::escapeString(llvm::StringRef String) {
63 std::string Escaped;
64
65 for (const auto &C : String) {
66 if (C == '"')
67 Escaped += '\\';
68
69 Escaped += C;
70 }
71 return Escaped;
72}
73
74void DOTGraphTraits<ScopDetection *>::printRegionCluster(ScopDetection *SD,
75 const Region *R,
76 raw_ostream &O,
77 unsigned depth) {
78 O.indent(NumSpaces: 2 * depth) << "subgraph cluster_" << static_cast<const void *>(R)
79 << " {\n";
80 unsigned LineBegin, LineEnd;
81 std::string FileName;
82
83 getDebugLocation(R, LineBegin, LineEnd, FileName);
84
85 std::string Location;
86 if (LineBegin != (unsigned)-1) {
87 Location = escapeString(String: FileName + ":" + std::to_string(val: LineBegin) + "-" +
88 std::to_string(val: LineEnd) + "\n");
89 }
90
91 std::string ErrorMessage = SD->regionIsInvalidBecause(R);
92 ErrorMessage = escapeString(String: ErrorMessage);
93 O.indent(NumSpaces: 2 * (depth + 1))
94 << "label = \"" << Location << ErrorMessage << "\";\n";
95
96 if (SD->isMaxRegionInScop(R: *R)) {
97 O.indent(NumSpaces: 2 * (depth + 1)) << "style = filled;\n";
98
99 // Set color to green.
100 O.indent(NumSpaces: 2 * (depth + 1)) << "color = 3";
101 } else {
102 O.indent(NumSpaces: 2 * (depth + 1)) << "style = solid;\n";
103
104 int color = (R->getDepth() * 2 % 12) + 1;
105
106 // We do not want green again.
107 if (color == 3)
108 color = 6;
109
110 O.indent(NumSpaces: 2 * (depth + 1)) << "color = " << color << "\n";
111 }
112
113 for (const auto &SubRegion : *R)
114 printRegionCluster(SD, R: SubRegion.get(), O, depth: depth + 1);
115
116 RegionInfo *RI = R->getRegionInfo();
117
118 for (BasicBlock *BB : R->blocks())
119 if (RI->getRegionFor(BB) == R)
120 O.indent(NumSpaces: 2 * (depth + 1))
121 << "Node"
122 << static_cast<void *>(RI->getTopLevelRegion()->getBBNode(BB))
123 << ";\n";
124
125 O.indent(NumSpaces: 2 * depth) << "}\n";
126}
127
128void DOTGraphTraits<ScopDetection *>::addCustomGraphFeatures(
129 ScopDetection *SD, GraphWriter<ScopDetection *> &GW) {
130 raw_ostream &O = GW.getOStream();
131 O << "\tcolorscheme = \"paired12\"\n";
132 printRegionCluster(SD, R: SD->getRI()->getTopLevelRegion(), O, depth: 4);
133}
134
135} // namespace llvm
136
137struct ScopDetectionAnalysisGraphTraits {
138 static ScopDetection *getGraph(ScopDetectionWrapperPass *Analysis) {
139 return &Analysis->getSD();
140 }
141};
142
143struct ScopViewerWrapperPass
144 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
145 ScopDetection *,
146 ScopDetectionAnalysisGraphTraits> {
147 static char ID;
148 ScopViewerWrapperPass()
149 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
150 ScopDetection *,
151 ScopDetectionAnalysisGraphTraits>(
152 "scops", ID) {}
153 bool processFunction(Function &F, ScopDetectionWrapperPass &SD) override {
154 if (ViewFilter != "" && !F.getName().count(Str: ViewFilter))
155 return false;
156
157 if (ViewAll)
158 return true;
159
160 // Check that at least one scop was detected.
161 return std::distance(first: SD.getSD().begin(), last: SD.getSD().end()) > 0;
162 }
163};
164char ScopViewerWrapperPass::ID = 0;
165
166struct ScopOnlyViewerWrapperPass
167 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
168 ScopDetection *,
169 ScopDetectionAnalysisGraphTraits> {
170 static char ID;
171 ScopOnlyViewerWrapperPass()
172 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
173 ScopDetection *,
174 ScopDetectionAnalysisGraphTraits>(
175 "scopsonly", ID) {}
176};
177char ScopOnlyViewerWrapperPass::ID = 0;
178
179struct ScopPrinterWrapperPass
180 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, false,
181 ScopDetection *,
182 ScopDetectionAnalysisGraphTraits> {
183 static char ID;
184 ScopPrinterWrapperPass()
185 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, false,
186 ScopDetection *,
187 ScopDetectionAnalysisGraphTraits>(
188 "scops", ID) {}
189};
190char ScopPrinterWrapperPass::ID = 0;
191
192struct ScopOnlyPrinterWrapperPass
193 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, true,
194 ScopDetection *,
195 ScopDetectionAnalysisGraphTraits> {
196 static char ID;
197 ScopOnlyPrinterWrapperPass()
198 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, true,
199 ScopDetection *,
200 ScopDetectionAnalysisGraphTraits>(
201 "scopsonly", ID) {}
202};
203char ScopOnlyPrinterWrapperPass::ID = 0;
204
205static RegisterPass<ScopViewerWrapperPass> X("view-scops",
206 "Polly - View Scops of function");
207
208static RegisterPass<ScopOnlyViewerWrapperPass>
209 Y("view-scops-only",
210 "Polly - View Scops of function (with no function bodies)");
211
212static RegisterPass<ScopPrinterWrapperPass>
213 M("dot-scops", "Polly - Print Scops of function");
214
215static RegisterPass<ScopOnlyPrinterWrapperPass>
216 N("dot-scops-only",
217 "Polly - Print Scops of function (with no function bodies)");
218
219Pass *polly::createDOTViewerWrapperPass() {
220 return new ScopViewerWrapperPass();
221}
222
223Pass *polly::createDOTOnlyViewerWrapperPass() {
224 return new ScopOnlyViewerWrapperPass();
225}
226
227Pass *polly::createDOTPrinterWrapperPass() {
228 return new ScopPrinterWrapperPass();
229}
230
231Pass *polly::createDOTOnlyPrinterWrapperPass() {
232 return new ScopOnlyPrinterWrapperPass();
233}
234
235bool ScopViewer::processFunction(Function &F, const ScopDetection &SD) {
236 if (ViewFilter != "" && !F.getName().count(Str: ViewFilter))
237 return false;
238
239 if (ViewAll)
240 return true;
241
242 // Check that at least one scop was detected.
243 return std::distance(first: SD.begin(), last: SD.end()) > 0;
244}
245

source code of polly/lib/Analysis/ScopGraphPrinter.cpp