xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Support/GraphWriter.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- llvm/Support/GraphWriter.h - Write graph to a .dot file --*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines a simple interface that can be used to print out generic
100b57cec5SDimitry Andric // LLVM graphs to ".dot" files.  "dot" is a tool that is part of the AT&T
110b57cec5SDimitry Andric // graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
120b57cec5SDimitry Andric // be used to turn the files output by this interface into a variety of
130b57cec5SDimitry Andric // different graphics formats.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric // Graphs do not need to implement any interface past what is already required
160b57cec5SDimitry Andric // by the GraphTraits template, but they can choose to implement specializations
170b57cec5SDimitry Andric // of the DOTGraphTraits template if they want to customize the graphs output in
180b57cec5SDimitry Andric // any way.
190b57cec5SDimitry Andric //
200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_GRAPHWRITER_H
230b57cec5SDimitry Andric #define LLVM_SUPPORT_GRAPHWRITER_H
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #include "llvm/ADT/GraphTraits.h"
260b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
270b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
280b57cec5SDimitry Andric #include "llvm/Support/DOTGraphTraits.h"
290b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
300b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric #include <iterator>
320b57cec5SDimitry Andric #include <string>
330b57cec5SDimitry Andric #include <type_traits>
340b57cec5SDimitry Andric #include <vector>
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric namespace llvm {
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric namespace DOT {  // Private functions...
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric std::string EscapeString(const std::string &Label);
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric /// Get a color string for this node number. Simply round-robin selects
430b57cec5SDimitry Andric /// from a reasonable number of colors.
440b57cec5SDimitry Andric StringRef getColorString(unsigned NodeNumber);
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric } // end namespace DOT
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric namespace GraphProgram {
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric enum Name {
510b57cec5SDimitry Andric   DOT,
520b57cec5SDimitry Andric   FDP,
530b57cec5SDimitry Andric   NEATO,
540b57cec5SDimitry Andric   TWOPI,
550b57cec5SDimitry Andric   CIRCO
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric } // end namespace GraphProgram
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric bool DisplayGraph(StringRef Filename, bool wait = true,
610b57cec5SDimitry Andric                   GraphProgram::Name program = GraphProgram::DOT);
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric template<typename GraphType>
640b57cec5SDimitry Andric class GraphWriter {
650b57cec5SDimitry Andric   raw_ostream &O;
660b57cec5SDimitry Andric   const GraphType &G;
67349cc55cSDimitry Andric   bool RenderUsingHTML = false;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   using DOTTraits = DOTGraphTraits<GraphType>;
700b57cec5SDimitry Andric   using GTraits = GraphTraits<GraphType>;
710b57cec5SDimitry Andric   using NodeRef = typename GTraits::NodeRef;
720b57cec5SDimitry Andric   using node_iterator = typename GTraits::nodes_iterator;
730b57cec5SDimitry Andric   using child_iterator = typename GTraits::ChildIteratorType;
740b57cec5SDimitry Andric   DOTTraits DTraits;
750b57cec5SDimitry Andric 
7606c3fb27SDimitry Andric   static_assert(std::is_pointer_v<NodeRef>,
770b57cec5SDimitry Andric                 "FIXME: Currently GraphWriter requires the NodeRef type to be "
780b57cec5SDimitry Andric                 "a pointer.\nThe pointer usage should be moved to "
790b57cec5SDimitry Andric                 "DOTGraphTraits, and removed from GraphWriter itself.");
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   // Writes the edge labels of the node to O and returns true if there are any
820b57cec5SDimitry Andric   // edge labels not equal to the empty string "".
830b57cec5SDimitry Andric   bool getEdgeSourceLabels(raw_ostream &O, NodeRef Node) {
840b57cec5SDimitry Andric     child_iterator EI = GTraits::child_begin(Node);
850b57cec5SDimitry Andric     child_iterator EE = GTraits::child_end(Node);
860b57cec5SDimitry Andric     bool hasEdgeSourceLabels = false;
870b57cec5SDimitry Andric 
88349cc55cSDimitry Andric     if (RenderUsingHTML)
89349cc55cSDimitry Andric       O << "</tr><tr>";
90349cc55cSDimitry Andric 
910b57cec5SDimitry Andric     for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
920b57cec5SDimitry Andric       std::string label = DTraits.getEdgeSourceLabel(Node, EI);
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric       if (label.empty())
950b57cec5SDimitry Andric         continue;
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric       hasEdgeSourceLabels = true;
980b57cec5SDimitry Andric 
99349cc55cSDimitry Andric       if (RenderUsingHTML)
100349cc55cSDimitry Andric         O << "<td colspan=\"1\" port=\"s" << i << "\">" << label << "</td>";
101349cc55cSDimitry Andric       else {
1020b57cec5SDimitry Andric         if (i)
1030b57cec5SDimitry Andric           O << "|";
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric         O << "<s" << i << ">" << DOT::EscapeString(label);
1060b57cec5SDimitry Andric       }
107349cc55cSDimitry Andric     }
1080b57cec5SDimitry Andric 
109349cc55cSDimitry Andric     if (EI != EE && hasEdgeSourceLabels) {
110349cc55cSDimitry Andric       if (RenderUsingHTML)
111349cc55cSDimitry Andric         O << "<td colspan=\"1\" port=\"s64\">truncated...</td>";
112349cc55cSDimitry Andric       else
1130b57cec5SDimitry Andric         O << "|<s64>truncated...";
114349cc55cSDimitry Andric     }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric     return hasEdgeSourceLabels;
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric public:
1200b57cec5SDimitry Andric   GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
1210b57cec5SDimitry Andric     DTraits = DOTTraits(SN);
122349cc55cSDimitry Andric     RenderUsingHTML = DTraits.renderNodesUsingHTML();
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   void writeGraph(const std::string &Title = "") {
1260b57cec5SDimitry Andric     // Output the header for the graph...
1270b57cec5SDimitry Andric     writeHeader(Title);
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric     // Emit all of the nodes in the graph...
1300b57cec5SDimitry Andric     writeNodes();
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric     // Output any customizations on the graph
1330b57cec5SDimitry Andric     DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, *this);
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric     // Output the end of the graph
1360b57cec5SDimitry Andric     writeFooter();
1370b57cec5SDimitry Andric   }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   void writeHeader(const std::string &Title) {
1405ffd83dbSDimitry Andric     std::string GraphName(DTraits.getGraphName(G));
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     if (!Title.empty())
1430b57cec5SDimitry Andric       O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
1440b57cec5SDimitry Andric     else if (!GraphName.empty())
1450b57cec5SDimitry Andric       O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
1460b57cec5SDimitry Andric     else
1470b57cec5SDimitry Andric       O << "digraph unnamed {\n";
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric     if (DTraits.renderGraphFromBottomUp())
1500b57cec5SDimitry Andric       O << "\trankdir=\"BT\";\n";
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     if (!Title.empty())
1530b57cec5SDimitry Andric       O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
1540b57cec5SDimitry Andric     else if (!GraphName.empty())
1550b57cec5SDimitry Andric       O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
1560b57cec5SDimitry Andric     O << DTraits.getGraphProperties(G);
1570b57cec5SDimitry Andric     O << "\n";
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   void writeFooter() {
1610b57cec5SDimitry Andric     // Finish off the graph
1620b57cec5SDimitry Andric     O << "}\n";
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   void writeNodes() {
1660b57cec5SDimitry Andric     // Loop over the graph, printing it out...
1670b57cec5SDimitry Andric     for (const auto Node : nodes<GraphType>(G))
1680b57cec5SDimitry Andric       if (!isNodeHidden(Node))
1690b57cec5SDimitry Andric         writeNode(Node);
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
172e8d8bef9SDimitry Andric   bool isNodeHidden(NodeRef Node) { return DTraits.isNodeHidden(Node, G); }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   void writeNode(NodeRef Node) {
1750b57cec5SDimitry Andric     std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
1760b57cec5SDimitry Andric 
177349cc55cSDimitry Andric     O << "\tNode" << static_cast<const void *>(Node) << " [shape=";
178349cc55cSDimitry Andric     if (RenderUsingHTML)
179349cc55cSDimitry Andric       O << "none,";
180349cc55cSDimitry Andric     else
181349cc55cSDimitry Andric       O << "record,";
182349cc55cSDimitry Andric 
1830b57cec5SDimitry Andric     if (!NodeAttributes.empty()) O << NodeAttributes << ",";
184349cc55cSDimitry Andric     O << "label=";
185349cc55cSDimitry Andric 
186349cc55cSDimitry Andric     if (RenderUsingHTML) {
187349cc55cSDimitry Andric       // Count the numbewr of edges out of the node to determine how
188349cc55cSDimitry Andric       // many columns to span (max 64)
189349cc55cSDimitry Andric       unsigned ColSpan = 0;
190349cc55cSDimitry Andric       child_iterator EI = GTraits::child_begin(Node);
191349cc55cSDimitry Andric       child_iterator EE = GTraits::child_end(Node);
192349cc55cSDimitry Andric       for (; EI != EE && ColSpan != 64; ++EI, ++ColSpan)
193349cc55cSDimitry Andric         ;
194349cc55cSDimitry Andric       if (ColSpan == 0)
195349cc55cSDimitry Andric         ColSpan = 1;
196349cc55cSDimitry Andric       // Include truncated messages when counting.
197349cc55cSDimitry Andric       if (EI != EE)
198349cc55cSDimitry Andric         ++ColSpan;
199349cc55cSDimitry Andric       O << "<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
200349cc55cSDimitry Andric         << " cellpadding=\"0\"><tr><td align=\"text\" colspan=\"" << ColSpan
201349cc55cSDimitry Andric         << "\">";
202349cc55cSDimitry Andric     } else
203349cc55cSDimitry Andric       O << "\"{";
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric     if (!DTraits.renderGraphFromBottomUp()) {
206349cc55cSDimitry Andric       if (RenderUsingHTML)
207349cc55cSDimitry Andric         O << DTraits.getNodeLabel(Node, G) << "</td>";
208349cc55cSDimitry Andric       else
2090b57cec5SDimitry Andric         O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric       // If we should include the address of the node in the label, do so now.
2120b57cec5SDimitry Andric       std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
2130b57cec5SDimitry Andric       if (!Id.empty())
2140b57cec5SDimitry Andric         O << "|" << DOT::EscapeString(Id);
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric       std::string NodeDesc = DTraits.getNodeDescription(Node, G);
2170b57cec5SDimitry Andric       if (!NodeDesc.empty())
2180b57cec5SDimitry Andric         O << "|" << DOT::EscapeString(NodeDesc);
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric     std::string edgeSourceLabels;
2220b57cec5SDimitry Andric     raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
2230b57cec5SDimitry Andric     bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric     if (hasEdgeSourceLabels) {
226349cc55cSDimitry Andric       if (!DTraits.renderGraphFromBottomUp())
227349cc55cSDimitry Andric         if (!RenderUsingHTML)
228349cc55cSDimitry Andric           O << "|";
2290b57cec5SDimitry Andric 
230349cc55cSDimitry Andric       if (RenderUsingHTML)
231*0fca6ea1SDimitry Andric         O << edgeSourceLabels;
232349cc55cSDimitry Andric       else
233*0fca6ea1SDimitry Andric         O << "{" << edgeSourceLabels << "}";
2340b57cec5SDimitry Andric 
235349cc55cSDimitry Andric       if (DTraits.renderGraphFromBottomUp())
236349cc55cSDimitry Andric         if (!RenderUsingHTML)
237349cc55cSDimitry Andric           O << "|";
2380b57cec5SDimitry Andric     }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric     if (DTraits.renderGraphFromBottomUp()) {
241349cc55cSDimitry Andric       if (RenderUsingHTML)
242349cc55cSDimitry Andric         O << DTraits.getNodeLabel(Node, G);
243349cc55cSDimitry Andric       else
2440b57cec5SDimitry Andric         O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric       // If we should include the address of the node in the label, do so now.
2470b57cec5SDimitry Andric       std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
2480b57cec5SDimitry Andric       if (!Id.empty())
2490b57cec5SDimitry Andric         O << "|" << DOT::EscapeString(Id);
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric       std::string NodeDesc = DTraits.getNodeDescription(Node, G);
2520b57cec5SDimitry Andric       if (!NodeDesc.empty())
2530b57cec5SDimitry Andric         O << "|" << DOT::EscapeString(NodeDesc);
2540b57cec5SDimitry Andric     }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric     if (DTraits.hasEdgeDestLabels()) {
2570b57cec5SDimitry Andric       O << "|{";
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric       unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
2600b57cec5SDimitry Andric       for (; i != e && i != 64; ++i) {
2610b57cec5SDimitry Andric         if (i) O << "|";
2620b57cec5SDimitry Andric         O << "<d" << i << ">"
2630b57cec5SDimitry Andric           << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
2640b57cec5SDimitry Andric       }
2650b57cec5SDimitry Andric 
2660eae32dcSDimitry Andric       if (i != e)
2670eae32dcSDimitry Andric         O << "|<d64>truncated...";
2680eae32dcSDimitry Andric       O << "}";
2690b57cec5SDimitry Andric     }
2700b57cec5SDimitry Andric 
271349cc55cSDimitry Andric     if (RenderUsingHTML)
272349cc55cSDimitry Andric       O << "</tr></table>>";
273349cc55cSDimitry Andric     else
274349cc55cSDimitry Andric       O << "}\"";
275349cc55cSDimitry Andric     O << "];\n"; // Finish printing the "node" line
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric     // Output all of the edges now
2780b57cec5SDimitry Andric     child_iterator EI = GTraits::child_begin(Node);
2790b57cec5SDimitry Andric     child_iterator EE = GTraits::child_end(Node);
2800b57cec5SDimitry Andric     for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
281e8d8bef9SDimitry Andric       if (!DTraits.isNodeHidden(*EI, G))
2820b57cec5SDimitry Andric         writeEdge(Node, i, EI);
2830b57cec5SDimitry Andric     for (; EI != EE; ++EI)
284e8d8bef9SDimitry Andric       if (!DTraits.isNodeHidden(*EI, G))
2850b57cec5SDimitry Andric         writeEdge(Node, 64, EI);
2860b57cec5SDimitry Andric   }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI) {
2890b57cec5SDimitry Andric     if (NodeRef TargetNode = *EI) {
2900b57cec5SDimitry Andric       int DestPort = -1;
2910b57cec5SDimitry Andric       if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
2920b57cec5SDimitry Andric         child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric         // Figure out which edge this targets...
2950b57cec5SDimitry Andric         unsigned Offset =
2960b57cec5SDimitry Andric           (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
2970b57cec5SDimitry Andric         DestPort = static_cast<int>(Offset);
2980b57cec5SDimitry Andric       }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric       if (DTraits.getEdgeSourceLabel(Node, EI).empty())
3010b57cec5SDimitry Andric         edgeidx = -1;
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric       emitEdge(static_cast<const void*>(Node), edgeidx,
3040b57cec5SDimitry Andric                static_cast<const void*>(TargetNode), DestPort,
3050b57cec5SDimitry Andric                DTraits.getEdgeAttributes(Node, EI, G));
3060b57cec5SDimitry Andric     }
3070b57cec5SDimitry Andric   }
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   /// emitSimpleNode - Outputs a simple (non-record) node
3100b57cec5SDimitry Andric   void emitSimpleNode(const void *ID, const std::string &Attr,
3110b57cec5SDimitry Andric                    const std::string &Label, unsigned NumEdgeSources = 0,
3120b57cec5SDimitry Andric                    const std::vector<std::string> *EdgeSourceLabels = nullptr) {
3130b57cec5SDimitry Andric     O << "\tNode" << ID << "[ ";
3140b57cec5SDimitry Andric     if (!Attr.empty())
3150b57cec5SDimitry Andric       O << Attr << ",";
3160b57cec5SDimitry Andric     O << " label =\"";
3170b57cec5SDimitry Andric     if (NumEdgeSources) O << "{";
3180b57cec5SDimitry Andric     O << DOT::EscapeString(Label);
3190b57cec5SDimitry Andric     if (NumEdgeSources) {
3200b57cec5SDimitry Andric       O << "|{";
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric       for (unsigned i = 0; i != NumEdgeSources; ++i) {
3230b57cec5SDimitry Andric         if (i) O << "|";
3240b57cec5SDimitry Andric         O << "<s" << i << ">";
3250b57cec5SDimitry Andric         if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
3260b57cec5SDimitry Andric       }
3270b57cec5SDimitry Andric       O << "}}";
3280b57cec5SDimitry Andric     }
3290b57cec5SDimitry Andric     O << "\"];\n";
3300b57cec5SDimitry Andric   }
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   /// emitEdge - Output an edge from a simple node into the graph...
3330b57cec5SDimitry Andric   void emitEdge(const void *SrcNodeID, int SrcNodePort,
3340b57cec5SDimitry Andric                 const void *DestNodeID, int DestNodePort,
3350b57cec5SDimitry Andric                 const std::string &Attrs) {
3360b57cec5SDimitry Andric     if (SrcNodePort  > 64) return;             // Eminating from truncated part?
3370b57cec5SDimitry Andric     if (DestNodePort > 64) DestNodePort = 64;  // Targeting the truncated part?
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     O << "\tNode" << SrcNodeID;
3400b57cec5SDimitry Andric     if (SrcNodePort >= 0)
3410b57cec5SDimitry Andric       O << ":s" << SrcNodePort;
3420b57cec5SDimitry Andric     O << " -> Node" << DestNodeID;
3430b57cec5SDimitry Andric     if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
3440b57cec5SDimitry Andric       O << ":d" << DestNodePort;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric     if (!Attrs.empty())
3470b57cec5SDimitry Andric       O << "[" << Attrs << "]";
3480b57cec5SDimitry Andric     O << ";\n";
3490b57cec5SDimitry Andric   }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   /// getOStream - Get the raw output stream into the graph file. Useful to
3520b57cec5SDimitry Andric   /// write fancy things using addCustomGraphFeatures().
3530b57cec5SDimitry Andric   raw_ostream &getOStream() {
3540b57cec5SDimitry Andric     return O;
3550b57cec5SDimitry Andric   }
3560b57cec5SDimitry Andric };
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric template<typename GraphType>
3590b57cec5SDimitry Andric raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
3600b57cec5SDimitry Andric                         bool ShortNames = false,
3610b57cec5SDimitry Andric                         const Twine &Title = "") {
3620b57cec5SDimitry Andric   // Start the graph emission process...
3630b57cec5SDimitry Andric   GraphWriter<GraphType> W(O, G, ShortNames);
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   // Emit the graph.
3660b57cec5SDimitry Andric   W.writeGraph(Title.str());
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   return O;
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric std::string createGraphFilename(const Twine &Name, int &FD);
3720b57cec5SDimitry Andric 
373fe6060f1SDimitry Andric /// Writes graph into a provided @c Filename.
374fe6060f1SDimitry Andric /// If @c Filename is empty, generates a random one.
3750b57cec5SDimitry Andric /// \return The resulting filename, or an empty string if writing
3760b57cec5SDimitry Andric /// failed.
3770b57cec5SDimitry Andric template <typename GraphType>
3780b57cec5SDimitry Andric std::string WriteGraph(const GraphType &G, const Twine &Name,
3790b57cec5SDimitry Andric                        bool ShortNames = false,
3800b57cec5SDimitry Andric                        const Twine &Title = "",
3810b57cec5SDimitry Andric                        std::string Filename = "") {
3820b57cec5SDimitry Andric   int FD;
3830b57cec5SDimitry Andric   if (Filename.empty()) {
3845ffd83dbSDimitry Andric     Filename = createGraphFilename(Name.str(), FD);
3850b57cec5SDimitry Andric   } else {
386fe6060f1SDimitry Andric     std::error_code EC = sys::fs::openFileForWrite(
387fe6060f1SDimitry Andric         Filename, FD, sys::fs::CD_CreateAlways, sys::fs::OF_Text);
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric     // Writing over an existing file is not considered an error.
3900b57cec5SDimitry Andric     if (EC == std::errc::file_exists) {
3910b57cec5SDimitry Andric       errs() << "file exists, overwriting" << "\n";
3920b57cec5SDimitry Andric     } else if (EC) {
3930b57cec5SDimitry Andric       errs() << "error writing into file" << "\n";
3940b57cec5SDimitry Andric       return "";
3955ffd83dbSDimitry Andric     } else {
3965ffd83dbSDimitry Andric       errs() << "writing to the newly created file " << Filename << "\n";
3970b57cec5SDimitry Andric     }
3980b57cec5SDimitry Andric   }
3990b57cec5SDimitry Andric   raw_fd_ostream O(FD, /*shouldClose=*/ true);
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric   if (FD == -1) {
4020b57cec5SDimitry Andric     errs() << "error opening file '" << Filename << "' for writing!\n";
4030b57cec5SDimitry Andric     return "";
4040b57cec5SDimitry Andric   }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   llvm::WriteGraph(O, G, ShortNames, Title);
4070b57cec5SDimitry Andric   errs() << " done. \n";
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   return Filename;
4100b57cec5SDimitry Andric }
4110b57cec5SDimitry Andric 
4125ffd83dbSDimitry Andric /// DumpDotGraph - Just dump a dot graph to the user-provided file name.
4135ffd83dbSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4145ffd83dbSDimitry Andric template <typename GraphType>
4155ffd83dbSDimitry Andric LLVM_DUMP_METHOD void
4165ffd83dbSDimitry Andric dumpDotGraphToFile(const GraphType &G, const Twine &FileName,
4175ffd83dbSDimitry Andric                    const Twine &Title, bool ShortNames = false,
4185ffd83dbSDimitry Andric                    const Twine &Name = "") {
4195ffd83dbSDimitry Andric   llvm::WriteGraph(G, Name, ShortNames, Title, FileName.str());
4205ffd83dbSDimitry Andric }
4215ffd83dbSDimitry Andric #endif
4225ffd83dbSDimitry Andric 
4230b57cec5SDimitry Andric /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
4240b57cec5SDimitry Andric /// then cleanup.  For use from the debugger.
4250b57cec5SDimitry Andric ///
4260b57cec5SDimitry Andric template<typename GraphType>
4270b57cec5SDimitry Andric void ViewGraph(const GraphType &G, const Twine &Name,
4280b57cec5SDimitry Andric                bool ShortNames = false, const Twine &Title = "",
4290b57cec5SDimitry Andric                GraphProgram::Name Program = GraphProgram::DOT) {
4300b57cec5SDimitry Andric   std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric   if (Filename.empty())
4330b57cec5SDimitry Andric     return;
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   DisplayGraph(Filename, false, Program);
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric } // end namespace llvm
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric #endif // LLVM_SUPPORT_GRAPHWRITER_H
441