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