175805378STobias Grosser //===- GraphPrinter.cpp - Create a DOT output describing the Scop. --------===//
275805378STobias Grosser //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
675805378STobias Grosser //
775805378STobias Grosser //===----------------------------------------------------------------------===//
875805378STobias Grosser //
975805378STobias Grosser // Create a DOT output describing the Scop.
1075805378STobias Grosser //
1175805378STobias Grosser // For each function a dot file is created that shows the control flow graph of
1275805378STobias Grosser // the function and highlights the detected Scops.
1375805378STobias Grosser //
1475805378STobias Grosser //===----------------------------------------------------------------------===//
1575805378STobias Grosser 
166b3b8737SMichael Kruse #include "polly/ScopGraphPrinter.h"
1775805378STobias Grosser #include "polly/LinkAllPasses.h"
1875805378STobias Grosser #include "polly/ScopDetection.h"
1914e67e43STobias Grosser #include "llvm/Support/CommandLine.h"
2075805378STobias Grosser 
2175805378STobias Grosser using namespace polly;
2275805378STobias Grosser using namespace llvm;
2314e67e43STobias Grosser static cl::opt<std::string>
2414e67e43STobias Grosser     ViewFilter("polly-view-only",
2514e67e43STobias Grosser                cl::desc("Only view functions that match this pattern"),
26*36c7d79dSFangrui Song                cl::Hidden, cl::init(""));
2775805378STobias Grosser 
28deb4abb4STobias Grosser static cl::opt<bool> ViewAll("polly-view-all",
29eb2eebe4STobias Grosser                              cl::desc("Also show functions without any scops"),
30*36c7d79dSFangrui Song                              cl::Hidden, cl::init(false));
31eb2eebe4STobias Grosser 
3275805378STobias Grosser namespace llvm {
3375805378STobias Grosser 
getEdgeAttributes(RegionNode * srcNode,GraphTraits<RegionInfo * >::ChildIteratorType CI,ScopDetection * SD)346b3b8737SMichael Kruse std::string DOTGraphTraits<ScopDetection *>::getEdgeAttributes(
356b3b8737SMichael Kruse     RegionNode *srcNode, GraphTraits<RegionInfo *>::ChildIteratorType CI,
366b3b8737SMichael Kruse     ScopDetection *SD) {
3775805378STobias Grosser   RegionNode *destNode = *CI;
3875805378STobias Grosser 
3975805378STobias Grosser   if (srcNode->isSubRegion() || destNode->isSubRegion())
4075805378STobias Grosser     return "";
4175805378STobias Grosser 
4275805378STobias Grosser   // In case of a backedge, do not use it to define the layout of the nodes.
4375805378STobias Grosser   BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>();
4475805378STobias Grosser   BasicBlock *destBB = destNode->getNodeAs<BasicBlock>();
4575805378STobias Grosser 
4675805378STobias Grosser   RegionInfo *RI = SD->getRI();
4775805378STobias Grosser   Region *R = RI->getRegionFor(destBB);
4875805378STobias Grosser 
4975805378STobias Grosser   while (R && R->getParent())
5075805378STobias Grosser     if (R->getParent()->getEntry() == destBB)
5175805378STobias Grosser       R = R->getParent();
5275805378STobias Grosser     else
5375805378STobias Grosser       break;
5475805378STobias Grosser 
55eefe9416STobias Grosser   if (R && R->getEntry() == destBB && R->contains(srcBB))
5675805378STobias Grosser     return "constraint=false";
5775805378STobias Grosser 
5875805378STobias Grosser   return "";
5975805378STobias Grosser }
6075805378STobias Grosser 
616b3b8737SMichael Kruse std::string
escapeString(llvm::StringRef String)626b3b8737SMichael Kruse DOTGraphTraits<ScopDetection *>::escapeString(llvm::StringRef String) {
630b5a1959STobias Grosser   std::string Escaped;
640b5a1959STobias Grosser 
65083d3d3cSTobias Grosser   for (const auto &C : String) {
66083d3d3cSTobias Grosser     if (C == '"')
670b5a1959STobias Grosser       Escaped += '\\';
680b5a1959STobias Grosser 
69083d3d3cSTobias Grosser     Escaped += C;
700b5a1959STobias Grosser   }
710b5a1959STobias Grosser   return Escaped;
720b5a1959STobias Grosser }
730b5a1959STobias Grosser 
printRegionCluster(ScopDetection * SD,const Region * R,raw_ostream & O,unsigned depth)746b3b8737SMichael Kruse void DOTGraphTraits<ScopDetection *>::printRegionCluster(ScopDetection *SD,
756b3b8737SMichael Kruse                                                          const Region *R,
766b3b8737SMichael Kruse                                                          raw_ostream &O,
776b3b8737SMichael Kruse                                                          unsigned depth) {
7875805378STobias Grosser   O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void *>(R)
7975805378STobias Grosser                       << " {\n";
80a63b7ceeSTobias Grosser   unsigned LineBegin, LineEnd;
81a63b7ceeSTobias Grosser   std::string FileName;
82a63b7ceeSTobias Grosser 
83a63b7ceeSTobias Grosser   getDebugLocation(R, LineBegin, LineEnd, FileName);
84a63b7ceeSTobias Grosser 
85a63b7ceeSTobias Grosser   std::string Location;
86a63b7ceeSTobias Grosser   if (LineBegin != (unsigned)-1) {
87a63b7ceeSTobias Grosser     Location = escapeString(FileName + ":" + std::to_string(LineBegin) + "-" +
88a63b7ceeSTobias Grosser                             std::to_string(LineEnd) + "\n");
89a63b7ceeSTobias Grosser   }
90a63b7ceeSTobias Grosser 
914f129a6bSTobias Grosser   std::string ErrorMessage = SD->regionIsInvalidBecause(R);
920b5a1959STobias Grosser   ErrorMessage = escapeString(ErrorMessage);
93b6945e33STobias Grosser   O.indent(2 * (depth + 1))
94b6945e33STobias Grosser       << "label = \"" << Location << ErrorMessage << "\";\n";
9575805378STobias Grosser 
9675805378STobias Grosser   if (SD->isMaxRegionInScop(*R)) {
9775805378STobias Grosser     O.indent(2 * (depth + 1)) << "style = filled;\n";
9875805378STobias Grosser 
9975805378STobias Grosser     // Set color to green.
10075805378STobias Grosser     O.indent(2 * (depth + 1)) << "color = 3";
10175805378STobias Grosser   } else {
10275805378STobias Grosser     O.indent(2 * (depth + 1)) << "style = solid;\n";
10375805378STobias Grosser 
10475805378STobias Grosser     int color = (R->getDepth() * 2 % 12) + 1;
10575805378STobias Grosser 
10675805378STobias Grosser     // We do not want green again.
10775805378STobias Grosser     if (color == 3)
10875805378STobias Grosser       color = 6;
10975805378STobias Grosser 
1104d96c8d7STobias Grosser     O.indent(2 * (depth + 1)) << "color = " << color << "\n";
11175805378STobias Grosser   }
11275805378STobias Grosser 
1131d191909STobias Grosser   for (const auto &SubRegion : *R)
1141fc97224SChandler Carruth     printRegionCluster(SD, SubRegion.get(), O, depth + 1);
11575805378STobias Grosser 
11675805378STobias Grosser   RegionInfo *RI = R->getRegionInfo();
11775805378STobias Grosser 
1181d549cffSMark de Wever   for (BasicBlock *BB : R->blocks())
1191d191909STobias Grosser     if (RI->getRegionFor(BB) == R)
1204d96c8d7STobias Grosser       O.indent(2 * (depth + 1))
121aef925e8STobias Grosser           << "Node"
1221d191909STobias Grosser           << static_cast<void *>(RI->getTopLevelRegion()->getBBNode(BB))
123aef925e8STobias Grosser           << ";\n";
12475805378STobias Grosser 
12575805378STobias Grosser   O.indent(2 * depth) << "}\n";
12675805378STobias Grosser }
1276b3b8737SMichael Kruse 
addCustomGraphFeatures(ScopDetection * SD,GraphWriter<ScopDetection * > & GW)1286b3b8737SMichael Kruse void DOTGraphTraits<ScopDetection *>::addCustomGraphFeatures(
1296b3b8737SMichael Kruse     ScopDetection *SD, GraphWriter<ScopDetection *> &GW) {
13075805378STobias Grosser   raw_ostream &O = GW.getOStream();
13175805378STobias Grosser   O << "\tcolorscheme = \"paired12\"\n";
1326b3b8737SMichael Kruse   printRegionCluster(SD, SD->getRI()->getTopLevelRegion(), O, 4);
1336b3b8737SMichael Kruse }
1346b3b8737SMichael Kruse 
1356b3b8737SMichael Kruse } // namespace llvm
1366b3b8737SMichael Kruse 
1376b3b8737SMichael Kruse struct ScopDetectionAnalysisGraphTraits {
getGraphScopDetectionAnalysisGraphTraits1386b3b8737SMichael Kruse   static ScopDetection *getGraph(ScopDetectionWrapperPass *Analysis) {
1396b3b8737SMichael Kruse     return &Analysis->getSD();
14075805378STobias Grosser   }
14175805378STobias Grosser };
14275805378STobias Grosser 
1436b3b8737SMichael Kruse struct ScopViewerWrapperPass
144bd93df93SMichael Kruse     : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
1456b3b8737SMichael Kruse                                       ScopDetection *,
1466b3b8737SMichael Kruse                                       ScopDetectionAnalysisGraphTraits> {
14775805378STobias Grosser   static char ID;
ScopViewerWrapperPassScopViewerWrapperPass1486b3b8737SMichael Kruse   ScopViewerWrapperPass()
1496b3b8737SMichael Kruse       : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
1506b3b8737SMichael Kruse                                         ScopDetection *,
1516b3b8737SMichael Kruse                                         ScopDetectionAnalysisGraphTraits>(
152a6b399adSMichael Kruse             "scops", ID) {}
processFunctionScopViewerWrapperPass1535cc87e3aSPhilip Pfaffe   bool processFunction(Function &F, ScopDetectionWrapperPass &SD) override {
154eb2eebe4STobias Grosser     if (ViewFilter != "" && !F.getName().count(ViewFilter))
15514e67e43STobias Grosser       return false;
156eb2eebe4STobias Grosser 
157eb2eebe4STobias Grosser     if (ViewAll)
158eb2eebe4STobias Grosser       return true;
159eb2eebe4STobias Grosser 
160eb2eebe4STobias Grosser     // Check that at least one scop was detected.
1615cc87e3aSPhilip Pfaffe     return std::distance(SD.getSD().begin(), SD.getSD().end()) > 0;
16214e67e43STobias Grosser   }
16375805378STobias Grosser };
1646b3b8737SMichael Kruse char ScopViewerWrapperPass::ID = 0;
16575805378STobias Grosser 
1666b3b8737SMichael Kruse struct ScopOnlyViewerWrapperPass
167bd93df93SMichael Kruse     : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
1686b3b8737SMichael Kruse                                       ScopDetection *,
1696b3b8737SMichael Kruse                                       ScopDetectionAnalysisGraphTraits> {
17075805378STobias Grosser   static char ID;
ScopOnlyViewerWrapperPassScopOnlyViewerWrapperPass1716b3b8737SMichael Kruse   ScopOnlyViewerWrapperPass()
1726b3b8737SMichael Kruse       : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false,
1736b3b8737SMichael Kruse                                         ScopDetection *,
1746b3b8737SMichael Kruse                                         ScopDetectionAnalysisGraphTraits>(
175a6b399adSMichael Kruse             "scopsonly", ID) {}
17675805378STobias Grosser };
1776b3b8737SMichael Kruse char ScopOnlyViewerWrapperPass::ID = 0;
17875805378STobias Grosser 
1796b3b8737SMichael Kruse struct ScopPrinterWrapperPass
180bd93df93SMichael Kruse     : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, false,
181bd93df93SMichael Kruse                                        ScopDetection *,
1826b3b8737SMichael Kruse                                        ScopDetectionAnalysisGraphTraits> {
18375805378STobias Grosser   static char ID;
ScopPrinterWrapperPassScopPrinterWrapperPass1846b3b8737SMichael Kruse   ScopPrinterWrapperPass()
1856b3b8737SMichael Kruse       : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, false,
1866b3b8737SMichael Kruse                                          ScopDetection *,
1876b3b8737SMichael Kruse                                          ScopDetectionAnalysisGraphTraits>(
188a6b399adSMichael Kruse             "scops", ID) {}
18975805378STobias Grosser };
1906b3b8737SMichael Kruse char ScopPrinterWrapperPass::ID = 0;
19175805378STobias Grosser 
1926b3b8737SMichael Kruse struct ScopOnlyPrinterWrapperPass
193bd93df93SMichael Kruse     : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, true,
194bd93df93SMichael Kruse                                        ScopDetection *,
1956b3b8737SMichael Kruse                                        ScopDetectionAnalysisGraphTraits> {
19675805378STobias Grosser   static char ID;
ScopOnlyPrinterWrapperPassScopOnlyPrinterWrapperPass1976b3b8737SMichael Kruse   ScopOnlyPrinterWrapperPass()
1986b3b8737SMichael Kruse       : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, true,
1996b3b8737SMichael Kruse                                          ScopDetection *,
2006b3b8737SMichael Kruse                                          ScopDetectionAnalysisGraphTraits>(
201a6b399adSMichael Kruse             "scopsonly", ID) {}
20275805378STobias Grosser };
2036b3b8737SMichael Kruse char ScopOnlyPrinterWrapperPass::ID = 0;
20475805378STobias Grosser 
2056b3b8737SMichael Kruse static RegisterPass<ScopViewerWrapperPass> X("view-scops",
206e602a076STobias Grosser                                              "Polly - View Scops of function");
20775805378STobias Grosser 
2086b3b8737SMichael Kruse static RegisterPass<ScopOnlyViewerWrapperPass>
20975805378STobias Grosser     Y("view-scops-only",
21075805378STobias Grosser       "Polly - View Scops of function (with no function bodies)");
21175805378STobias Grosser 
2126b3b8737SMichael Kruse static RegisterPass<ScopPrinterWrapperPass>
2136b3b8737SMichael Kruse     M("dot-scops", "Polly - Print Scops of function");
21475805378STobias Grosser 
2156b3b8737SMichael Kruse static RegisterPass<ScopOnlyPrinterWrapperPass>
21675805378STobias Grosser     N("dot-scops-only",
21775805378STobias Grosser       "Polly - Print Scops of function (with no function bodies)");
21875805378STobias Grosser 
createDOTViewerWrapperPass()2196b3b8737SMichael Kruse Pass *polly::createDOTViewerWrapperPass() {
2206b3b8737SMichael Kruse   return new ScopViewerWrapperPass();
2216b3b8737SMichael Kruse }
22275805378STobias Grosser 
createDOTOnlyViewerWrapperPass()2236b3b8737SMichael Kruse Pass *polly::createDOTOnlyViewerWrapperPass() {
2246b3b8737SMichael Kruse   return new ScopOnlyViewerWrapperPass();
2256b3b8737SMichael Kruse }
22675805378STobias Grosser 
createDOTPrinterWrapperPass()2276b3b8737SMichael Kruse Pass *polly::createDOTPrinterWrapperPass() {
2286b3b8737SMichael Kruse   return new ScopPrinterWrapperPass();
2296b3b8737SMichael Kruse }
23075805378STobias Grosser 
createDOTOnlyPrinterWrapperPass()2316b3b8737SMichael Kruse Pass *polly::createDOTOnlyPrinterWrapperPass() {
2326b3b8737SMichael Kruse   return new ScopOnlyPrinterWrapperPass();
2336b3b8737SMichael Kruse }
2346b3b8737SMichael Kruse 
processFunction(Function & F,const ScopDetection & SD)2356b3b8737SMichael Kruse bool ScopViewer::processFunction(Function &F, const ScopDetection &SD) {
2366b3b8737SMichael Kruse   if (ViewFilter != "" && !F.getName().count(ViewFilter))
2376b3b8737SMichael Kruse     return false;
2386b3b8737SMichael Kruse 
2396b3b8737SMichael Kruse   if (ViewAll)
2406b3b8737SMichael Kruse     return true;
2416b3b8737SMichael Kruse 
2426b3b8737SMichael Kruse   // Check that at least one scop was detected.
2436b3b8737SMichael Kruse   return std::distance(SD.begin(), SD.end()) > 0;
2446b3b8737SMichael Kruse }
245