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/ADT/GraphTraits.h" 00027 #include "llvm/Support/DOTGraphTraits.h" 00028 #include "llvm/Support/Path.h" 00029 #include "llvm/Support/raw_ostream.h" 00030 #include <cassert> 00031 #include <vector> 00032 00033 namespace llvm { 00034 00035 namespace DOT { // Private functions... 00036 std::string EscapeString(const std::string &Label); 00037 00038 /// \brief Get a color string for this node number. Simply round-robin selects 00039 /// from a reasonable number of colors. 00040 StringRef getColorString(unsigned NodeNumber); 00041 } 00042 00043 namespace GraphProgram { 00044 enum Name { 00045 DOT, 00046 FDP, 00047 NEATO, 00048 TWOPI, 00049 CIRCO 00050 }; 00051 } 00052 00053 bool DisplayGraph(StringRef Filename, bool wait = true, 00054 GraphProgram::Name program = GraphProgram::DOT); 00055 00056 template<typename GraphType> 00057 class GraphWriter { 00058 raw_ostream &O; 00059 const GraphType &G; 00060 00061 typedef DOTGraphTraits<GraphType> DOTTraits; 00062 typedef GraphTraits<GraphType> GTraits; 00063 typedef typename GTraits::NodeType NodeType; 00064 typedef typename GTraits::nodes_iterator node_iterator; 00065 typedef typename GTraits::ChildIteratorType child_iterator; 00066 DOTTraits DTraits; 00067 00068 // Writes the edge labels of the node to O and returns true if there are any 00069 // edge labels not equal to the empty string "". 00070 bool getEdgeSourceLabels(raw_ostream &O, NodeType *Node) { 00071 child_iterator EI = GTraits::child_begin(Node); 00072 child_iterator EE = GTraits::child_end(Node); 00073 bool hasEdgeSourceLabels = false; 00074 00075 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 00076 std::string label = DTraits.getEdgeSourceLabel(Node, EI); 00077 00078 if (label.empty()) 00079 continue; 00080 00081 hasEdgeSourceLabels = true; 00082 00083 if (i) 00084 O << "|"; 00085 00086 O << "<s" << i << ">" << DOT::EscapeString(label); 00087 } 00088 00089 if (EI != EE && hasEdgeSourceLabels) 00090 O << "|<s64>truncated..."; 00091 00092 return hasEdgeSourceLabels; 00093 } 00094 00095 public: 00096 GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) { 00097 DTraits = DOTTraits(SN); 00098 } 00099 00100 void writeGraph(const std::string &Title = "") { 00101 // Output the header for the graph... 00102 writeHeader(Title); 00103 00104 // Emit all of the nodes in the graph... 00105 writeNodes(); 00106 00107 // Output any customizations on the graph 00108 DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, *this); 00109 00110 // Output the end of the graph 00111 writeFooter(); 00112 } 00113 00114 void writeHeader(const std::string &Title) { 00115 std::string GraphName = DTraits.getGraphName(G); 00116 00117 if (!Title.empty()) 00118 O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n"; 00119 else if (!GraphName.empty()) 00120 O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n"; 00121 else 00122 O << "digraph unnamed {\n"; 00123 00124 if (DTraits.renderGraphFromBottomUp()) 00125 O << "\trankdir=\"BT\";\n"; 00126 00127 if (!Title.empty()) 00128 O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n"; 00129 else if (!GraphName.empty()) 00130 O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; 00131 O << DTraits.getGraphProperties(G); 00132 O << "\n"; 00133 } 00134 00135 void writeFooter() { 00136 // Finish off the graph 00137 O << "}\n"; 00138 } 00139 00140 void writeNodes() { 00141 // Loop over the graph, printing it out... 00142 for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G); 00143 I != E; ++I) 00144 if (!isNodeHidden(*I)) 00145 writeNode(*I); 00146 } 00147 00148 bool isNodeHidden(NodeType &Node) { 00149 return isNodeHidden(&Node); 00150 } 00151 00152 bool isNodeHidden(NodeType *const *Node) { 00153 return isNodeHidden(*Node); 00154 } 00155 00156 bool isNodeHidden(NodeType *Node) { 00157 return DTraits.isNodeHidden(Node); 00158 } 00159 00160 void writeNode(NodeType& Node) { 00161 writeNode(&Node); 00162 } 00163 00164 void writeNode(NodeType *const *Node) { 00165 writeNode(*Node); 00166 } 00167 00168 void writeNode(NodeType *Node) { 00169 std::string NodeAttributes = DTraits.getNodeAttributes(Node, G); 00170 00171 O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,"; 00172 if (!NodeAttributes.empty()) O << NodeAttributes << ","; 00173 O << "label=\"{"; 00174 00175 if (!DTraits.renderGraphFromBottomUp()) { 00176 O << DOT::EscapeString(DTraits.getNodeLabel(Node, G)); 00177 00178 // If we should include the address of the node in the label, do so now. 00179 if (DTraits.hasNodeAddressLabel(Node, G)) 00180 O << "|" << static_cast<const void*>(Node); 00181 00182 std::string NodeDesc = DTraits.getNodeDescription(Node, G); 00183 if (!NodeDesc.empty()) 00184 O << "|" << DOT::EscapeString(NodeDesc); 00185 } 00186 00187 std::string edgeSourceLabels; 00188 raw_string_ostream EdgeSourceLabels(edgeSourceLabels); 00189 bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node); 00190 00191 if (hasEdgeSourceLabels) { 00192 if (!DTraits.renderGraphFromBottomUp()) O << "|"; 00193 00194 O << "{" << EdgeSourceLabels.str() << "}"; 00195 00196 if (DTraits.renderGraphFromBottomUp()) O << "|"; 00197 } 00198 00199 if (DTraits.renderGraphFromBottomUp()) { 00200 O << DOT::EscapeString(DTraits.getNodeLabel(Node, G)); 00201 00202 // If we should include the address of the node in the label, do so now. 00203 if (DTraits.hasNodeAddressLabel(Node, G)) 00204 O << "|" << static_cast<const void*>(Node); 00205 00206 std::string NodeDesc = DTraits.getNodeDescription(Node, G); 00207 if (!NodeDesc.empty()) 00208 O << "|" << DOT::EscapeString(NodeDesc); 00209 } 00210 00211 if (DTraits.hasEdgeDestLabels()) { 00212 O << "|{"; 00213 00214 unsigned i = 0, e = DTraits.numEdgeDestLabels(Node); 00215 for (; i != e && i != 64; ++i) { 00216 if (i) O << "|"; 00217 O << "<d" << i << ">" 00218 << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i)); 00219 } 00220 00221 if (i != e) 00222 O << "|<d64>truncated..."; 00223 O << "}"; 00224 } 00225 00226 O << "}\"];\n"; // Finish printing the "node" line 00227 00228 // Output all of the edges now 00229 child_iterator EI = GTraits::child_begin(Node); 00230 child_iterator EE = GTraits::child_end(Node); 00231 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) 00232 if (!DTraits.isNodeHidden(*EI)) 00233 writeEdge(Node, i, EI); 00234 for (; EI != EE; ++EI) 00235 if (!DTraits.isNodeHidden(*EI)) 00236 writeEdge(Node, 64, EI); 00237 } 00238 00239 void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) { 00240 if (NodeType *TargetNode = *EI) { 00241 int DestPort = -1; 00242 if (DTraits.edgeTargetsEdgeSource(Node, EI)) { 00243 child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI); 00244 00245 // Figure out which edge this targets... 00246 unsigned Offset = 00247 (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt); 00248 DestPort = static_cast<int>(Offset); 00249 } 00250 00251 if (DTraits.getEdgeSourceLabel(Node, EI).empty()) 00252 edgeidx = -1; 00253 00254 emitEdge(static_cast<const void*>(Node), edgeidx, 00255 static_cast<const void*>(TargetNode), DestPort, 00256 DTraits.getEdgeAttributes(Node, EI, G)); 00257 } 00258 } 00259 00260 /// emitSimpleNode - Outputs a simple (non-record) node 00261 void emitSimpleNode(const void *ID, const std::string &Attr, 00262 const std::string &Label, unsigned NumEdgeSources = 0, 00263 const std::vector<std::string> *EdgeSourceLabels = nullptr) { 00264 O << "\tNode" << ID << "[ "; 00265 if (!Attr.empty()) 00266 O << Attr << ","; 00267 O << " label =\""; 00268 if (NumEdgeSources) O << "{"; 00269 O << DOT::EscapeString(Label); 00270 if (NumEdgeSources) { 00271 O << "|{"; 00272 00273 for (unsigned i = 0; i != NumEdgeSources; ++i) { 00274 if (i) O << "|"; 00275 O << "<s" << i << ">"; 00276 if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]); 00277 } 00278 O << "}}"; 00279 } 00280 O << "\"];\n"; 00281 } 00282 00283 /// emitEdge - Output an edge from a simple node into the graph... 00284 void emitEdge(const void *SrcNodeID, int SrcNodePort, 00285 const void *DestNodeID, int DestNodePort, 00286 const std::string &Attrs) { 00287 if (SrcNodePort > 64) return; // Eminating from truncated part? 00288 if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part? 00289 00290 O << "\tNode" << SrcNodeID; 00291 if (SrcNodePort >= 0) 00292 O << ":s" << SrcNodePort; 00293 O << " -> Node" << DestNodeID; 00294 if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels()) 00295 O << ":d" << DestNodePort; 00296 00297 if (!Attrs.empty()) 00298 O << "[" << Attrs << "]"; 00299 O << ";\n"; 00300 } 00301 00302 /// getOStream - Get the raw output stream into the graph file. Useful to 00303 /// write fancy things using addCustomGraphFeatures(). 00304 raw_ostream &getOStream() { 00305 return O; 00306 } 00307 }; 00308 00309 template<typename GraphType> 00310 raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G, 00311 bool ShortNames = false, 00312 const Twine &Title = "") { 00313 // Start the graph emission process... 00314 GraphWriter<GraphType> W(O, G, ShortNames); 00315 00316 // Emit the graph. 00317 W.writeGraph(Title.str()); 00318 00319 return O; 00320 } 00321 00322 std::string createGraphFilename(const Twine &Name, int &FD); 00323 00324 template <typename GraphType> 00325 std::string WriteGraph(const GraphType &G, const Twine &Name, 00326 bool ShortNames = false, const Twine &Title = "") { 00327 int FD; 00328 // Windows can't always handle long paths, so limit the length of the name. 00329 std::string N = Name.str(); 00330 N = N.substr(0, std::min<std::size_t>(N.size(), 140)); 00331 std::string Filename = createGraphFilename(N, FD); 00332 raw_fd_ostream O(FD, /*shouldClose=*/ true); 00333 00334 if (FD == -1) { 00335 errs() << "error opening file '" << Filename << "' for writing!\n"; 00336 return ""; 00337 } 00338 00339 llvm::WriteGraph(O, G, ShortNames, Title); 00340 errs() << " done. \n"; 00341 00342 return Filename; 00343 } 00344 00345 /// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file, 00346 /// then cleanup. For use from the debugger. 00347 /// 00348 template<typename GraphType> 00349 void ViewGraph(const GraphType &G, const Twine &Name, 00350 bool ShortNames = false, const Twine &Title = "", 00351 GraphProgram::Name Program = GraphProgram::DOT) { 00352 std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title); 00353 00354 if (Filename.empty()) 00355 return; 00356 00357 DisplayGraph(Filename, true, Program); 00358 } 00359 00360 } // End llvm namespace 00361 00362 #endif