llvm.org GIT mirror llvm / release_29 include / llvm / Support / GraphWriter.h
release_29

Tree @release_29 (Download .tar.gz)

GraphWriter.h @release_29

551ccae
63b3afa
b2109ce
 
7ed47a1
 
63b3afa
b2109ce
95b923d
 
 
 
 
 
 
 
 
 
 
 
 
 
551ccae
 
95b923d
551ccae
103289e
551ccae
1f6efa3
52883e7
229509a
95b923d
d0fde30
 
95b923d
103289e
95b923d
 
00ad26f
 
 
 
 
 
 
 
 
65b6607
00ad26f
fe2cce6
95b923d
8c836ce
103289e
8c836ce
95b923d
8c836ce
 
 
 
 
a10d598
c500566
 
 
 
 
 
 
 
 
a10d598
c500566
b0cdabb
c500566
 
 
 
 
 
 
7ee42e6
c500566
 
 
 
 
 
 
 
8c836ce
56f4ef3
640e742
 
dc05fff
cce563c
f7e2ca9
d73b908
f7e2ca9
 
d73b908
f7e2ca9
 
d73b908
f7e2ca9
 
d73b908
f7e2ca9
 
4c6809d
a10d598
afbd073
4c6809d
 
afbd073
358f5ac
afbd073
 
95b923d
a10d598
89a1ed5
 
4c6809d
 
2d3ff5a
8c836ce
a10d598
8c836ce
 
 
dc05fff
8c836ce
 
 
95b923d
8c836ce
 
 
 
89938ce
 
 
 
 
 
 
 
 
 
 
 
 
 
9634518
fe2cce6
9634518
 
8c836ce
63b3afa
ce393a6
 
 
63b3afa
8c836ce
a10d598
63b3afa
7953f37
95b923d
89a1ed5
 
a10d598
56f4ef3
63b3afa
f85a55b
a10d598
f85a55b
 
 
c500566
795eb2a
c500566
 
 
a10d598
63b3afa
c500566
63b3afa
a10d598
95b923d
f85a55b
a10d598
56f4ef3
63b3afa
f85a55b
a10d598
f85a55b
 
 
a10d598
3580331
 
a10d598
3580331
 
5b296e3
 
3580331
 
 
 
 
 
 
b78ea80
63b3afa
95b923d
c500566
 
8c836ce
89938ce
 
6a6dd6f
89938ce
 
8c836ce
 
 
 
96f5493
a10d598
 
8c836ce
 
34cd4a4
 
8b70b78
95b923d
96f5493
b0cdabb
c500566
 
7953f37
 
a91f86c
95b923d
 
96f5493
 
7be17dd
a329733
 
96f5493
 
 
137d399
 
 
7be17dd
 
63b3afa
7be17dd
 
787b0db
5b296e3
7be17dd
137d399
7be17dd
137d399
96f5493
 
 
7be17dd
 
 
d8d97ce
 
 
96f5493
 
3580331
7953f37
a10d598
ce4edd6
96f5493
 
 
 
 
f96b006
 
 
 
 
 
8c836ce
95b923d
8c836ce
103289e
 
 
8c836ce
8cbc94a
dc05fff
f7e2ca9
cce563c
dc05fff
95b923d
 
 
9d5b532
74382b7
 
5860c6c
 
 
 
 
 
 
 
 
51c5a28
 
 
5860c6c
 
 
 
 
 
 
 
 
 
 
 
fe2cce6
5860c6c
9d5b532
fe2cce6
9d5b532
 
 
 
74382b7
 
00ad26f
68e18b3
9d5b532
74382b7
9d5b532
fe2cce6
00ad26f
9d5b532
 
d0fde30
 
95b923d
//===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a simple interface that can be used to print out generic
// LLVM graphs to ".dot" files.  "dot" is a tool that is part of the AT&T
// graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
// be used to turn the files output by this interface into a variety of
// different graphics formats.
//
// Graphs do not need to implement any interface past what is already required
// by the GraphTraits template, but they can choose to implement specializations
// of the DOTGraphTraits template if they want to customize the graphs output in
// any way.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_GRAPHWRITER_H
#define LLVM_SUPPORT_GRAPHWRITER_H

#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/Support/Path.h"
#include <vector>
#include <cassert>

