LLVM  3.7.0
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"
27 #include "llvm/ADT/Twine.h"
30 #include <vector>
31 
32 namespace llvm {
33 
34 namespace DOT { // Private functions...
35  std::string EscapeString(const std::string &Label);
36 
37  /// \brief Get a color string for this node number. Simply round-robin selects
38  /// from a reasonable number of colors.
39  StringRef getColorString(unsigned NodeNumber);
40 }
41 
42 namespace GraphProgram {
43  enum Name {
44  DOT,
45  FDP,
49  };
50 }
51 
52 bool DisplayGraph(StringRef Filename, bool wait = true,
54 
55 template<typename GraphType>
56 class GraphWriter {
57  raw_ostream &O;
58  const GraphType &G;
59 
60  typedef DOTGraphTraits<GraphType> DOTTraits;
61  typedef GraphTraits<GraphType> GTraits;
62  typedef typename GTraits::NodeType NodeType;
63  typedef typename GTraits::nodes_iterator node_iterator;
64  typedef typename GTraits::ChildIteratorType child_iterator;
65  DOTTraits DTraits;
66 
67  // Writes the edge labels of the node to O and returns true if there are any
68  // edge labels not equal to the empty string "".
69  bool getEdgeSourceLabels(raw_ostream &O, NodeType *Node) {
70  child_iterator EI = GTraits::child_begin(Node);
71  child_iterator EE = GTraits::child_end(Node);
72  bool hasEdgeSourceLabels = false;
73 
74  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
75  std::string label = DTraits.getEdgeSourceLabel(Node, EI);
76 
77  if (label.empty())
78  continue;
79 
80  hasEdgeSourceLabels = true;
81 
82  if (i)
83  O << "|";
84 
85  O << "<s" << i << ">" << DOT::EscapeString(label);
86  }
87 
88  if (EI != EE && hasEdgeSourceLabels)
89  O << "|<s64>truncated...";
90 
91  return hasEdgeSourceLabels;
92  }
93 
94 public:
95  GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
96  DTraits = DOTTraits(SN);
97  }
98 
99  void writeGraph(const std::string &Title = "") {
100  // Output the header for the graph...
101  writeHeader(Title);
102 
103  // Emit all of the nodes in the graph...
104  writeNodes();
105 
106  // Output any customizations on the graph
108 
109  // Output the end of the graph
110  writeFooter();
111  }
112 
113  void writeHeader(const std::string &Title) {
114  std::string GraphName = DTraits.getGraphName(G);
115 
116  if (!Title.empty())
117  O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
118  else if (!GraphName.empty())
119  O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
120  else
121  O << "digraph unnamed {\n";
122 
123  if (DTraits.renderGraphFromBottomUp())
124  O << "\trankdir=\"BT\";\n";
125 
126  if (!Title.empty())
127  O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
128  else if (!GraphName.empty())
129  O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
130  O << DTraits.getGraphProperties(G);
131  O << "\n";
132  }
133 
134  void writeFooter() {
135  // Finish off the graph
136  O << "}\n";
137  }
138 
139  void writeNodes() {
140  // Loop over the graph, printing it out...
141  for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
142  I != E; ++I)
143  if (!isNodeHidden(*I))
144  writeNode(*I);
145  }
146 
147  bool isNodeHidden(NodeType &Node) {
148  return isNodeHidden(&Node);
149  }
150 
151  bool isNodeHidden(NodeType *const *Node) {
152  return isNodeHidden(*Node);
153  }
154 
155  bool isNodeHidden(NodeType *Node) {
156  return DTraits.isNodeHidden(Node);
157  }
158 
159  void writeNode(NodeType& Node) {
160  writeNode(&Node);
161  }
162 
163  void writeNode(NodeType *const *Node) {
164  writeNode(*Node);
165  }
166 
167  void writeNode(NodeType *Node) {
168  std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
169 
170  O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
171  if (!NodeAttributes.empty()) O << NodeAttributes << ",";
172  O << "label=\"{";
173 
174  if (!DTraits.renderGraphFromBottomUp()) {
175  O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
176 
177  // If we should include the address of the node in the label, do so now.
178  if (DTraits.hasNodeAddressLabel(Node, G))
179  O << "|" << static_cast<const void*>(Node);
180 
181  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
182  if (!NodeDesc.empty())
183  O << "|" << DOT::EscapeString(NodeDesc);
184  }
185 
186  std::string edgeSourceLabels;
187  raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
188  bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
189 
190  if (hasEdgeSourceLabels) {
191  if (!DTraits.renderGraphFromBottomUp()) O << "|";
192 
193  O << "{" << EdgeSourceLabels.str() << "}";
194 
195  if (DTraits.renderGraphFromBottomUp()) O << "|";
196  }
197 
198  if (DTraits.renderGraphFromBottomUp()) {
199  O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
200 
201  // If we should include the address of the node in the label, do so now.
202  if (DTraits.hasNodeAddressLabel(Node, G))
203  O << "|" << static_cast<const void*>(Node);
204 
205  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
206  if (!NodeDesc.empty())
207  O << "|" << DOT::EscapeString(NodeDesc);
208  }
209 
210  if (DTraits.hasEdgeDestLabels()) {
211  O << "|{";
212 
213  unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
214  for (; i != e && i != 64; ++i) {
215  if (i) O << "|";
216  O << "<d" << i << ">"
217  << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
218  }
219 
220  if (i != e)
221  O << "|<d64>truncated...";
222  O << "}";
223  }
224 
225  O << "}\"];\n"; // Finish printing the "node" line
226 
227  // Output all of the edges now
228  child_iterator EI = GTraits::child_begin(Node);
229  child_iterator EE = GTraits::child_end(Node);
230  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
231  if (!DTraits.isNodeHidden(*EI))
232  writeEdge(Node, i, EI);
233  for (; EI != EE; ++EI)
234  if (!DTraits.isNodeHidden(*EI))
235  writeEdge(Node, 64, EI);
236  }
237 
238  void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) {
239  if (NodeType *TargetNode = *EI) {
240  int DestPort = -1;
241  if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
242  child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
243 
244  // Figure out which edge this targets...
245  unsigned Offset =
246  (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
247  DestPort = static_cast<int>(Offset);
248  }
249 
250  if (DTraits.getEdgeSourceLabel(Node, EI).empty())
251  edgeidx = -1;
252 
253  emitEdge(static_cast<const void*>(Node), edgeidx,
254  static_cast<const void*>(TargetNode), DestPort,
255  DTraits.getEdgeAttributes(Node, EI, G));
256  }
257  }
258 
259  /// emitSimpleNode - Outputs a simple (non-record) node
260  void emitSimpleNode(const void *ID, const std::string &Attr,
261  const std::string &Label, unsigned NumEdgeSources = 0,
262  const std::vector<std::string> *EdgeSourceLabels = nullptr) {
263  O << "\tNode" << ID << "[ ";
264  if (!Attr.empty())
265  O << Attr << ",";
266  O << " label =\"";
267  if (NumEdgeSources) O << "{";
268  O << DOT::EscapeString(Label);
269  if (NumEdgeSources) {
270  O << "|{";
271 
272  for (unsigned i = 0; i != NumEdgeSources; ++i) {
273  if (i) O << "|";
274  O << "<s" << i << ">";
275  if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
276  }
277  O << "}}";
278  }
279  O << "\"];\n";
280  }
281 
282  /// emitEdge - Output an edge from a simple node into the graph...
283  void emitEdge(const void *SrcNodeID, int SrcNodePort,
284  const void *DestNodeID, int DestNodePort,
285  const std::string &Attrs) {
286  if (SrcNodePort > 64) return; // Eminating from truncated part?
287  if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part?
288 
289  O << "\tNode" << SrcNodeID;
290  if (SrcNodePort >= 0)
291  O << ":s" << SrcNodePort;
292  O << " -> Node" << DestNodeID;
293  if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
294  O << ":d" << DestNodePort;
295 
296  if (!Attrs.empty())
297  O << "[" << Attrs << "]";
298  O << ";\n";
299  }
300 
301  /// getOStream - Get the raw output stream into the graph file. Useful to
302  /// write fancy things using addCustomGraphFeatures().
304  return O;
305  }
306 };
307 
308 template<typename GraphType>
309 raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
310  bool ShortNames = false,
311  const Twine &Title = "") {
312  // Start the graph emission process...
313  GraphWriter<GraphType> W(O, G, ShortNames);
314 
315  // Emit the graph.
316  W.writeGraph(Title.str());
317 
318  return O;
319 }
320 
321 std::string createGraphFilename(const Twine &Name, int &FD);
322 
323 template <typename GraphType>
324 std::string WriteGraph(const GraphType &G, const Twine &Name,
325  bool ShortNames = false, const Twine &Title = "") {
326  int FD;
327  // Windows can't always handle long paths, so limit the length of the name.
328  std::string N = Name.str();
329  N = N.substr(0, std::min<std::size_t>(N.size(), 140));
330  std::string Filename = createGraphFilename(N, FD);
331  raw_fd_ostream O(FD, /*shouldClose=*/ true);
332 
333  if (FD == -1) {
334  errs() << "error opening file '" << Filename << "' for writing!\n";
335  return "";
336  }
337 
338  llvm::WriteGraph(O, G, ShortNames, Title);
339  errs() << " done. \n";
340 
341  return Filename;
342 }
343 
344 /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
345 /// then cleanup. For use from the debugger.
346 ///
347 template<typename GraphType>
348 void ViewGraph(const GraphType &G, const Twine &Name,
349  bool ShortNames = false, const Twine &Title = "",
351  std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
352 
353  if (Filename.empty())
354  return;
355 
356  DisplayGraph(Filename, false, Program);
357 }
358 
359 } // End llvm namespace
360 
361 #endif
static std::string getNodeDescription(const void *, const GraphType &)
static EdgeIter getEdgeTarget(const void *, EdgeIter I)
getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is called to determine which outgo...
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool isNodeHidden(NodeType *const *Node)
Definition: GraphWriter.h:151
static void addCustomGraphFeatures(const GraphType &, GraphWriter &)
addCustomGraphFeatures - If a graph is made up of more than just straight-forward nodes and edges...
void writeNode(NodeType &Node)
Definition: GraphWriter.h:159
void emitSimpleNode(const void *ID, const std::string &Attr, const std::string &Label, unsigned NumEdgeSources=0, const std::vector< std::string > *EdgeSourceLabels=nullptr)
emitSimpleNode - Outputs a simple (non-record) node
Definition: GraphWriter.h:260
void writeNode(NodeType *Node)
Definition: GraphWriter.h:167
static std::string getEdgeAttributes(const void *, EdgeIter, const GraphType &)
If you want to override the dot attributes printed for a particular edge, override this method...
raw_ostream & getOStream()
getOStream - Get the raw output stream into the graph file.
Definition: GraphWriter.h:303
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:16
static std::string getEdgeSourceLabel(const void *, EdgeIter)
getEdgeSourceLabel - If you want to label the edge source itself, implement this method.
static bool hasEdgeDestLabels()
hasEdgeDestLabels - If this function returns true, the graph is able to provide labels for edge desti...
static unsigned numEdgeDestLabels(const void *)
numEdgeDestLabels - If hasEdgeDestLabels, this function returns the number of incoming edge labels th...
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:79
static bool edgeTargetsEdgeSource(const void *, EdgeIter)
edgeTargetsEdgeSource - This method returns true if this outgoing edge should actually target another...
bool isNodeHidden(NodeType &Node)
Definition: GraphWriter.h:147
GraphWriter(raw_ostream &o, const GraphType &g, bool SN)
Definition: GraphWriter.h:95
#define G(x, y, z)
Definition: MD5.cpp:52
std::string getNodeLabel(const void *, const GraphType &)
getNodeLabel - Given a node and a pointer to the top level graph, return the label to print in the no...
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
Definition: GraphWriter.h:309
void writeNode(NodeType *const *Node)
Definition: GraphWriter.h:163
std::string EscapeString(const std::string &Label)
Definition: GraphWriter.cpp:24
void ViewGraph(const GraphType &G, const Twine &Name, bool ShortNames=false, const Twine &Title="", GraphProgram::Name Program=GraphProgram::DOT)
ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, then cleanup.
Definition: GraphWriter.h:348
std::string & str()
Flushes the stream contents to the target string and returns the string's reference.
Definition: raw_ostream.h:480
GraphType::UnknownGraphTypeError NodeType
Definition: GraphTraits.h:60
std::string createGraphFilename(const Twine &Name, int &FD)
Definition: GraphWriter.cpp:67
static std::string getEdgeDestLabel(const void *, unsigned)
getEdgeDestLabel - If hasEdgeDestLabels, this function returns the incoming edge label with the given...
static std::string getGraphProperties(const GraphType &)
getGraphProperties - Return any custom properties that should be included in the top level graph stru...
void writeHeader(const std::string &Title)
Definition: GraphWriter.h:113
StringRef getColorString(unsigned NodeNumber)
Get a color string for this node number.
Definition: GraphWriter.cpp:58
static std::string getNodeAttributes(const void *, const GraphType &)
If you want to specify custom node attributes, this is the place to do so.
static bool isNodeHidden(const void *)
isNodeHidden - If the function returns true, the given node is not displayed in the graph...
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:345
bool DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)
#define I(x, y, z)
Definition: MD5.cpp:54
#define N
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:465
static bool hasNodeAddressLabel(const void *, const GraphType &)
hasNodeAddressLabel - If this method returns true, the address of the node is added to the label of t...
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:38
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:40
void writeGraph(const std::string &Title="")
Definition: GraphWriter.h:99
void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI)
Definition: GraphWriter.h:238
static bool renderGraphFromBottomUp()
renderGraphFromBottomUp - If this function returns true, the graph is emitted bottom-up instead of to...
static std::string getGraphName(const GraphType &)
getGraphName - Return the label for the graph as a whole.
bool isNodeHidden(NodeType *Node)
Definition: GraphWriter.h:155
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:283