1 //===- DDGPrinter.cpp - DOT printer for the data dependence graph ----------==//
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 //===----------------------------------------------------------------------===//
10 //
11 // This file defines the `-dot-ddg` analysis pass, which emits DDG in DOT format
12 // in a file named `ddg.<graph-name>.dot` for each loop  in a function.
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/Analysis/DDGPrinter.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/GraphWriter.h"
18 
19 using namespace llvm;
20 
21 static cl::opt<bool> DotOnly("dot-ddg-only", cl::Hidden,
22                              cl::desc("simple ddg dot graph"));
23 static cl::opt<std::string> DDGDotFilenamePrefix(
24     "dot-ddg-filename-prefix", cl::init("ddg"), cl::Hidden,
25     cl::desc("The prefix used for the DDG dot file names."));
26 
27 static void writeDDGToDotFile(DataDependenceGraph &G, bool DOnly = false);
28 
29 //===--------------------------------------------------------------------===//
30 // Implementation of DDG DOT Printer for a loop
31 //===--------------------------------------------------------------------===//
32 PreservedAnalyses DDGDotPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
33                                          LoopStandardAnalysisResults &AR,
34                                          LPMUpdater &U) {
35   writeDDGToDotFile(*AM.getResult<DDGAnalysis>(L, AR), DotOnly);
36   return PreservedAnalyses::all();
37 }
38 
39 static void writeDDGToDotFile(DataDependenceGraph &G, bool DOnly) {
40   std::string Filename =
41       Twine(DDGDotFilenamePrefix + "." + G.getName() + ".dot").str();
42   errs() << "Writing '" << Filename << "'...";
43 
44   std::error_code EC;
45   raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
46 
47   if (!EC)
48     // We only provide the constant verson of the DOTGraphTrait specialization,
49     // hence the conversion to const pointer
50     WriteGraph(File, (const DataDependenceGraph *)&G, DOnly);
51   else
52     errs() << "  error opening file for writing!";
53   errs() << "\n";
54 }
55 
56 //===--------------------------------------------------------------------===//
57 // DDG DOT Printer Implementation
58 //===--------------------------------------------------------------------===//
59 std::string DDGDotGraphTraits::getNodeLabel(const DDGNode *Node,
60                                             const DataDependenceGraph *Graph) {
61   if (isSimple())
62     return getSimpleNodeLabel(Node, Graph);
63   else
64     return getVerboseNodeLabel(Node, Graph);
65 }
66 
67 std::string DDGDotGraphTraits::getEdgeAttributes(
68     const DDGNode *Node, GraphTraits<const DDGNode *>::ChildIteratorType I,
69     const DataDependenceGraph *G) {
70   const DDGEdge *E = static_cast<const DDGEdge *>(*I.getCurrent());
71   if (isSimple())
72     return getSimpleEdgeAttributes(Node, E, G);
73   else
74     return getVerboseEdgeAttributes(Node, E, G);
75 }
76 
77 bool DDGDotGraphTraits::isNodeHidden(const DDGNode *Node,
78                                      const DataDependenceGraph *Graph) {
79   if (isSimple() && isa<RootDDGNode>(Node))
80     return true;
81   assert(Graph && "expected a valid graph pointer");
82   return Graph->getPiBlock(*Node) != nullptr;
83 }
84 
85 std::string
86 DDGDotGraphTraits::getSimpleNodeLabel(const DDGNode *Node,
87                                       const DataDependenceGraph *G) {
88   std::string Str;
89   raw_string_ostream OS(Str);
90   if (isa<SimpleDDGNode>(Node))
91     for (auto *II : static_cast<const SimpleDDGNode *>(Node)->getInstructions())
92       OS << *II << "\n";
93   else if (isa<PiBlockDDGNode>(Node))
94     OS << "pi-block\nwith\n"
95        << cast<PiBlockDDGNode>(Node)->getNodes().size() << " nodes\n";
96   else if (isa<RootDDGNode>(Node))
97     OS << "root\n";
98   else
99     llvm_unreachable("Unimplemented type of node");
100   return OS.str();
101 }
102 
103 std::string
104 DDGDotGraphTraits::getVerboseNodeLabel(const DDGNode *Node,
105                                        const DataDependenceGraph *G) {
106   std::string Str;
107   raw_string_ostream OS(Str);
108   OS << "<kind:" << Node->getKind() << ">\n";
109   if (isa<SimpleDDGNode>(Node))
110     for (auto *II : static_cast<const SimpleDDGNode *>(Node)->getInstructions())
111       OS << *II << "\n";
112   else if (isa<PiBlockDDGNode>(Node)) {
113     OS << "--- start of nodes in pi-block ---\n";
114     unsigned Count = 0;
115     const auto &PNodes = cast<PiBlockDDGNode>(Node)->getNodes();
116     for (auto *PN : PNodes) {
117       OS << getVerboseNodeLabel(PN, G);
118       if (++Count != PNodes.size())
119         OS << "\n";
120     }
121     OS << "--- end of nodes in pi-block ---\n";
122   } else if (isa<RootDDGNode>(Node))
123     OS << "root\n";
124   else
125     llvm_unreachable("Unimplemented type of node");
126   return OS.str();
127 }
128 
129 std::string DDGDotGraphTraits::getSimpleEdgeAttributes(
130     const DDGNode *Src, const DDGEdge *Edge, const DataDependenceGraph *G) {
131   std::string Str;
132   raw_string_ostream OS(Str);
133   DDGEdge::EdgeKind Kind = Edge->getKind();
134   OS << "label=\"[" << Kind << "]\"";
135   return OS.str();
136 }
137 
138 std::string DDGDotGraphTraits::getVerboseEdgeAttributes(
139     const DDGNode *Src, const DDGEdge *Edge, const DataDependenceGraph *G) {
140   std::string Str;
141   raw_string_ostream OS(Str);
142   DDGEdge::EdgeKind Kind = Edge->getKind();
143   OS << "label=\"[";
144   if (Kind == DDGEdge::EdgeKind::MemoryDependence)
145     OS << G->getDependenceString(*Src, Edge->getTargetNode());
146   else
147     OS << Kind;
148   OS << "]\"";
149   return OS.str();
150 }
151