LLVM API Documentation
00001 //===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by the LLVM research group and is distributed under 00006 // the University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a simple interface that can be used to print out generic 00011 // LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T 00012 // graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can 00013 // be used to turn the files output by this interface into a variety of 00014 // different graphics formats. 00015 // 00016 // Graphs do not need to implement any interface past what is already required 00017 // by the GraphTraits template, but they can choose to implement specializations 00018 // of the DOTGraphTraits template if they want to customize the graphs output in 00019 // any way. 00020 // 00021 //===----------------------------------------------------------------------===// 00022 00023 #ifndef LLVM_SUPPORT_GRAPHWRITER_H 00024 #define LLVM_SUPPORT_GRAPHWRITER_H 00025 00026 #include "llvm/Support/DOTGraphTraits.h" 00027 #include "llvm/ADT/GraphTraits.h" 00028 #include <vector> 00029 #include <iostream> 00030 00031 namespace llvm { 00032 00033 namespace DOT { // Private functions... 00034 inline std::string EscapeString(const std::string &Label) { 00035 std::string Str(Label); 00036 for (unsigned i = 0; i != Str.length(); ++i) 00037 switch (Str[i]) { 00038 case '\n': 00039 Str.insert(Str.begin()+i, '\\'); // Escape character... 00040 ++i; 00041 Str[i] = 'n'; 00042 break; 00043 case '\t': 00044 Str.insert(Str.begin()+i, ' '); // Convert to two spaces 00045 ++i; 00046 Str[i] = ' '; 00047 break; 00048 case '\\': 00049 if (i+1 != Str.length() && Str[i+1] == 'l') 00050 break; // don't disturb \l 00051 case '{': case '}': 00052 case '<': case '>': 00053 case '"': 00054 Str.insert(Str.begin()+i, '\\'); // Escape character... 00055 ++i; // don't infinite loop 00056 break; 00057 } 00058 return Str; 00059 } 00060 } 00061 00062 template<typename GraphType> 00063 class GraphWriter { 00064 std::ostream &O; 00065 const GraphType &G; 00066 00067 typedef DOTGraphTraits<GraphType> DOTTraits; 00068 typedef GraphTraits<GraphType> GTraits; 00069 typedef typename GTraits::NodeType NodeType; 00070 typedef typename GTraits::nodes_iterator node_iterator; 00071 typedef typename GTraits::ChildIteratorType child_iterator; 00072 public: 00073 GraphWriter(std::ostream &o, const GraphType &g) : O(o), G(g) {} 00074 00075 void writeHeader(const std::string &Name) { 00076 if (Name.empty()) 00077 O << "digraph foo {\n"; // Graph name doesn't matter 00078 else 00079 O << "digraph " << Name << " {\n"; 00080 00081 if (DOTTraits::renderGraphFromBottomUp()) 00082 O << "\trankdir=\"BT\";\n"; 00083 00084 std::string GraphName = DOTTraits::getGraphName(G); 00085 if (!GraphName.empty()) 00086 O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; 00087 O << DOTTraits::getGraphProperties(G); 00088 O << "\n"; 00089 } 00090 00091 void writeFooter() { 00092 // Finish off the graph 00093 O << "}\n"; 00094 } 00095 00096 void writeNodes() { 00097 // Loop over the graph, printing it out... 00098 for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G); 00099 I != E; ++I) 00100 writeNode(&*I); 00101 } 00102 00103 void writeNode(NodeType *const *Node) { 00104 writeNode(*Node); 00105 } 00106 00107 void writeNode(NodeType *Node) { 00108 std::string NodeAttributes = DOTTraits::getNodeAttributes(Node); 00109 00110 O << "\tNode" << reinterpret_cast<const void*>(Node) << " [shape=record,"; 00111 if (!NodeAttributes.empty()) O << NodeAttributes << ","; 00112 O << "label=\"{"; 00113 00114 if (!DOTTraits::renderGraphFromBottomUp()) { 00115 O << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 00116 00117 // If we should include the address of the node in the label, do so now. 00118 if (DOTTraits::hasNodeAddressLabel(Node, G)) 00119 O << "|" << (void*)Node; 00120 } 00121 00122 // Print out the fields of the current node... 00123 child_iterator EI = GTraits::child_begin(Node); 00124 child_iterator EE = GTraits::child_end(Node); 00125 if (EI != EE) { 00126 if (!DOTTraits::renderGraphFromBottomUp()) O << "|"; 00127 O << "{"; 00128 00129 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 00130 if (i) O << "|"; 00131 O << "<g" << i << ">" << DOTTraits::getEdgeSourceLabel(Node, EI); 00132 } 00133 00134 if (EI != EE) 00135 O << "|<g64>truncated..."; 00136 O << "}"; 00137 if (DOTTraits::renderGraphFromBottomUp()) O << "|"; 00138 } 00139 00140 if (DOTTraits::renderGraphFromBottomUp()) { 00141 O << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 00142 00143 // If we should include the address of the node in the label, do so now. 00144 if (DOTTraits::hasNodeAddressLabel(Node, G)) 00145 O << "|" << (void*)Node; 00146 } 00147 00148 O << "}\"];\n"; // Finish printing the "node" line 00149 00150 // Output all of the edges now 00151 EI = GTraits::child_begin(Node); 00152 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) 00153 writeEdge(Node, i, EI); 00154 for (; EI != EE; ++EI) 00155 writeEdge(Node, 64, EI); 00156 } 00157 00158 void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) { 00159 if (NodeType *TargetNode = *EI) { 00160 int DestPort = -1; 00161 if (DOTTraits::edgeTargetsEdgeSource(Node, EI)) { 00162 child_iterator TargetIt = DOTTraits::getEdgeTarget(Node, EI); 00163 00164 // Figure out which edge this targets... 00165 unsigned Offset = std::distance(GTraits::child_begin(TargetNode), 00166 TargetIt); 00167 DestPort = static_cast<int>(Offset); 00168 } 00169 00170 emitEdge(reinterpret_cast<const void*>(Node), edgeidx, 00171 reinterpret_cast<const void*>(TargetNode), DestPort, 00172 DOTTraits::getEdgeAttributes(Node, EI)); 00173 } 00174 } 00175 00176 /// emitSimpleNode - Outputs a simple (non-record) node 00177 void emitSimpleNode(const void *ID, const std::string &Attr, 00178 const std::string &Label, unsigned NumEdgeSources = 0, 00179 const std::vector<std::string> *EdgeSourceLabels = 0) { 00180 O << "\tNode" << ID << "[ "; 00181 if (!Attr.empty()) 00182 O << Attr << ","; 00183 O << " label =\""; 00184 if (NumEdgeSources) O << "{"; 00185 O << DOT::EscapeString(Label); 00186 if (NumEdgeSources) { 00187 O << "|{"; 00188 00189 for (unsigned i = 0; i != NumEdgeSources; ++i) { 00190 if (i) O << "|"; 00191 O << "<g" << i << ">"; 00192 if (EdgeSourceLabels) O << (*EdgeSourceLabels)[i]; 00193 } 00194 O << "}}"; 00195 } 00196 O << "\"];\n"; 00197 } 00198 00199 /// emitEdge - Output an edge from a simple node into the graph... 00200 void emitEdge(const void *SrcNodeID, int SrcNodePort, 00201 const void *DestNodeID, int DestNodePort, 00202 const std::string &Attrs) { 00203 if (SrcNodePort > 64) return; // Eminating from truncated part? 00204 if (DestNodePort > 64) DestNodePort = 64; // Targetting the truncated part? 00205 00206 O << "\tNode" << SrcNodeID; 00207 if (SrcNodePort >= 0) 00208 O << ":g" << SrcNodePort; 00209 O << " -> Node" << reinterpret_cast<const void*>(DestNodeID); 00210 if (DestNodePort >= 0) 00211 O << ":g" << DestNodePort; 00212 00213 if (!Attrs.empty()) 00214 O << "[" << Attrs << "]"; 00215 O << ";\n"; 00216 } 00217 }; 00218 00219 template<typename GraphType> 00220 std::ostream &WriteGraph(std::ostream &O, const GraphType &G, 00221 const std::string &Name = "") { 00222 // Start the graph emission process... 00223 GraphWriter<GraphType> W(O, G); 00224 00225 // Output the header for the graph... 00226 W.writeHeader(Name); 00227 00228 // Emit all of the nodes in the graph... 00229 W.writeNodes(); 00230 00231 // Output any customizations on the graph 00232 DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, W); 00233 00234 // Output the end of the graph 00235 W.writeFooter(); 00236 return O; 00237 } 00238 00239 } // End llvm namespace 00240 00241 #endif