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/ADT/GraphTraits.h"
27 #include "llvm/Support/DOTGraphTraits.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/raw_ostream.h"
35 namespace DOT
{ // Private functions...
36 std::string
EscapeString(const std::string
&Label
);
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
);
43 namespace GraphProgram
{
53 bool DisplayGraph(StringRef Filename
, bool wait
= true,
54 GraphProgram::Name program
= GraphProgram::DOT
);
56 template<typename GraphType
>
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
;
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;
75 for (unsigned i
= 0; EI
!= EE
&& i
!= 64; ++EI
, ++i
) {
76 std::string label
= DTraits
.getEdgeSourceLabel(Node
, EI
);
81 hasEdgeSourceLabels
= true;
86 O
<< "<s" << i
<< ">" << DOT::EscapeString(label
);
89 if (EI
!= EE
&& hasEdgeSourceLabels
)
90 O
<< "|<s64>truncated...";
92 return hasEdgeSourceLabels
;
96 GraphWriter(raw_ostream
&o
, const GraphType
&g
, bool SN
) : O(o
), G(g
) {
97 DTraits
= DOTTraits(SN
);
100 void writeGraph(const std::string
&Title
= "") {
101 // Output the header for the graph...
104 // Emit all of the nodes in the graph...
107 // Output any customizations on the graph
108 DOTGraphTraits
<GraphType
>::addCustomGraphFeatures(G
, *this);
110 // Output the end of the graph
114 void writeHeader(const std::string
&Title
) {
115 std::string GraphName
= DTraits
.getGraphName(G
);
118 O
<< "digraph \"" << DOT::EscapeString(Title
) << "\" {\n";
119 else if (!GraphName
.empty())
120 O
<< "digraph \"" << DOT::EscapeString(GraphName
) << "\" {\n";
122 O
<< "digraph unnamed {\n";
124 if (DTraits
.renderGraphFromBottomUp())
125 O
<< "\trankdir=\"BT\";\n";
128 O
<< "\tlabel=\"" << DOT::EscapeString(Title
) << "\";\n";
129 else if (!GraphName
.empty())
130 O
<< "\tlabel=\"" << DOT::EscapeString(GraphName
) << "\";\n";
131 O
<< DTraits
.getGraphProperties(G
);
136 // Finish off the graph
141 // Loop over the graph, printing it out...
142 for (node_iterator I
= GTraits::nodes_begin(G
), E
= GTraits::nodes_end(G
);
144 if (!isNodeHidden(*I
))
148 bool isNodeHidden(NodeType
&Node
) {
149 return isNodeHidden(&Node
);
152 bool isNodeHidden(NodeType
*const *Node
) {
153 return isNodeHidden(*Node
);
156 bool isNodeHidden(NodeType
*Node
) {
157 return DTraits
.isNodeHidden(Node
);
160 void writeNode(NodeType
& Node
) {
164 void writeNode(NodeType
*const *Node
) {
168 void writeNode(NodeType
*Node
) {
169 std::string NodeAttributes
= DTraits
.getNodeAttributes(Node
, G
);
171 O
<< "\tNode" << static_cast<const void*>(Node
) << " [shape=record,";
172 if (!NodeAttributes
.empty()) O
<< NodeAttributes
<< ",";
175 if (!DTraits
.renderGraphFromBottomUp()) {
176 O
<< DOT::EscapeString(DTraits
.getNodeLabel(Node
, G
));
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
);
182 std::string NodeDesc
= DTraits
.getNodeDescription(Node
, G
);
183 if (!NodeDesc
.empty())
184 O
<< "|" << DOT::EscapeString(NodeDesc
);
187 std::string edgeSourceLabels
;
188 raw_string_ostream
EdgeSourceLabels(edgeSourceLabels
);
189 bool hasEdgeSourceLabels
= getEdgeSourceLabels(EdgeSourceLabels
, Node
);
191 if (hasEdgeSourceLabels
) {
192 if (!DTraits
.renderGraphFromBottomUp()) O
<< "|";
194 O
<< "{" << EdgeSourceLabels
.str() << "}";
196 if (DTraits
.renderGraphFromBottomUp()) O
<< "|";
199 if (DTraits
.renderGraphFromBottomUp()) {
200 O
<< DOT::EscapeString(DTraits
.getNodeLabel(Node
, G
));
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
);
206 std::string NodeDesc
= DTraits
.getNodeDescription(Node
, G
);
207 if (!NodeDesc
.empty())
208 O
<< "|" << DOT::EscapeString(NodeDesc
);
211 if (DTraits
.hasEdgeDestLabels()) {
214 unsigned i
= 0, e
= DTraits
.numEdgeDestLabels(Node
);
215 for (; i
!= e
&& i
!= 64; ++i
) {
217 O
<< "<d" << i
<< ">"
218 << DOT::EscapeString(DTraits
.getEdgeDestLabel(Node
, i
));
222 O
<< "|<d64>truncated...";
226 O
<< "}\"];\n"; // Finish printing the "node" line
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
);
239 void writeEdge(NodeType
*Node
, unsigned edgeidx
, child_iterator EI
) {
240 if (NodeType
*TargetNode
= *EI
) {
242 if (DTraits
.edgeTargetsEdgeSource(Node
, EI
)) {
243 child_iterator TargetIt
= DTraits
.getEdgeTarget(Node
, EI
);
245 // Figure out which edge this targets...
247 (unsigned)std::distance(GTraits::child_begin(TargetNode
), TargetIt
);
248 DestPort
= static_cast<int>(Offset
);
251 if (DTraits
.getEdgeSourceLabel(Node
, EI
).empty())
254 emitEdge(static_cast<const void*>(Node
), edgeidx
,
255 static_cast<const void*>(TargetNode
), DestPort
,
256 DTraits
.getEdgeAttributes(Node
, EI
, G
));
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
= nullptr) {
264 O
<< "\tNode" << ID
<< "[ ";
268 if (NumEdgeSources
) O
<< "{";
269 O
<< DOT::EscapeString(Label
);
270 if (NumEdgeSources
) {
273 for (unsigned i
= 0; i
!= NumEdgeSources
; ++i
) {
275 O
<< "<s" << i
<< ">";
276 if (EdgeSourceLabels
) O
<< DOT::EscapeString((*EdgeSourceLabels
)[i
]);
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?
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
;
298 O
<< "[" << Attrs
<< "]";
302 /// getOStream - Get the raw output stream into the graph file. Useful to
303 /// write fancy things using addCustomGraphFeatures().
304 raw_ostream
&getOStream() {
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
);
317 W
.writeGraph(Title
.str());
322 std::string
createGraphFilename(const Twine
&Name
, int &FD
);
324 template <typename GraphType
>
325 std::string
WriteGraph(const GraphType
&G
, const Twine
&Name
,
326 bool ShortNames
= false, const Twine
&Title
= "") {
328 // Windows can't always handle long paths, so limit the length of the name.
329 std::string N
= Name
.str();
330 N
= N
.substr(0, std::min
<std::size_t>(N
.size(), 140));
331 std::string Filename
= createGraphFilename(N
, FD
);
332 raw_fd_ostream
O(FD
, /*shouldClose=*/ true);
335 errs() << "error opening file '" << Filename
<< "' for writing!\n";
339 llvm::WriteGraph(O
, G
, ShortNames
, Title
);
340 errs() << " done. \n";
345 /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
346 /// then cleanup. For use from the debugger.
348 template<typename GraphType
>
349 void ViewGraph(const GraphType
&G
, const Twine
&Name
,
350 bool ShortNames
= false, const Twine
&Title
= "",
351 GraphProgram::Name Program
= GraphProgram::DOT
) {
352 std::string Filename
= llvm::WriteGraph(G
, Name
, ShortNames
, Title
);
354 if (Filename
.empty())
357 DisplayGraph(Filename
, true, Program
);
360 } // End llvm namespace