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 std::string GraphName = DOTTraits::getGraphName(G); 00082 if (!GraphName.empty()) 00083 O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; 00084 O << DOTTraits::getGraphProperties(G); 00085 O << "\n"; 00086 } 00087 00088 void writeFooter() { 00089 // Finish off the graph 00090 O << "}\n"; 00091 } 00092 00093 void writeNodes() { 00094 // Loop over the graph, printing it out... 00095 for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G); 00096 I != E; ++I) 00097 writeNode(&*I); 00098 } 00099 00100 void writeNode(NodeType *Node) { 00101 std::string NodeAttributes = DOTTraits::getNodeAttributes(Node); 00102 00103 O << "\tNode" << reinterpret_cast<const void*>(Node) << " [shape=record,"; 00104 if (!NodeAttributes.empty()) O << NodeAttributes << ","; 00105 O << "label=\"{" 00106 << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 00107 00108 // Print out the fields of the current node... 00109 child_iterator EI = GTraits::child_begin(Node); 00110 child_iterator EE = GTraits::child_end(Node); 00111 if (EI != EE) { 00112 O << "|{"; 00113 00114 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 00115 if (i) O << "|"; 00116 O << "<g" << i << ">" << DOTTraits::getEdgeSourceLabel(Node, EI); 00117 } 00118 00119 if (EI != EE) 00120 O << "|<g64>truncated..."; 00121 O << "}"; 00122 } 00123 O << "}\"];\n"; // Finish printing the "node" line 00124 00125 // Output all of the edges now 00126 EI = GTraits::child_begin(Node); 00127 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) 00128 writeEdge(Node, i, EI); 00129 for (; EI != EE; ++EI) 00130 writeEdge(Node, 64, EI); 00131 } 00132 00133 void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) { 00134 if (NodeType *TargetNode = *EI) { 00135 int DestPort = -1; 00136 if (DOTTraits::edgeTargetsEdgeSource(Node, EI)) { 00137 child_iterator TargetIt = DOTTraits::getEdgeTarget(Node, EI); 00138 00139 // Figure out which edge this targets... 00140 unsigned Offset = std::distance(GTraits::child_begin(TargetNode), 00141 TargetIt); 00142 DestPort = static_cast<int>(Offset); 00143 } 00144 00145 emitEdge(reinterpret_cast<const void*>(Node), edgeidx, 00146 reinterpret_cast<const void*>(TargetNode), DestPort, 00147 DOTTraits::getEdgeAttributes(Node, EI)); 00148 } 00149 } 00150 00151 /// emitSimpleNode - Outputs a simple (non-record) node 00152 void emitSimpleNode(const void *ID, const std::string &Attr, 00153 const std::string &Label, unsigned NumEdgeSources = 0, 00154 const std::vector<std::string> *EdgeSourceLabels = 0) { 00155 O << "\tNode" << ID << "[ "; 00156 if (!Attr.empty()) 00157 O << Attr << ","; 00158 O << " label =\""; 00159 if (NumEdgeSources) O << "{"; 00160 O << DOT::EscapeString(Label); 00161 if (NumEdgeSources) { 00162 O << "|{"; 00163 00164 for (unsigned i = 0; i != NumEdgeSources; ++i) { 00165 if (i) O << "|"; 00166 O << "<g" << i << ">"; 00167 if (EdgeSourceLabels) O << (*EdgeSourceLabels)[i]; 00168 } 00169 O << "}}"; 00170 } 00171 O << "\"];\n"; 00172 } 00173 00174 /// emitEdge - Output an edge from a simple node into the graph... 00175 void emitEdge(const void *SrcNodeID, int SrcNodePort, 00176 const void *DestNodeID, int DestNodePort, 00177 const std::string &Attrs) { 00178 if (SrcNodePort > 64) return; // Eminating from truncated part? 00179 if (DestNodePort > 64) DestNodePort = 64; // Targetting the truncated part? 00180 00181 O << "\tNode" << SrcNodeID; 00182 if (SrcNodePort >= 0) 00183 O << ":g" << SrcNodePort; 00184 O << " -> Node" << reinterpret_cast<const void*>(DestNodeID); 00185 if (DestNodePort >= 0) 00186 O << ":g" << DestNodePort; 00187 00188 if (!Attrs.empty()) 00189 O << "[" << Attrs << "]"; 00190 O << ";\n"; 00191 } 00192 }; 00193 00194 template<typename GraphType> 00195 std::ostream &WriteGraph(std::ostream &O, const GraphType &G, 00196 const std::string &Name = "") { 00197 // Start the graph emission process... 00198 GraphWriter<GraphType> W(O, G); 00199 00200 // Output the header for the graph... 00201 W.writeHeader(Name); 00202 00203 // Emit all of the nodes in the graph... 00204 W.writeNodes(); 00205 00206 // Output any customizations on the graph 00207 DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, W); 00208 00209 // Output the end of the graph 00210 W.writeFooter(); 00211 return O; 00212 } 00213 00214 } // End llvm namespace 00215 00216 #endif