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