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
19using namespace llvm;
20
21static cl::opt<bool> DotOnly("dot-ddg-only", cl::Hidden,
22 cl::desc("simple ddg dot graph"));
23static cl::opt<std::string> DDGDotFilenamePrefix(
24 "dot-ddg-filename-prefix", cl::init(Val: "ddg"), cl::Hidden,
25 cl::desc("The prefix used for the DDG dot file names."));
26
27static void writeDDGToDotFile(DataDependenceGraph &G, bool DOnly = false);
28
29//===--------------------------------------------------------------------===//
30// Implementation of DDG DOT Printer for a loop
31//===--------------------------------------------------------------------===//
32PreservedAnalyses DDGDotPrinterPass::run(Loop &L, LoopAnalysisManager &AM,
33 LoopStandardAnalysisResults &AR,
34 LPMUpdater &U) {
35 writeDDGToDotFile(G&: *AM.getResult<DDGAnalysis>(IR&: L, ExtraArgs&: AR), DOnly: DotOnly);
36 return PreservedAnalyses::all();
37}
38
39static 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(O&: File, G: (const DataDependenceGraph *)&G, ShortNames: DOnly);
51 else
52 errs() << " error opening file for writing!";
53 errs() << "\n";
54}
55
56//===--------------------------------------------------------------------===//
57// DDG DOT Printer Implementation
58//===--------------------------------------------------------------------===//
59std::string DDGDotGraphTraits::getNodeLabel(const DDGNode *Node,
60 const DataDependenceGraph *Graph) {
61 if (isSimple())
62 return getSimpleNodeLabel(Node, G: Graph);
63 else
64 return getVerboseNodeLabel(Node, G: Graph);
65}
66
67std::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(Src: Node, Edge: E, G);
73 else
74 return getVerboseEdgeAttributes(Src: Node, Edge: E, G);
75}
76
77bool DDGDotGraphTraits::isNodeHidden(const DDGNode *Node,
78 const DataDependenceGraph *Graph) {
79 if (isSimple() && isa<RootDDGNode>(Val: Node))
80 return true;
81 assert(Graph && "expected a valid graph pointer");
82 return Graph->getPiBlock(N: *Node) != nullptr;
83}
84
85std::string DDGDotGraphTraits::getNodeAttributes(const DDGNode *Node,
86 const DataDependenceGraph *) {
87 if (isa<PiBlockDDGNode>(Val: Node))
88 return "shape=box, style=\"rounded,filled\", fillcolor=lightyellow, "
89 "color=darkorange, penwidth=3";
90 if (isa<SimpleDDGNode>(Val: Node) &&
91 Node->getKind() == DDGNode::NodeKind::MultiInstruction)
92 return "style=filled, fillcolor=lightcyan";
93 return "";
94}
95
96std::string
97DDGDotGraphTraits::getSimpleNodeLabel(const DDGNode *Node,
98 const DataDependenceGraph *G) {
99 std::string Str;
100 raw_string_ostream OS(Str);
101 if (isa<SimpleDDGNode>(Val: Node))
102 for (auto *II : static_cast<const SimpleDDGNode *>(Node)->getInstructions())
103 OS << *II << "\n";
104 else if (isa<PiBlockDDGNode>(Val: Node))
105 OS << "pi-block\nwith\n"
106 << cast<PiBlockDDGNode>(Val: Node)->getNodes().size() << " nodes\n";
107 else if (isa<RootDDGNode>(Val: Node))
108 OS << "root\n";
109 else
110 llvm_unreachable("Unimplemented type of node");
111 return OS.str();
112}
113
114std::string
115DDGDotGraphTraits::getVerboseNodeLabel(const DDGNode *Node,
116 const DataDependenceGraph *G) {
117 std::string Str;
118 raw_string_ostream OS(Str);
119 OS << "<kind:" << Node->getKind() << ">\n";
120 if (isa<SimpleDDGNode>(Val: Node))
121 for (auto *II : static_cast<const SimpleDDGNode *>(Node)->getInstructions())
122 OS << *II << "\n";
123 else if (isa<PiBlockDDGNode>(Val: Node)) {
124 OS << "--- start of nodes in pi-block ---\n";
125 unsigned Count = 0;
126 const auto &PNodes = cast<PiBlockDDGNode>(Val: Node)->getNodes();
127 for (auto *PN : PNodes) {
128 OS << getVerboseNodeLabel(Node: PN, G);
129 if (++Count != PNodes.size())
130 OS << "\n";
131 }
132 OS << "--- end of nodes in pi-block ---\n";
133 } else if (isa<RootDDGNode>(Val: Node))
134 OS << "root\n";
135 else
136 llvm_unreachable("Unimplemented type of node");
137 return OS.str();
138}
139
140/// EdgeKind to DOT color mapping:
141/// - MemoryDependence: red
142/// - RegisterDefUse: blue
143/// - Rooted/Unknown=default (no attribute).
144static void writeEdgeKindColorAttr(raw_ostream &OS, DDGEdge::EdgeKind Kind) {
145 if (Kind == DDGEdge::EdgeKind::MemoryDependence)
146 OS << ", color=red";
147 else if (Kind == DDGEdge::EdgeKind::RegisterDefUse)
148 OS << ", color=blue";
149}
150
151std::string DDGDotGraphTraits::getSimpleEdgeAttributes(
152 const DDGNode *Src, const DDGEdge *Edge, const DataDependenceGraph *G) {
153 std::string Str;
154 raw_string_ostream OS(Str);
155 DDGEdge::EdgeKind Kind = Edge->getKind();
156 OS << "label=\"[" << Kind << "]\"";
157 writeEdgeKindColorAttr(OS, Kind);
158 return OS.str();
159}
160
161std::string DDGDotGraphTraits::getVerboseEdgeAttributes(
162 const DDGNode *Src, const DDGEdge *Edge, const DataDependenceGraph *G) {
163 std::string Str;
164 raw_string_ostream OS(Str);
165 DDGEdge::EdgeKind Kind = Edge->getKind();
166 OS << "label=\"[";
167 if (Kind == DDGEdge::EdgeKind::MemoryDependence)
168 OS << G->getDependenceString(Src: *Src, Dst: Edge->getTargetNode());
169 else
170 OS << Kind;
171 OS << "]\"";
172 writeEdgeKindColorAttr(OS, Kind);
173 return OS.str();
174}
175