~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to libclamav/c++/llvm/include/llvm/Support/GraphWriter.h

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===//
2
 
//
3
 
//                     The LLVM Compiler Infrastructure
4
 
//
5
 
// This file is distributed under the University of Illinois Open Source
6
 
// License. See LICENSE.TXT for details.
7
 
//
8
 
//===----------------------------------------------------------------------===//
9
 
//
10
 
// This file defines a simple interface that can be used to print out generic
11
 
// LLVM graphs to ".dot" files.  "dot" is a tool that is part of the AT&T
12
 
// graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
13
 
// be used to turn the files output by this interface into a variety of
14
 
// different graphics formats.
15
 
//
16
 
// Graphs do not need to implement any interface past what is already required
17
 
// by the GraphTraits template, but they can choose to implement specializations
18
 
// of the DOTGraphTraits template if they want to customize the graphs output in
19
 
// any way.
20
 
//
21
 
//===----------------------------------------------------------------------===//
22
 
 
23
 
#ifndef LLVM_SUPPORT_GRAPHWRITER_H
24
 
#define LLVM_SUPPORT_GRAPHWRITER_H
25
 
 
26
 
#include "llvm/Support/DOTGraphTraits.h"
27
 
#include "llvm/Support/raw_ostream.h"
28
 
#include "llvm/ADT/GraphTraits.h"
29
 
#include "llvm/System/Path.h"
30
 
#include <vector>
31
 
#include <cassert>
32
 
 
33
 
namespace llvm {
34
 
 
35
 
namespace DOT {  // Private functions...
36
 
  std::string EscapeString(const std::string &Label);
37
 
}
38
 
 
39
 
namespace GraphProgram {
40
 
   enum Name {
41
 
      DOT,
42
 
      FDP,
43
 
      NEATO,
44
 
      TWOPI,
45
 
      CIRCO
46
 
   };
47
 
}
48
 
 
49
 
void DisplayGraph(const sys::Path& Filename, bool wait=true, GraphProgram::Name program = GraphProgram::DOT);
50
 
 
51
 
template<typename GraphType>
52
 
class GraphWriter {
53
 
  raw_ostream &O;
54
 
  const GraphType &G;
55
 
 
56
 
  typedef DOTGraphTraits<GraphType>           DOTTraits;
57
 
  typedef GraphTraits<GraphType>              GTraits;
58
 
  typedef typename GTraits::NodeType          NodeType;
59
 
  typedef typename GTraits::nodes_iterator    node_iterator;
60
 
  typedef typename GTraits::ChildIteratorType child_iterator;
61
 
  DOTTraits DTraits;
62
 
 
63
 
  // Writes the edge labels of the node to O and returns true if there are any
64
 
  // edge labels not equal to the empty string "".
65
 
  bool getEdgeSourceLabels(raw_ostream &O, NodeType *Node) {
66
 
    child_iterator EI = GTraits::child_begin(Node);
67
 
    child_iterator EE = GTraits::child_end(Node);
68
 
    bool hasEdgeSourceLabels = false;
69
 
 
70
 
    for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
71
 
      std::string label = DTraits.getEdgeSourceLabel(Node, EI);
72
 
 
73
 
      if (label == "")
74
 
        continue;
75
 
 
76
 
      hasEdgeSourceLabels = true;
77
 
 
78
 
      if (i)
79
 
        O << "|";
80
 
 
81
 
      O << "<s" << i << ">" << DTraits.getEdgeSourceLabel(Node, EI);
82
 
    }
83
 
 
84
 
    if (EI != EE && hasEdgeSourceLabels)
85
 
      O << "|<s64>truncated...";
86
 
 
87
 
    return hasEdgeSourceLabels;
88
 
  }
89
 
 
90
 
public:
91
 
  GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
92
 
  DTraits = DOTTraits(SN);
93
 
}
94
 
 
95
 
  void writeHeader(const std::string &Name) {
96
 
    std::string GraphName = DTraits.getGraphName(G);
97
 
 
98
 
    if (!Name.empty())
99
 
      O << "digraph \"" << DOT::EscapeString(Name) << "\" {\n";
100
 
    else if (!GraphName.empty())
101
 
      O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
102
 
    else
103
 
      O << "digraph unnamed {\n";
104
 
 
105
 
    if (DTraits.renderGraphFromBottomUp())
106
 
      O << "\trankdir=\"BT\";\n";
107
 
 
108
 
    if (!Name.empty())
109
 
      O << "\tlabel=\"" << DOT::EscapeString(Name) << "\";\n";
110
 
    else if (!GraphName.empty())
111
 
      O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
112
 
    O << DTraits.getGraphProperties(G);
113
 
    O << "\n";
114
 
  }
