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 | |
21 | using namespace polly; |
22 | using namespace llvm; |
23 | static 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 | |
28 | static cl::opt<bool> ViewAll("polly-view-all" , |
29 | cl::desc("Also show functions without any scops" ), |
30 | cl::Hidden, cl::init(Val: false)); |
31 | |
32 | namespace llvm { |
33 | |
34 | std::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 | |
61 | std::string |
62 | DOTGraphTraits<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 | |
74 | void 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 | |
128 | void 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 | |
137 | struct ScopDetectionAnalysisGraphTraits { |
138 | static ScopDetection *getGraph(ScopDetectionWrapperPass *Analysis) { |
139 | return &Analysis->getSD(); |
140 | } |
141 | }; |
142 | |
143 | struct 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 | }; |
164 | char ScopViewerWrapperPass::ID = 0; |
165 | |
166 | struct 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 | }; |
177 | char ScopOnlyViewerWrapperPass::ID = 0; |
178 | |
179 | struct 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 | }; |
190 | char ScopPrinterWrapperPass::ID = 0; |
191 | |
192 | struct 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 | }; |
203 | char ScopOnlyPrinterWrapperPass::ID = 0; |
204 | |
205 | static RegisterPass<ScopViewerWrapperPass> X("view-scops" , |
206 | "Polly - View Scops of function" ); |
207 | |
208 | static RegisterPass<ScopOnlyViewerWrapperPass> |
209 | Y("view-scops-only" , |
210 | "Polly - View Scops of function (with no function bodies)" ); |
211 | |
212 | static RegisterPass<ScopPrinterWrapperPass> |
213 | M("dot-scops" , "Polly - Print Scops of function" ); |
214 | |
215 | static RegisterPass<ScopOnlyPrinterWrapperPass> |
216 | N("dot-scops-only" , |
217 | "Polly - Print Scops of function (with no function bodies)" ); |
218 | |
219 | Pass *polly::createDOTViewerWrapperPass() { |
220 | return new ScopViewerWrapperPass(); |
221 | } |
222 | |
223 | Pass *polly::createDOTOnlyViewerWrapperPass() { |
224 | return new ScopOnlyViewerWrapperPass(); |
225 | } |
226 | |
227 | Pass *polly::createDOTPrinterWrapperPass() { |
228 | return new ScopPrinterWrapperPass(); |
229 | } |
230 | |
231 | Pass *polly::createDOTOnlyPrinterWrapperPass() { |
232 | return new ScopOnlyPrinterWrapperPass(); |
233 | } |
234 | |
235 | bool 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 | |