LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GraphWriter.h
Go to the documentation of this file.
1 //===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
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.
15 //
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
19 // any way.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 #ifndef LLVM_SUPPORT_GRAPHWRITER_H
24 #define LLVM_SUPPORT_GRAPHWRITER_H
25 
26 #include "llvm/ADT/GraphTraits.h"
28 #include "llvm/Support/Path.h"
30 #include <cassert>
31 #include <vector>
32 
33 namespace llvm {
34 
35 namespace DOT { // Private functions...
36  std::string EscapeString(const std::string &Label);
37 
38  /// \brief Get a color string for this node number. Simply round-robin selects
39  /// from a reasonable number of colors.
40  StringRef getColorString(unsigned NodeNumber);
41 }
42 
43 namespace GraphProgram {
44  enum Name {
45  DOT,
46  FDP,
50  };
51 }
52 
53 void DisplayGraph(StringRef Filename, bool wait = true,
55 
56 template<typename GraphType>
57 class GraphWriter {
58  raw_ostream &O;
59  const GraphType &G;
60 
61  typedef DOTGraphTraits<GraphType> DOTTraits;
62  typedef GraphTraits<GraphType> GTraits;
63  typedef typename GTraits::NodeType NodeType;
64  typedef typename GTraits::nodes_iterator node_iterator;
65  typedef typename GTraits::ChildIteratorType child_iterator;
66  DOTTraits DTraits;
67 
68  // Writes the edge labels of the node to O and returns true if there are any
69  // edge labels not equal to the empty string "".
70  bool getEdgeSourceLabels(raw_ostream &O, NodeType *Node) {
71  child_iterator EI = GTraits::child_begin(Node);
72  child_iterator EE = GTraits::child_end(Node);
73  bool hasEdgeSourceLabels = false;
74 
75  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
76  std::string label = DTraits.getEdgeSourceLabel(Node, EI);
77 
78  if (label.empty())
79  continue;
80 
81  hasEdgeSourceLabels = true;
82 
83  if (i)
84  O << "|";
85 
86  O << "<s" << i << ">" << DOT::EscapeString(label);
87  }
88 
89  if (EI != EE && hasEdgeSourceLabels)
90  O << "|<s64>truncated...";
91 
92  return hasEdgeSourceLabels;
93  }
94 
95 public:
96  GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
97  DTraits = DOTTraits(SN);
98  }
99 
100  void writeGraph(const std::string &Title = "") {
101  // Output the header for the graph...
102  writeHeader(Title);
103 
104  // Emit all of the nodes in the graph...
105  writeNodes();
106 
107  // Output any customizations on the graph
109 
110  // Output the end of the graph
111  writeFooter();
112  }
113 
114  void writeHeader(const std::string &Title) {
115  std::string GraphName = DTraits.getGraphName(G);
116 
117  if (!Title.empty())
118  O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
119  else if (!GraphName.empty())
120  O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
121  else
122  O << "digraph unnamed {\n";
123 
124  if (DTraits.renderGraphFromBottomUp())
125  O << "\trankdir=\"BT\";\n";
126 
127  if (!Title.empty())
128  O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
129  else if (!GraphName.empty())
130  O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
131  O << DTraits.getGraphProperties(G);
132  O << "\n";
133  }
134 
135  void writeFooter() {
136  // Finish off the graph
137  O << "}\n";
138  }
139 
140  void writeNodes() {
141  // Loop over the graph, printing it out...
142  for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
143  I != E; ++I)
144  if (!isNodeHidden(*I))
145  writeNode(*I);
146  }
147 
148  bool isNodeHidden(NodeType &Node) {
149  return isNodeHidden(&Node);
150  }
151 
152  bool isNodeHidden(NodeType *const *Node) {
153  return isNodeHidden(*Node);
154  }
155 
156  bool isNodeHidden(NodeType *Node) {
157  return DTraits.isNodeHidden(Node);
158  }
159 
160  void writeNode(NodeType& Node) {
161  writeNode(&Node);
162  }
163 
164  void writeNode(NodeType *const *Node) {
165  writeNode(*Node);
166  }
167 
168  void writeNode(NodeType *Node) {
169  std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
170 
171  O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
172  if (!NodeAttributes.empty()) O << NodeAttributes << ",";
173  O << "label=\"{";
174 
175  if (!DTraits.renderGraphFromBottomUp()) {
176  O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
177 
178  // If we should include the address of the node in the label, do so now.
179  if (DTraits.hasNodeAddressLabel(Node, G))
180  O << "|" << static_cast<const void*>(Node);
181 
182  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
183  if (!NodeDesc.empty())
184  O << "|" << DOT::EscapeString(NodeDesc);
185  }
186 
187  std::string edgeSourceLabels;
188  raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
189  bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
190 
191  if (hasEdgeSourceLabels) {
192  if (!DTraits.renderGraphFromBottomUp()) O << "|";
193 
194  O << "{" << EdgeSourceLabels.str() << "}";
195 
196  if (DTraits.renderGraphFromBottomUp()) O << "|";
197  }
198 
199  if (DTraits.renderGraphFromBottomUp()) {
200  O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
201 
202  // If we should include the address of the node in the label, do so now.
203  if (DTraits.hasNodeAddressLabel(Node, G))
204  O << "|" << static_cast<const void*>(Node);
205 
206  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
207  if (!NodeDesc.empty())
208  O << "|" << DOT::EscapeString(NodeDesc);
209  }
210 
211  if (DTraits.hasEdgeDestLabels()) {
212  O << "|{";
213 
214  unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
215  for (; i != e && i != 64; ++i) {
216  if (i) O << "|";
217  O << "<d" << i << ">"
218  << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
219  }
220 
221  if (i != e)
222  O << "|<d64>truncated...";
223  O << "}";
224  }
225 
226  O << "}\"];\n"; // Finish printing the "node" line
227 
228  // Output all of the edges now
229  child_iterator EI = GTraits::child_begin(Node);
230  child_iterator EE = GTraits::child_end(Node);
231  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
232  if (!DTraits.isNodeHidden(*EI))
233  writeEdge(Node, i, EI);
234  for (; EI != EE; ++EI)
235  if (!DTraits.isNodeHidden(*EI))
236  writeEdge(Node, 64, EI);
237  }
238 
239  void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) {
240  if (NodeType *TargetNode = *EI) {
241  int DestPort = -1;
242  if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
243  child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
244 
245  // Figure out which edge this targets...
246  unsigned Offset =
247  (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
248  DestPort = static_cast<int>(Offset);
249  }
250 
251  if (DTraits.getEdgeSourceLabel(Node, EI).empty())
252  edgeidx = -1;
253 
254  emitEdge(static_cast<const void*>(Node), edgeidx,
255  static_cast<const void*>(TargetNode), DestPort,
256  DTraits.getEdgeAttributes(Node, EI, G));
257  }
258  }
259 
260  /// emitSimpleNode - Outputs a simple (non-record) node
261  void emitSimpleNode(const void *ID, const std::string &Attr,
262  const std::string &Label, unsigned NumEdgeSources = 0,
263  const std::vector<std::string> *EdgeSourceLabels = 0) {
264  O << "\tNode" << ID << "[ ";
265  if (!Attr.empty())
266  O << Attr << ",";
267  O << " label =\"";
268  if (NumEdgeSources) O << "{";
269  O << DOT::EscapeString(Label);
270  if (NumEdgeSources) {
271  O << "|{";
272 
273  for (unsigned i = 0; i != NumEdgeSources; ++i) {
274  if (i) O << "|";
275  O << "<s" << i << ">";
276  if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
277  }
278  O << "}}";
279  }
280  O << "\"];\n";
281  }
282 
283  /// emitEdge - Output an edge from a simple node into the graph...
284  void emitEdge(const void *SrcNodeID, int SrcNodePort,
285  const void *DestNodeID, int DestNodePort,
286  const std::string &Attrs) {
287  if (SrcNodePort > 64) return; // Eminating from truncated part?
288  if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part?
289 
290  O << "\tNode" << SrcNodeID;
291  if (SrcNodePort >= 0)
292  O << ":s" << SrcNodePort;
293  O << " -> Node" << DestNodeID;
294  if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
295  O << ":d" << DestNodePort;
296 
297  if (!Attrs.empty())
298  O << "[" << Attrs << "]";
299  O << ";\n";
300  }
301 
302  /// getOStream - Get the raw output stream into the graph file. Useful to
303  /// write fancy things using addCustomGraphFeatures().
305  return O;
306  }
307 };
308 
309 template<typename GraphType>
310 raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
311  bool ShortNames = false,
312  const Twine &Title = "") {
313  // Start the graph emission process...
314  GraphWriter<GraphType> W(O, G, ShortNames);
315 
316  // Emit the graph.
317  W.writeGraph(Title.str());
318 
319  return O;
320 }
321 
322 std::string createGraphFilename(const Twine &Name, int &FD);
323 
324 template <typename GraphType>
325 std::string WriteGraph(const GraphType &G, const Twine &Name,
326  bool ShortNames = false, const Twine &Title = "") {
327  int FD;
328  std::string Filename = createGraphFilename(Name, FD);
329  raw_fd_ostream O(FD, /*shouldClose=*/ true);
330 
331  if (FD == -1) {
332  errs() << "error opening file '" << Filename << "' for writing!\n";
333  return "";
334  }
335 
336  llvm::WriteGraph(O, G, ShortNames, Title);
337  errs() << " done. \n";
338 
339  return Filename;
340 }
341 
342 /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
343 /// then cleanup. For use from the debugger.
344 ///
345 template<typename GraphType>
346 void ViewGraph(const GraphType &G, const Twine &Name,
347  bool ShortNames = false, const Twine &Title = "",
349  std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
350 
351  if (Filename.empty())
352  return;
353 
354  DisplayGraph(Filename, true, Program);
355 }
356 
357 } // End llvm namespace
358 
359 #endif
static std::string getNodeDescription(const void *, const GraphType &)
static EdgeIter getEdgeTarget(const void *, EdgeIter I)
void emitSimpleNode(const void *ID, const std::string &Attr, const std::string &Label, unsigned NumEdgeSources=0, const std::vector< std::string > *EdgeSourceLabels=0)
emitSimpleNode - Outputs a simple (non-record) node
Definition: GraphWriter.h:261
raw_ostream & errs()
bool isNodeHidden(NodeType *const *Node)
Definition: GraphWriter.h:152
static void addCustomGraphFeatures(const GraphType &, GraphWriter &)
void writeNode(NodeType &Node)
Definition: GraphWriter.h:160
void writeNode(NodeType *Node)
Definition: GraphWriter.h:168
raw_ostream & WriteGraph(raw_ostream &O, const EdgeBundles &G, bool ShortNames=false, const Twine &Title="")
Specialize WriteGraph, the standard implementation won't work.
Definition: EdgeBundles.cpp:78
static std::string getEdgeAttributes(const void *, EdgeIter, const GraphType &)
raw_ostream & getOStream()
Definition: GraphWriter.h:304
static std::string getEdgeSourceLabel(const void *, EdgeIter)
static unsigned numEdgeDestLabels(const void *)
static bool edgeTargetsEdgeSource(const void *, EdgeIter)
bool isNodeHidden(NodeType &Node)
Definition: GraphWriter.h:148
GraphWriter(raw_ostream &o, const GraphType &g, bool SN)
Definition: GraphWriter.h:96
ID
LLVM Calling Convention Representation.
Definition: CallingConv.h:26
#define G(x, y, z)
Definition: MD5.cpp:52
std::string getNodeLabel(const void *, const GraphType &)
void writeNode(NodeType *const *Node)
Definition: GraphWriter.h:164
std::string EscapeString(const std::string &Label)
Definition: GraphWriter.cpp:25
void DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)
void ViewGraph(const GraphType &G, const Twine &Name, bool ShortNames=false, const Twine &Title="", GraphProgram::Name Program=GraphProgram::DOT)
Definition: GraphWriter.h:346
std::string & str()
Definition: raw_ostream.h:441
GraphType::UnknownGraphTypeError NodeType
Definition: GraphTraits.h:60
std::string createGraphFilename(const Twine &Name, int &FD)
Definition: GraphWriter.cpp:68
static std::string getEdgeDestLabel(const void *, unsigned)
static std::string getGraphProperties(const GraphType &)
void writeHeader(const std::string &Title)
Definition: GraphWriter.h:114
StringRef getColorString(unsigned NodeNumber)
Get a color string for this node number. Simply round-robin selects from a reasonable number of color...
Definition: GraphWriter.cpp:59
static std::string getNodeAttributes(const void *, const GraphType &)
static bool isNodeHidden(const void *)
#define I(x, y, z)
Definition: MD5.cpp:54
static bool hasNodeAddressLabel(const void *, const GraphType &)
void writeGraph(const std::string &Title="")
Definition: GraphWriter.h:100
void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI)
Definition: GraphWriter.h:239
static bool renderGraphFromBottomUp()
static std::string getGraphName(const GraphType &)
bool isNodeHidden(NodeType *Node)
Definition: GraphWriter.h:156
void emitEdge(const void *SrcNodeID, int SrcNodePort, const void *DestNodeID, int DestNodePort, const std::string &Attrs)
emitEdge - Output an edge from a simple node into the graph...
Definition: GraphWriter.h:284