GraphWriter.h revision 9106a588060085316895a9b256909d795c2f5b5e
1//===-- Support/GraphWriter.h - Write a graph to a .dot file ---*- C++ -*--===// 2// 3// This file defines a simple interface that can be used to print out generic 4// LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T 5// graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can 6// be used to turn the files output by this interface into a variety of 7// different graphics formats. 8// 9// Graphs do not need to implement any interface past what is already required 10// by the GraphTraits template, but they can choose to implement specializations 11// of the DOTGraphTraits template if they want to customize the graphs output in 12// any way. 13// 14//===----------------------------------------------------------------------===// 15 16#ifndef SUPPORT_GRAPHWRITER_H 17#define SUPPORT_GRAPHWRITER_H 18 19#include "Support/DOTGraphTraits.h" 20#include "Support/DepthFirstIterator.h" 21#include <ostream> 22 23namespace DOT { // Private functions... 24 inline std::string EscapeString(const std::string &Label) { 25 std::string Str(Label); 26 for (unsigned i = 0; i != Str.length(); ++i) 27 switch (Str[i]) { 28 case '\n': 29 Str.insert(Str.begin()+i, '\\'); // Escape character... 30 ++i; 31 Str[i] = 'n'; 32 break; 33 case '\t': 34 Str.insert(Str.begin()+i, ' '); // Convert to two spaces 35 ++i; 36 Str[i] = ' '; 37 break; 38 case '\\': 39 if (i+1 != Str.length() && Str[i+1] == 'l') 40 break; // don't disturb \l 41 case '{': case '}': 42 case '<': case '>': 43 Str.insert(Str.begin()+i, '\\'); // Escape character... 44 ++i; // don't infinite loop 45 break; 46 } 47 return Str; 48 } 49} 50 51template<typename GraphType> 52std::ostream &WriteGraph(std::ostream &O, const GraphType &G) { 53 typedef DOTGraphTraits<GraphType> DOTTraits; 54 typedef GraphTraits<GraphType> GTraits; 55 typedef typename GTraits::NodeType NodeType; 56 57 O << "digraph foo {\n" // Graph name doesn't matter 58 << "\tsize=\"7.5,10\";\n"; // Size to fit on a page 59 60 std::string GraphName = DOTTraits::getGraphName(G); 61 if (!GraphName.empty()) 62 O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; 63 O << "\n"; 64 65 // Loop over the graph in DFO, printing it out... 66 NodeType *Root = GTraits::getEntryNode(G); 67 for (df_iterator<GraphType> I = df_begin(G), E = df_end(G); I != E; ++I) { 68 NodeType *Node = *I; 69 70 std::string NodeAttributes = DOTTraits::getNodeAttributes(Node); 71 72 O << "\tNode" << (void*)Node << " ["; 73 if (!NodeAttributes.empty()) O << NodeAttributes << ","; 74 O << "shape=record,label=\"{" 75 << DOT::EscapeString(DOTTraits::getNodeLabel(Node, G)); 76 77 // Print out the fields of the current node... 78 typename GTraits::ChildIteratorType EI = GTraits::child_begin(Node); 79 typename GTraits::ChildIteratorType EE = GTraits::child_end(Node); 80 if (EI != EE) { 81 O << "|{"; 82 83 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 84 if (i) O << "|"; 85 O << "<g" << i << ">" << DOTTraits::getEdgeSourceLabel(Node, EI); 86 } 87 88 if (EI != EE) 89 O << "|truncated..."; 90 O << "}"; 91 } 92 O << "}\"];\n"; // Finish printing the "node" line 93 94 // Output all of the edges now 95 EI = GTraits::child_begin(Node); 96 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) { 97 NodeType *TargetNode = *EI; 98 O << "\tNode" << (void*)Node << ":g" << i << " -> Node" 99 << (void*)TargetNode; 100 if (DOTTraits::edgeTargetsEdgeSource(Node, EI)) { 101 typename GTraits::ChildIteratorType TargetIt = 102 DOTTraits::getEdgeTarget(Node, EI); 103 // Figure out which edge this targets... 104 unsigned Offset = std::distance(GTraits::child_begin(TargetNode), 105 TargetIt); 106 if (Offset > 64) Offset = 64; // Targetting the trancated part? 107 O << ":g" << Offset; 108 } 109 110 std::string EdgeAttributes = DOTTraits::getEdgeAttributes(Node, EI); 111 if (!EdgeAttributes.empty()) 112 O << "[" << EdgeAttributes << "]"; 113 O << ";\n"; 114 } 115 } 116 117 // Finish off the graph 118 O << "}\n"; 119 return O; 120} 121 122#endif 123