namespace llvm {

namespace DOT {  // Private functions...
  std::string EscapeString(const std::string &Label);
}

namespace GraphProgram {
   enum Name {
      DOT,
      FDP,
      NEATO,
      TWOPI,
      CIRCO
   };
}

void DisplayGraph(const sys::Path& Filename, bool wait=true, GraphProgram::Name program = GraphProgram::DOT);

template<typename GraphType>
class GraphWriter {
  raw_ostream &O;
  const GraphType &G;

  typedef DOTGraphTraits<GraphType>           DOTTraits;
  typedef GraphTraits<GraphType>              GTraits;
  typedef typename GTraits::NodeType          NodeType;
  typedef typename GTraits::nodes_iterator    node_iterator;
  typedef typename GTraits::ChildIteratorType child_iterator;
  DOTTraits DTraits;

  // Writes the edge labels of the node to O and returns true if there are any
  // edge labels not equal to the empty string "".
  bool getEdgeSourceLabels(raw_ostream &O, NodeType *Node) {
    child_iterator EI = GTraits::child_begin(Node);
    child_iterator EE = GTraits::child_end(Node);
    bool hasEdgeSourceLabels = false;

    for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
      std::string label = DTraits.getEdgeSourceLabel(Node, EI);

      if (label.empty())
        continue;

      hasEdgeSourceLabels = true;

      if (i)
        O << "|";

      O << "<s" << i << ">" << DOT::EscapeString(label);
    }

    if (EI != EE && hasEdgeSourceLabels)
      O << "|<s64>truncated...";

    return hasEdgeSourceLabels;
  }

public:
  GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
    DTraits = DOTTraits(SN);
  }

  void writeGraph(const std::string &Title = "") {
    // Output the header for the graph...
    writeHeader(Title);

    // Emit all of the nodes in the graph...
    writeNodes();

    // Output any customizations on the graph
    DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, *this);

    // Output the end of the graph
    writeFooter();
  }

  void writeHeader(const std::string &Title) {
    std::string GraphName = DTraits.getGraphName(G);

    if (!Title.empty())
      O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
    else if (!GraphName.empty())
      O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
    else
      O << "digraph unnamed {\n";

    if (DTraits.renderGraphFromBottomUp())
      O << "\trankdir=\"BT\";\n";

    if (!Title.empty())
      O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
    else if (!GraphName.empty())
      O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
    O << DTraits.getGraphProperties(G);
    O << "\n";
  }

  void writeFooter() {
    // Finish off the graph
    O << "}\n";
  }

  void writeNodes() {
    // Loop over the graph, printing it out...
    for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
         I != E; ++I)
      if (!isNodeHidden(*I))
        writeNode(*I);
  }

  bool isNodeHidden(NodeType &Node) {
    return isNodeHidden(&Node);
  }

  bool isNodeHidden(NodeType *const *Node) {
    return isNodeHidden(*Node);
  }

  bool isNodeHidden(NodeType *Node) {
    return DTraits.isNodeHidden(Node);
  }

  void writeNode(NodeType& Node) {
    writeNode(&Node);
  }

  void writeNode(NodeType *const *Node) {
    writeNode(*Node);
  }

  void writeNode(NodeType *Node) {
    std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);

    O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
    if (!NodeAttributes.empty()) O << NodeAttributes << ",";
    O << "label=\"{";

    if (!DTraits.renderGraphFromBottomUp()) {
      O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));

      // If we should include the address of the node in the label, do so now.
      if (DTraits.hasNodeAddressLabel(Node, G))
        O << "|" << (void*)Node;
    }

    std::string edgeSourceLabels;
    raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
    bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);

    if (hasEdgeSourceLabels) {
      if (!DTraits.renderGraphFromBottomUp()) O << "|";

      O << "{" << EdgeSourceLabels.str() << "}";

      if (DTraits.renderGraphFromBottomUp()) O << "|";
    }

    if (DTraits.renderGraphFromBottomUp()) {
      O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));

      // If we should include the address of the node in the label, do so now.
      if (DTraits.hasNodeAddressLabel(Node, G))
        O << "|" << (void*)Node;
    }

    if (DTraits.hasEdgeDestLabels()) {
      O << "|{";

      unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
      for (; i != e && i != 64; ++i) {
        if (i) O << "|";
        O << "<d" << i << ">"
          << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
      }

      if (i != e)
        O << "|<d64>truncated...";
      O << "}";
    }

    O << "}\"];\n";   // Finish printing the "node" line

    // Output all of the edges now
    child_iterator EI = GTraits::child_begin(Node);
    child_iterator EE = GTraits::child_end(Node);
    for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
      if (!DTraits.isNodeHidden(*EI))
        writeEdge(Node, i, EI);
    for (; EI != EE; ++EI)
      if (!DTraits.isNodeHidden(*EI))
        writeEdge(Node, 64, EI);
  }

  void writeEdge(NodeType *Node, unsigned edgeidx, child_iterator EI) {
    if (NodeType *TargetNode = *EI) {
      int DestPort = -1;
      if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
        child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);

        // Figure out which edge this targets...
        unsigned Offset =
          (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
        DestPort = static_cast<int>(Offset);
      }

      if (DTraits.getEdgeSourceLabel(Node, EI).empty())
        edgeidx = -1;

      emitEdge(static_cast<const void*>(Node), edgeidx,
               static_cast<const void*>(TargetNode), DestPort,
               DTraits.getEdgeAttributes(Node, EI, G));
    }
  }

  /// emitSimpleNode - Outputs a simple (non-record) node
  void emitSimpleNode(const void *ID, const std::string &Attr,
                      const std::string &Label, unsigned NumEdgeSources = 0,
                      const std::vector<std::string> *EdgeSourceLabels = 0) {
    O << "\tNode" << ID << "[ ";
    if (!Attr.empty())
      O << Attr << ",";
    O << " label =\"";
    if (NumEdgeSources) O << "{";
    O << DOT::EscapeString(Label);
    if (NumEdgeSources) {
      O << "|{";

      for (unsigned i = 0; i != NumEdgeSources; ++i) {
        if (i) O << "|";
        O << "<s" << i << ">";
        if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
      }
      O << "}}";
    }
    O << "\"];\n";
  }

  /// emitEdge - Output an edge from a simple node into the graph...
  void emitEdge(const void *SrcNodeID, int SrcNodePort,
                const void *DestNodeID, int DestNodePort,
                const std::string &Attrs) {
    if (SrcNodePort  > 64) return;             // Eminating from truncated part?
    if (DestNodePort > 64) DestNodePort = 64;  // Targetting the truncated part?

    O << "\tNode" << SrcNodeID;
    if (SrcNodePort >= 0)
      O << ":s" << SrcNodePort;
    O << " -> Node" << DestNodeID;
    if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
      O << ":d" << DestNodePort;

    if (!Attrs.empty())
      O << "[" << Attrs << "]";
    O << ";\n";
  }

  /// getOStream - Get the raw output stream into the graph file. Useful to
  /// write fancy things using addCustomGraphFeatures().
  raw_ostream &getOStream() {
    return O;
  }
};