115
 
 
116
 
  void writeFooter() {
117
 
    // Finish off the graph
118
 
    O << "}\n";
119
 
  }
120
 
 
121
 
  void writeNodes() {
122
 
    // Loop over the graph, printing it out...
123
 
    for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
124
 
         I != E; ++I)
125
 
      if (!isNodeHidden(*I))
126
 
        writeNode(*I);
127
 
  }
128
 
 
129
 
  bool isNodeHidden(NodeType &Node) {
130
 
    return isNodeHidden(&Node);
131
 
  }
132
 
 
133
 
  bool isNodeHidden(NodeType *const *Node) {
134
 
    return isNodeHidden(*Node);
135
 
  }
136
 
 
137
 
  bool isNodeHidden(NodeType *Node) {
138
 
    return DTraits.isNodeHidden(Node);
139
 
  }
140
 
 
141
 
  void writeNode(NodeType& Node) {
142
 
    writeNode(&Node);
143
 
  }
144
 
 
145
 
  void writeNode(NodeType *const *Node) {
146
 
    writeNode(*Node);
147
 
  }
148
 
 
149
 
  void writeNode(NodeType *Node) {
150
 
    std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
151
 
 
152
 
    O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
153
 
    if (!NodeAttributes.empty()) O << NodeAttributes << ",";
154
 
    O << "label=\"{";
155
 
 
156
 
    if (!DTraits.renderGraphFromBottomUp()) {
157
 
      O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
158
 
 
159
 
      // If we should include the address of the node in the label, do so now.
160
 
      if (DTraits.hasNodeAddressLabel(Node, G))
161
 
        O << "|" << (void*)Node;
162
 
    }
163
 
 
164
 
    std::string edgeSourceLabels;
165
 
    raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
166
 
    bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
167
 
 
168
 
    if (hasEdgeSourceLabels) {
169
 
      if (!DTraits.renderGraphFromBottomUp()) O << "|";
170
 
 
171
 
      O << "{" << EdgeSourceLabels.str() << "}";
172
 
 
173
 
      if (DTraits.renderGraphFromBottomUp()) O << "|";
174
 
    }
175
 
 
176
 
    if (DTraits.renderGraphFromBottomUp()) {
177
 
      O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
178
 
 
179
 
      // If we should include the address of the node in the label, do so now.
180
 
      if (DTraits.hasNodeAddressLabel(Node, G))
181
 
        O << "|" << (void*)Node;
182
 
    }
183
 
 
184
 
    if (DTraits.hasEdgeDestLabels()) {
185
 
      O << "|{";
186
 
 
187
 
      unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
188
 
      for (; i != e && i != 64; ++i) {
189
 
        if (i) O << "|";
190
 
        O << "<d" << i << ">"
191
 
          << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
192
 
      }
193
 
 
194
 
      if (i != e)
195
 
        O << "|<d64>truncated...";
196
 
      O << "}";
197
 
    }
198
 
 
199
 
    O << "}\"];\n";   // Finish printing the "node" line
200
 
 
201
 
    // Output all of the edges now
202
 
    child_iterator EI = GTraits::child_begin(Node);
203
 
    child_iterator EE = GTraits::child_end(Node);
204
 
    for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
205
 
      if (!DTraits.isNodeHidden(*EI))
206
 
        writeEdge(Node, i, EI);
207
 
    for (; EI != EE; ++EI)
208
 
      if (!DTraits.isNodeHidden(*EI))
209
 
        writeEdge(Node, 64, EI);
210
 
  }
211
 
 
212
 
  void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) {
213
 
    if (NodeType *TargetNode = *EI) {
214
 
      int DestPort = -1;
215
 
      if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
216
 
        child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
217
 
 
218
 
        // Figure out which edge this targets...
219
 
        unsigned Offset =
220
 
          (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
221
 
        DestPort = static_cast<int>(Offset);
222
 
      }
223
 
 
224
 
      if (DTraits.getEdgeSourceLabel(Node, EI) == "")
225
 
        edgeidx = -1;
226
 
 
227
 
      emitEdge(static_cast<const void*>(Node), edgeidx,
228
 
               static_cast<const void*>(TargetNode), DestPort,
229
 
               DTraits.getEdgeAttributes(Node, EI));
230
 
    }
231
 
  }
232
 
 
233
 
  /// emitSimpleNode - Outputs a simple (non-record) node
