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