template<typename GraphType>
raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
                        bool ShortNames = false,
                        const std::string &Title = "") {
  // Start the graph emission process...
  GraphWriter<GraphType> W(O, G, ShortNames);

  // Emit the graph.
  W.writeGraph(Title);

  return O;
}

template<typename GraphType>
sys::Path WriteGraph(const GraphType &G, const std::string &Name,
                     bool ShortNames = false, const std::string &Title = "") {
  std::string ErrMsg;
  sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
  if (Filename.isEmpty()) {
    errs() << "Error: " << ErrMsg << "\n";
    return Filename;
  }
  Filename.appendComponent(Name + ".dot");
  if (Filename.makeUnique(true,&ErrMsg)) {
    errs() << "Error: " << ErrMsg << "\n";
    return sys::Path();
  }

  errs() << "Writing '" << Filename.str() << "'... ";

  std::string ErrorInfo;
  raw_fd_ostream O(Filename.c_str(), ErrorInfo);

  if (ErrorInfo.empty()) {
    llvm::WriteGraph(O, G, ShortNames, Title);
    errs() << " done. \n";
  } else {
    errs() << "error opening file '" << Filename.str() << "' for writing!\n";
    Filename.clear();
  }

  return Filename;
}

/// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
/// then cleanup.  For use from the debugger.
///
template<typename GraphType>
void ViewGraph(const GraphType &G, const std::string &Name,
               bool ShortNames = false, const std::string &Title = "",
               GraphProgram::Name Program = GraphProgram::DOT) {
  sys::Path Filename = llvm::WriteGraph(G, Name, ShortNames, Title);

  if (Filename.isEmpty())
    return;

  DisplayGraph(Filename, true, Program);
}

} // End llvm namespace

#endif