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 is distributed under the University of Illinois Open Source 00006 // 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/Support/Streams.h" 00028 #include "llvm/ADT/GraphTraits.h" 00029 #include "llvm/System/Path.h" 00030 #include <fstream> 00031 #include <vector> 00032 00033 namespace llvm { 00034 00035 namespace DOT { // Private functions... 00036 inline std::string EscapeString(const std::string &Label) { 00037 std::string Str(Label); 00038 for (unsigned i = 0; i != Str.length(); ++i) 00039 switch (Str[i]) { 00040 case '\n': 00041 Str.insert(Str.begin()+i, '\\'); // Escape character... 00042 ++i; 00043 Str[i] = 'n'; 00044 break; 00045 case '\t': 00046 Str.insert(Str.begin()+i, ' '); // Convert to two spaces 00047 ++i; 00048 Str[i] = ' '; 00049 break; 00050 case '\\': 00051 if (i+1 != Str.length()) 00052 switch (Str[i+1]) { 00053 case 'l': continue; // don't disturb \l 00054 case '|': case '{': case '}': 00055 Str.erase(Str.begin()+i); continue; 00056 default: break; 00057 } 00058 case '{': case '}': 00059 case '<': case '>': 00060 case '|': case '"': 00061 Str.insert(Str.begin()+i, '\\'); // Escape character... 00062 ++i; // don't infinite loop 00063 break; 00064 } 00065 return Str; 00066 } 00067 } 00068 00069 void DisplayGraph(const sys::Path& Filename); 00070 00071 template<typename GraphType> 00072 class GraphWriter { 00073 std::ostream &O; 00074 const GraphType &G; 00075 00076 typedef DOTGraphTraits<GraphType> DOTTraits; 00077 typedef GraphTraits<GraphType> GTraits; 00078 typedef typename GTraits::NodeType NodeType; 00079 typedef typename GTraits::nodes_iterator node_iterator; 00080 typedef typename GTraits::ChildIteratorType child_iterator; 00081 public: 00082 GraphWriter(std::ostream &o, const GraphType &g) : O(o), G(g) {} 00083 00084 void writeHeader(const std::string &Name) { 00085 std::string GraphName = DOTTraits::getGraphName(G); 00086 00087 if (!Name.empty()) 00088 O << "digraph \"" << DOT::EscapeString(Name) << "\" {\n"; 00089 else if (!GraphName.empty()) 00090 O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n"; 00091 else 00092 O << "digraph unnamed {\n"; 00093 00094 if (DOTTraits::renderGraphFromBottomUp()) 00095 O << "\trankdir=\"BT\";\n"; 00096 00097 if (!Name.empty()) 00098 O << "\tlabel=\"" << DOT::EscapeString(Name) << "\";\n"; 00099 else if (!GraphName.empty()) 00100 O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; 00101 O << DOTTraits::getGraphProperties(G); 00102 O << "\n"; 00103 } 00104 00105 void writeFooter() { 00106 // Finish off the graph 00107 O << "}\n"; 00108 } 00109 00110 void writeNodes() { 00111 // Loop over the graph, printing it out... 00112 for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G); 00113 I != E; ++I) 00114 writeNode(*I); 00115 } 00116 00117 void writeNode(NodeType& Node) { 00118 writeNode(&Node); 00119 } 00120 00121 void writeNode(NodeType *const *Node) { 00122 writeNode(*Node); 00123 } 00124 00125 void writeNode(NodeType *Node) { 00126 std::string NodeAttributes = DOTTraits::getNodeAttributes(Node, G); 00127 00128 O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,"; 00129 if (!NodeAttributes.empty()) O << NodeAttributes << ","; 00130 O << "label=\"{"; 00131 00132 if (!DOTTraits::renderGraphFromBottomUp()) { 00133 O << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 00134 00135 // If we should include the address of the node in the label, do so now. 00136 if (DOTTraits::hasNodeAddressLabel(Node, G)) 00137 O << "|" << (void*)Node; 00138 } 00139 00140 // Print out the fields of the current node... 00141 child_iterator EI = GTraits::child_begin(Node); 00142 child_iterator EE = GTraits::child_end(Node); 00143 if (EI != EE) { 00144 if (!DOTTraits::renderGraphFromBottomUp()) O << "|"; 00145 O << "{"; 00146 00147 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 00148 if (i) O << "|"; 00149 O << "<s" << i << ">" << DOTTraits::getEdgeSourceLabel(Node, EI); 00150 } 00151 00152 if (EI != EE) 00153 O << "|<s64>truncated..."; 00154 O << "}"; 00155 if (DOTTraits::renderGraphFromBottomUp()) O << "|"; 00156 } 00157 00158 if (DOTTraits::renderGraphFromBottomUp()) { 00159 O << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 00160 00161 // If we should include the address of the node in the label, do so now. 00162 if (DOTTraits::hasNodeAddressLabel(Node, G)) 00163 O << "|" << (void*)Node; 00164 } 00165 00166 if (DOTTraits::hasEdgeDestLabels()) { 00167 O << "|{"; 00168 00169 unsigned i = 0, e = DOTTraits::numEdgeDestLabels(Node); 00170 for (; i != e && i != 64; ++i) { 00171 if (i) O << "|"; 00172 O << "<d" << i << ">" << DOTTraits::getEdgeDestLabel(Node, i); 00173 } 00174 00175 if (i != e) 00176 O << "|<d64>truncated..."; 00177 O << "}"; 00178 } 00179 00180 O << "}\"];\n"; // Finish printing the "node" line 00181 00182 // Output all of the edges now 00183 EI = GTraits::child_begin(Node); 00184 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) 00185 writeEdge(Node, i, EI); 00186 for (; EI != EE; ++EI) 00187 writeEdge(Node, 64, EI); 00188 } 00189 00190 void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) { 00191 if (NodeType *TargetNode = *EI) { 00192 int DestPort = -1; 00193 if (DOTTraits::edgeTargetsEdgeSource(Node, EI)) { 00194 child_iterator TargetIt = DOTTraits::getEdgeTarget(Node, EI); 00195 00196 // Figure out which edge this targets... 00197 unsigned Offset = 00198 (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt); 00199 DestPort = static_cast<int>(Offset); 00200 } 00201 00202 emitEdge(static_cast<const void*>(Node), edgeidx, 00203 static_cast<const void*>(TargetNode), DestPort, 00204 DOTTraits::getEdgeAttributes(Node, EI)); 00205 } 00206 } 00207 00208 /// emitSimpleNode - Outputs a simple (non-record) node 00209 void emitSimpleNode(const void *ID, const std::string &Attr, 00210 const std::string &Label, unsigned NumEdgeSources = 0, 00211 const std::vector<std::string> *EdgeSourceLabels = 0) { 00212 O << "\tNode" << ID << "[ "; 00213 if (!Attr.empty()) 00214 O << Attr << ","; 00215 O << " label =\""; 00216 if (NumEdgeSources) O << "{"; 00217 O << DOT::EscapeString(Label); 00218 if (NumEdgeSources) { 00219 O << "|{"; 00220 00221 for (unsigned i = 0; i != NumEdgeSources; ++i) { 00222 if (i) O << "|"; 00223 O << "<g" << i << ">"; 00224 if (EdgeSourceLabels) O << (*EdgeSourceLabels)[i]; 00225 } 00226 O << "}}"; 00227 } 00228 O << "\"];\n"; 00229 } 00230 00231 /// emitEdge - Output an edge from a simple node into the graph... 00232 void emitEdge(const void *SrcNodeID, int SrcNodePort, 00233 const void *DestNodeID, int DestNodePort, 00234 const std::string &Attrs) { 00235 if (SrcNodePort > 64) return; // Eminating from truncated part? 00236 if (DestNodePort > 64) DestNodePort = 64; // Targetting the truncated part? 00237 00238 O << "\tNode" << SrcNodeID; 00239 if (SrcNodePort >= 0) 00240 O << ":s" << SrcNodePort; 00241 O << " -> Node" << DestNodeID; 00242 if (DestNodePort >= 0) 00243 O << ":d" << DestNodePort; 00244 00245 if (!Attrs.empty()) 00246 O << "[" << Attrs << "]"; 00247 O << ";\n"; 00248 } 00249 }; 00250 00251 template<typename GraphType> 00252 std::ostream &WriteGraph(std::ostream &O, const GraphType &G, 00253 const std::string &Name = "", 00254 const std::string &Title = "") { 00255 // Start the graph emission process... 00256 GraphWriter<GraphType> W(O, G); 00257 00258 // Output the header for the graph... 00259 W.writeHeader(Title); 00260 00261 // Emit all of the nodes in the graph... 00262 W.writeNodes(); 00263 00264 // Output any customizations on the graph 00265 DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, W); 00266 00267 // Output the end of the graph 00268 W.writeFooter(); 00269 return O; 00270 } 00271 00272 template<typename GraphType> 00273 sys::Path WriteGraph(const GraphType &G, 00274 const std::string& Name, 00275 const std::string& Title = "") { 00276 std::string ErrMsg; 00277 sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg); 00278 if (Filename.isEmpty()) { 00279 cerr << "Error: " << ErrMsg << "\n"; 00280 return Filename; 00281 } 00282 Filename.appendComponent(Name + ".dot"); 00283 if (Filename.makeUnique(true,&ErrMsg)) { 00284 cerr << "Error: " << ErrMsg << "\n"; 00285 return sys::Path(); 00286 } 00287 00288 cerr << "Writing '" << Filename << "'... "; 00289 00290 std::ofstream O(Filename.c_str()); 00291 00292 if (O.good()) { 00293 WriteGraph(O, G, Name, Title); 00294 cerr << " done. \n"; 00295 00296 O.close(); 00297 } else { 00298 cerr << "error opening file for writing!\n"; 00299 Filename.clear(); 00300 } 00301 00302 return Filename; 00303 } 00304 00305 /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, 00306 /// then cleanup. For use from the debugger. 00307 /// 00308 template<typename GraphType> 00309 void ViewGraph(const GraphType& G, 00310 const std::string& Name, 00311 const std::string& Title = "") { 00312 sys::Path Filename = WriteGraph(G, Name, Title); 00313 00314 if (Filename.isEmpty()) { 00315 return; 00316 } 00317 00318 DisplayGraph(Filename); 00319 } 00320 00321 } // End llvm namespace 00322 00323 #endif