xref: /llvm-project/polly/lib/Analysis/ScopGraphPrinter.cpp (revision 36c7d79dc4c114728b5f003bf48cd7a41bf932a4)
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(""));
27 
28 static cl::opt<bool> ViewAll("polly-view-all",
29                              cl::desc("Also show functions without any scops"),
30                              cl::Hidden, cl::init(false));
31 
32 namespace llvm {
33 
getEdgeAttributes(RegionNode * srcNode,GraphTraits<RegionInfo * >::ChildIteratorType CI,ScopDetection * SD)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(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(srcBB))
56     return "constraint=false";
57 
58   return "";
59 }
60 
61 std::string
escapeString(llvm::StringRef 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 
printRegionCluster(ScopDetection * SD,const Region * R,raw_ostream & O,unsigned depth)74 void DOTGraphTraits<ScopDetection *>::printRegionCluster(ScopDetection *SD,
75                                                          const Region *R,
76                                                          raw_ostream &O,
77                                                          unsigned depth) {
78   O.indent(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(FileName + ":" + std::to_string(LineBegin) + "-" +
88                             std::to_string(LineEnd) + "\n");
89   }
90 
91   std::string ErrorMessage = SD->regionIsInvalidBecause(R);
92   ErrorMessage = escapeString(ErrorMessage);
93   O.indent(2 * (depth + 1))
94       << "label = \"" << Location << ErrorMessage << "\";\n";
95 
96   if (SD->isMaxRegionInScop(*R)) {
97     O.indent(2 * (depth + 1)) << "style = filled;\n";
98 
99     // Set color to green.
100     O.indent(2 * (depth + 1)) << "color = 3";
101   } else {
102     O.indent(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(2 * (depth + 1)) << "color = " << color << "\n";
111   }
112 
113   for (const auto &SubRegion : *R)
114     printRegionCluster(SD, SubRegion.get(), O, depth + 1);
115 
116   RegionInfo *RI = R->getRegionInfo();
117 
118   for (BasicBlock *BB : R->blocks())
119     if (RI->getRegionFor(BB) == R)
120       O.indent(2 * (depth + 1))
121           << "Node"
122           << static_cast<void *>(RI->getTopLevelRegion()->getBBNode(BB))
123           << ";\n";
124 
125   O.indent(2 * depth) << "}\n";
126 }
127 
addCustomGraphFeatures(ScopDetection * SD,GraphWriter<ScopDetection * > & GW)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, SD->getRI()->getTopLevelRegion(), O, 4);
133 }
134 
135 } // namespace llvm
136 
137 struct ScopDetectionAnalysisGraphTraits {
getGraphScopDetectionAnalysisGraphTraits138   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;
ScopViewerWrapperPassScopViewerWrapperPass148   ScopViewerWrapperPass()
149       : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
150                                         ScopDetection *,
151                                         ScopDetectionAnalysisGraphTraits>(
152             "scops", ID) {}
processFunctionScopViewerWrapperPass153   bool processFunction(Function &F, ScopDetectionWrapperPass &SD) override {
154     if (ViewFilter != "" && !F.getName().count(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(SD.getSD().begin(), 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;
ScopOnlyViewerWrapperPassScopOnlyViewerWrapperPass171   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;
ScopPrinterWrapperPassScopPrinterWrapperPass184   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;
ScopOnlyPrinterWrapperPassScopOnlyPrinterWrapperPass197   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 
createDOTViewerWrapperPass()219 Pass *polly::createDOTViewerWrapperPass() {
220   return new ScopViewerWrapperPass();
221 }
222 
createDOTOnlyViewerWrapperPass()223 Pass *polly::createDOTOnlyViewerWrapperPass() {
224   return new ScopOnlyViewerWrapperPass();
225 }
226 
createDOTPrinterWrapperPass()227 Pass *polly::createDOTPrinterWrapperPass() {
228   return new ScopPrinterWrapperPass();
229 }
230 
createDOTOnlyPrinterWrapperPass()231 Pass *polly::createDOTOnlyPrinterWrapperPass() {
232   return new ScopOnlyPrinterWrapperPass();
233 }
234 
processFunction(Function & F,const ScopDetection & SD)235 bool ScopViewer::processFunction(Function &F, const ScopDetection &SD) {
236   if (ViewFilter != "" && !F.getName().count(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(SD.begin(), SD.end()) > 0;
244 }
245