1
//===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===//
3
// The LLVM Compiler Infrastructure
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
8
//===----------------------------------------------------------------------===//
10
// This file defines a simple interface that can be used to print out generic
11
// LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T
12
// graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
13
// be used to turn the files output by this interface into a variety of
14
// different graphics formats.
16
// Graphs do not need to implement any interface past what is already required
17
// by the GraphTraits template, but they can choose to implement specializations
18
// of the DOTGraphTraits template if they want to customize the graphs output in
21
//===----------------------------------------------------------------------===//
23
#ifndef LLVM_SUPPORT_GRAPHWRITER_H
24
#define LLVM_SUPPORT_GRAPHWRITER_H
26
#include "llvm/Support/DOTGraphTraits.h"
27
#include "llvm/Support/raw_ostream.h"
28
#include "llvm/ADT/GraphTraits.h"
29
#include "llvm/System/Path.h"
35
namespace DOT { // Private functions...
36
std::string EscapeString(const std::string &Label);
39
namespace GraphProgram {
49
void DisplayGraph(const sys::Path& Filename, bool wait=true, GraphProgram::Name program = GraphProgram::DOT);
51
template<typename GraphType>
56
typedef DOTGraphTraits<GraphType> DOTTraits;
57
typedef GraphTraits<GraphType> GTraits;
58
typedef typename GTraits::NodeType NodeType;
59
typedef typename GTraits::nodes_iterator node_iterator;
60
typedef typename GTraits::ChildIteratorType child_iterator;
63
// Writes the edge labels of the node to O and returns true if there are any
64
// edge labels not equal to the empty string "".
65
bool getEdgeSourceLabels(raw_ostream &O, NodeType *Node) {
66
child_iterator EI = GTraits::child_begin(Node);
67
child_iterator EE = GTraits::child_end(Node);
68
bool hasEdgeSourceLabels = false;
70
for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
71
std::string label = DTraits.getEdgeSourceLabel(Node, EI);
76
hasEdgeSourceLabels = true;
81
O << "<s" << i << ">" << DTraits.getEdgeSourceLabel(Node, EI);
84
if (EI != EE && hasEdgeSourceLabels)
85
O << "|<s64>truncated...";
87
return hasEdgeSourceLabels;
91
GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
92
DTraits = DOTTraits(SN);
95
void writeHeader(const std::string &Name) {
96
std::string GraphName = DTraits.getGraphName(G);
99
O << "digraph \"" << DOT::EscapeString(Name) << "\" {\n";
100
else if (!GraphName.empty())
101
O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
103
O << "digraph unnamed {\n";
105
if (DTraits.renderGraphFromBottomUp())
106
O << "\trankdir=\"BT\";\n";
109
O << "\tlabel=\"" << DOT::EscapeString(Name) << "\";\n";
110
else if (!GraphName.empty())
111
O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
112
O << DTraits.getGraphProperties(G);
117
// Finish off the graph
122
// Loop over the graph, printing it out...
123
for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
125
if (!isNodeHidden(*I))
129
bool isNodeHidden(NodeType &Node) {
130
return isNodeHidden(&Node);
133
bool isNodeHidden(NodeType *const *Node) {
134
return isNodeHidden(*Node);
137
bool isNodeHidden(NodeType *Node) {
138
return DTraits.isNodeHidden(Node);
141
void writeNode(NodeType& Node) {
145
void writeNode(NodeType *const *Node) {
149
void writeNode(NodeType *Node) {
150
std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
152
O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
153
if (!NodeAttributes.empty()) O << NodeAttributes << ",";
156
if (!DTraits.renderGraphFromBottomUp()) {
157
O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
159
// If we should include the address of the node in the label, do so now.
160
if (DTraits.hasNodeAddressLabel(Node, G))
161
O << "|" << (void*)Node;
164
std::string edgeSourceLabels;
165
raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
166
bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
168
if (hasEdgeSourceLabels) {
169
if (!DTraits.renderGraphFromBottomUp()) O << "|";
171
O << "{" << EdgeSourceLabels.str() << "}";
173
if (DTraits.renderGraphFromBottomUp()) O << "|";
176
if (DTraits.renderGraphFromBottomUp()) {
177
O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
179
// If we should include the address of the node in the label, do so now.
180
if (DTraits.hasNodeAddressLabel(Node, G))
181
O << "|" << (void*)Node;
184
if (DTraits.hasEdgeDestLabels()) {
187
unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
188
for (; i != e && i != 64; ++i) {
190
O << "<d" << i << ">"
191
<< DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
195
O << "|<d64>truncated...";
199
O << "}\"];\n"; // Finish printing the "node" line
201
// Output all of the edges now
202
child_iterator EI = GTraits::child_begin(Node);
203
child_iterator EE = GTraits::child_end(Node);
204
for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
205
if (!DTraits.isNodeHidden(*EI))
206
writeEdge(Node, i, EI);
207
for (; EI != EE; ++EI)
208
if (!DTraits.isNodeHidden(*EI))
209
writeEdge(Node, 64, EI);
212
void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) {
213
if (NodeType *TargetNode = *EI) {
215
if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
216
child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
218
// Figure out which edge this targets...
220
(unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
221
DestPort = static_cast<int>(Offset);
224
if (DTraits.getEdgeSourceLabel(Node, EI) == "")
227
emitEdge(static_cast<const void*>(Node), edgeidx,
228
static_cast<const void*>(TargetNode), DestPort,
229
DTraits.getEdgeAttributes(Node, EI));
233
/// emitSimpleNode - Outputs a simple (non-record) node
234
void emitSimpleNode(const void *ID, const std::string &Attr,
235
const std::string &Label, unsigned NumEdgeSources = 0,
236
const std::vector<std::string> *EdgeSourceLabels = 0) {
237
O << "\tNode" << ID << "[ ";
241
if (NumEdgeSources) O << "{";
242
O << DOT::EscapeString(Label);
243
if (NumEdgeSources) {
246
for (unsigned i = 0; i != NumEdgeSources; ++i) {
248
O << "<s" << i << ">";
249
if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
256
/// emitEdge - Output an edge from a simple node into the graph...
257
void emitEdge(const void *SrcNodeID, int SrcNodePort,
258
const void *DestNodeID, int DestNodePort,
259
const std::string &Attrs) {
260
if (SrcNodePort > 64) return; // Eminating from truncated part?
261
if (DestNodePort > 64) DestNodePort = 64; // Targetting the truncated part?
263
O << "\tNode" << SrcNodeID;
264
if (SrcNodePort >= 0)
265
O << ":s" << SrcNodePort;
266
O << " -> Node" << DestNodeID;
267
if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
268
O << ":d" << DestNodePort;
271
O << "[" << Attrs << "]";
275
/// getOStream - Get the raw output stream into the graph file. Useful to
276
/// write fancy things using addCustomGraphFeatures().
277
raw_ostream &getOStream() {
282
template<typename GraphType>
283
raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
284
bool ShortNames = false,
285
const std::string &Name = "",
286
const std::string &Title = "") {
287
// Start the graph emission process...
288
GraphWriter<GraphType> W(O, G, ShortNames);
290
// Output the header for the graph...
291
W.writeHeader(Title);
293
// Emit all of the nodes in the graph...
296
// Output any customizations on the graph
297
DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, W);
299
// Output the end of the graph
304
template<typename GraphType>
305
sys::Path WriteGraph(const GraphType &G, const std::string &Name,
306
bool ShortNames = false, const std::string &Title = "") {
308
sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
309
if (Filename.isEmpty()) {
310
errs() << "Error: " << ErrMsg << "\n";
313
Filename.appendComponent(Name + ".dot");
314
if (Filename.makeUnique(true,&ErrMsg)) {
315
errs() << "Error: " << ErrMsg << "\n";
319
errs() << "Writing '" << Filename.str() << "'... ";
321
std::string ErrorInfo;
322
raw_fd_ostream O(Filename.c_str(), ErrorInfo);
324
if (ErrorInfo.empty()) {
325
llvm::WriteGraph(O, G, ShortNames, Name, Title);
326
errs() << " done. \n";
328
errs() << "error opening file '" << Filename.str() << "' for writing!\n";
335
/// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
336
/// then cleanup. For use from the debugger.
338
template<typename GraphType>
339
void ViewGraph(const GraphType &G, const std::string &Name,
340
bool ShortNames = false, const std::string &Title = "",
341
GraphProgram::Name Program = GraphProgram::DOT) {
342
sys::Path Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
344
if (Filename.isEmpty())
347
DisplayGraph(Filename, true, Program);
350
} // End llvm namespace