234
 
  void emitSimpleNode(const void *ID, const std::string &Attr,
235
 
                      const std::string &Label, unsigned NumEdgeSources = 0,
236
 
                      const std::vector<std::string> *EdgeSourceLabels = 0) {
237
 
    O << "\tNode" << ID << "[ ";
238
 
    if (!Attr.empty())
239
 
      O << Attr << ",";
240
 
    O << " label =\"";
241
 
    if (NumEdgeSources) O << "{";
242
 
    O << DOT::EscapeString(Label);
243
 
    if (NumEdgeSources) {
244
 
      O << "|{";
245
 
 
246
 
      for (unsigned i = 0; i != NumEdgeSources; ++i) {
247
 
        if (i) O << "|";
248
 
        O << "<s" << i << ">";
249
 
        if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
250
 
      }
251
 
      O << "}}";
252
 
    }
253
 
    O << "\"];\n";
254
 
  }
255
 
 
256
 
  /// emitEdge - Output an edge from a simple node into the graph...
257
 
  void emitEdge(const void *SrcNodeID, int SrcNodePort,
258
 
                const void *DestNodeID, int DestNodePort,
259
 
                const std::string &Attrs) {
260
 
    if (SrcNodePort  > 64) return;             // Eminating from truncated part?
261
 
    if (DestNodePort > 64) DestNodePort = 64;  // Targetting the truncated part?
262
 
 
263
 
    O << "\tNode" << SrcNodeID;
264
 
    if (SrcNodePort >= 0)
265
 
      O << ":s" << SrcNodePort;
266
 
    O << " -> Node" << DestNodeID;
267
 
    if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
268
 
      O << ":d" << DestNodePort;
269
 
 
270
 
    if (!Attrs.empty())
271
 
      O << "[" << Attrs << "]";
272
 
    O << ";\n";
273
 
  }
274
 
 
275
 
  /// getOStream - Get the raw output stream into the graph file. Useful to
276
 
  /// write fancy things using addCustomGraphFeatures().
277
 
  raw_ostream &getOStream() {
278
 
    return O;
279
 
  }
280
 
};
281
 
 
282
 
template<typename GraphType>
283
 
raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
284
 
                        bool ShortNames = false,
285
 
                        const std::string &Name = "",
286
 
                        const std::string &Title = "") {
287
 
  // Start the graph emission process...
288
 
  GraphWriter<GraphType> W(O, G, ShortNames);
289
 
 
290
 
  // Output the header for the graph...
291
 
  W.writeHeader(Title);
292
 
 
293
 
  // Emit all of the nodes in the graph...
294
 
  W.writeNodes();
295
 
 
296
 
  // Output any customizations on the graph
297
 
  DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, W);
298
 
 
299
 
  // Output the end of the graph
300
 
  W.writeFooter();
301
 
  return O;
302
 
}
303
 
 
304
 
template<typename GraphType>
305
 
sys::Path WriteGraph(const GraphType &G, const std::string &Name,
306
 
                     bool ShortNames = false, const std::string &Title = "") {
307
 
  std::string ErrMsg;
308
 
  sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
309
 
  if (Filename.isEmpty()) {
310
 
    errs() << "Error: " << ErrMsg << "\n";
311
 
    return Filename;
312
 
  }
313
 
  Filename.appendComponent(Name + ".dot");
314
 
  if (Filename.makeUnique(true,&ErrMsg)) {
315
 
    errs() << "Error: " << ErrMsg << "\n";
316
 
    return sys::Path();
317
 
  }
318
 
 
319
 
  errs() << "Writing '" << Filename.str() << "'... ";
320
 
 
321
 
  std::string ErrorInfo;
322
 
  raw_fd_ostream O(Filename.c_str(), ErrorInfo);
323
 
 
324
 
  if (ErrorInfo.empty()) {
325
 
    llvm::WriteGraph(O, G, ShortNames, Name, Title);
326
 
    errs() << " done. \n";
327
 
  } else {
328
 
    errs() << "error opening file '" << Filename.str() << "' for writing!\n";
329
 
    Filename.clear();
330
 
  }
331
 
 
332
 
  return Filename;
333
 
}
334
 
 
335
 
/// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
336
 
/// then cleanup.  For use from the debugger.
337
 
///
338
 
template<typename GraphType>
339
 
void ViewGraph(const GraphType &G, const std::string &Name,
340
 
               bool ShortNames = false, const std::string &Title = "",
341
 
               GraphProgram::Name Program = GraphProgram::DOT) {
342
 
  sys::Path Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
343
 
 
344
 
  if (Filename.isEmpty())
345
 
    return;
346
 
 
347
 
  DisplayGraph(Filename, true, Program);
348
 
}
349
 
 
350
 
} // End llvm namespace
351
 
 
352
 
#endif