GraphWriter.h revision b2109ce97881269a610fa4afbcbca350e975174d
1//===-- Support/GraphWriter.h - Write a graph to a .dot file ----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file was developed by the LLVM research group and is distributed under 6// the University of Illinois Open Source 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 SUPPORT_GRAPHWRITER_H 24#define SUPPORT_GRAPHWRITER_H 25 26#include "Support/DOTGraphTraits.h" 27#include "Support/GraphTraits.h" 28#include <vector> 29#include <iostream> 30 31namespace DOT { // Private functions... 32 inline std::string EscapeString(const std::string &Label) { 33 std::string Str(Label); 34 for (unsigned i = 0; i != Str.length(); ++i) 35 switch (Str[i]) { 36 case '\n': 37 Str.insert(Str.begin()+i, '\\'); // Escape character... 38 ++i; 39 Str[i] = 'n'; 40 break; 41 case '\t': 42 Str.insert(Str.begin()+i, ' '); // Convert to two spaces 43 ++i; 44 Str[i] = ' '; 45 break; 46 case '\\': 47 if (i+1 != Str.length() && Str[i+1] == 'l') 48 break; // don't disturb \l 49 case '{': case '}': 50 case '<': case '>': 51 Str.insert(Str.begin()+i, '\\'); // Escape character... 52 ++i; // don't infinite loop 53 break; 54 } 55 return Str; 56 } 57} 58 59template<typename GraphType> 60class GraphWriter { 61 std::ostream &O; 62 const GraphType &G; 63 64 typedef DOTGraphTraits<GraphType> DOTTraits; 65 typedef GraphTraits<GraphType> GTraits; 66 typedef typename GTraits::NodeType NodeType; 67 typedef typename GTraits::nodes_iterator node_iterator; 68 typedef typename GTraits::ChildIteratorType child_iterator; 69public: 70 GraphWriter(std::ostream &o, const GraphType &g) : O(o), G(g) {} 71 72 void writeHeader(const std::string &Name) { 73 if (Name.empty()) 74 O << "digraph foo {\n"; // Graph name doesn't matter 75 else 76 O << "digraph " << Name << " {\n"; 77 78 std::string GraphName = DOTTraits::getGraphName(G); 79 if (!GraphName.empty()) 80 O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; 81 O << DOTTraits::getGraphProperties(G); 82 O << "\n"; 83 } 84 85 void writeFooter() { 86 // Finish off the graph 87 O << "}\n"; 88 } 89 90 void writeNodes() { 91 // Loop over the graph, printing it out... 92 for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G); 93 I != E; ++I) 94 writeNode(&*I); 95 } 96 97 void writeNode(NodeType *Node) { 98 std::string NodeAttributes = DOTTraits::getNodeAttributes(Node); 99 100 O << "\tNode" << (void*)Node << " [shape=record,"; 101 if (!NodeAttributes.empty()) O << NodeAttributes << ","; 102 O << "label=\"{" 103 << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 104 105 // Print out the fields of the current node... 106 child_iterator EI = GTraits::child_begin(Node); 107 child_iterator EE = GTraits::child_end(Node); 108 if (EI != EE) { 109 O << "|{"; 110 111 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 112 if (i) O << "|"; 113 O << "<g" << i << ">" << DOTTraits::getEdgeSourceLabel(Node, EI); 114 } 115 116 if (EI != EE) 117 O << "|truncated..."; 118 O << "}"; 119 } 120 O << "}\"];\n"; // Finish printing the "node" line 121 122 // Output all of the edges now 123 EI = GTraits::child_begin(Node); 124 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) 125 writeEdge(Node, i, EI); 126 } 127 128 void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) { 129 if (NodeType *TargetNode = *EI) { 130 int DestPort = -1; 131 if (DOTTraits::edgeTargetsEdgeSource(Node, EI)) { 132 child_iterator TargetIt = DOTTraits::getEdgeTarget(Node, EI); 133 134 // Figure out which edge this targets... 135 unsigned Offset = std::distance(GTraits::child_begin(TargetNode), 136 TargetIt); 137 DestPort = (int)Offset; 138 } 139 140 emitEdge((void *)Node, edgeidx, (void*)TargetNode, DestPort, 141 DOTTraits::getEdgeAttributes(Node, EI)); 142 } 143 } 144 145 /// emitSimpleNode - Outputs a simple (non-record) node 146 void emitSimpleNode(const void *ID, const std::string &Attr, 147 const std::string &Label, unsigned NumEdgeSources = 0, 148 const std::vector<std::string> *EdgeSourceLabels = 0) { 149 O << "\tNode" << ID << "[ "; 150 if (!Attr.empty()) 151 O << Attr << ","; 152 O << " label =\""; 153 if (NumEdgeSources) O << "{"; 154 O << DOT::EscapeString(Label); 155 if (NumEdgeSources) { 156 O << "|{"; 157 158 for (unsigned i = 0; i != NumEdgeSources; ++i) { 159 if (i) O << "|"; 160 O << "<g" << i << ">"; 161 if (EdgeSourceLabels) O << (*EdgeSourceLabels)[i]; 162 } 163 O << "}}"; 164 } 165 O << "\"];\n"; 166 } 167 168 /// emitEdge - Output an edge from a simple node into the graph... 169 void emitEdge(const void *SrcNodeID, int SrcNodePort, 170 const void *DestNodeID, int DestNodePort, 171 const std::string &Attrs) { 172 if (SrcNodePort > 64) return; // Eminating from truncated part? 173 if (DestNodePort > 64) DestNodePort = 64; // Targetting the truncated part? 174 175 O << "\tNode" << SrcNodeID; 176 if (SrcNodePort >= 0) 177 O << ":g" << SrcNodePort; 178 O << " -> Node" << (void*)DestNodeID; 179 if (DestNodePort >= 0) 180 O << ":g" << DestNodePort; 181 182 if (!Attrs.empty()) 183 O << "[" << Attrs << "]"; 184 O << ";\n"; 185 } 186}; 187 188template<typename GraphType> 189std::ostream &WriteGraph(std::ostream &O, const GraphType &G, 190 const std::string &Name = "") { 191 // Start the graph emission process... 192 GraphWriter<GraphType> W(O, G); 193 194 // Output the header for the graph... 195 W.writeHeader(Name); 196 197 // Emit all of the nodes in the graph... 198 W.writeNodes(); 199 200 // Output any customizations on the graph 201 DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, W); 202 203 // Output the end of the graph 204 W.writeFooter(); 205 return O; 206} 207 208#endif 209