1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2013 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/graph-visualizer.h"
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/generic-algorithm.h"
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/generic-node.h"
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/generic-node-inl.h"
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/graph.h"
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/graph-inl.h"
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/node.h"
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/node-properties.h"
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/node-properties-inl.h"
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/opcodes.h"
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/compiler/operator.h"
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/ostreams.h"
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 {
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal {
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace compiler {
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define DEAD_COLOR "#999999"
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass GraphVisualizer : public NullNodeVisitor {
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public:
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GraphVisualizer(OStream& os, Zone* zone, const Graph* graph);  // NOLINT
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void Print();
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GenericGraphVisit::Control Pre(Node* node);
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to);
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private:
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void AnnotateNode(Node* node);
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  void PrintEdge(Node::Edge edge);
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Zone* zone_;
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  NodeSet all_nodes_;
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  NodeSet white_nodes_;
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  bool use_to_def_;
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  OStream& os_;
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const Graph* const graph_;
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DISALLOW_COPY_AND_ASSIGN(GraphVisualizer);
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic Node* GetControlCluster(Node* node) {
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (OperatorProperties::IsBasicBlockBegin(node->op())) {
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return node;
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else if (OperatorProperties::GetControlInputCount(node->op()) == 1) {
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Node* control = NodeProperties::GetControlInput(node, 0);
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return OperatorProperties::IsBasicBlockBegin(control->op()) ? control
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                                                : NULL;
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return NULL;
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochGenericGraphVisit::Control GraphVisualizer::Pre(Node* node) {
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (all_nodes_.count(node) == 0) {
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Node* control_cluster = GetControlCluster(node);
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (control_cluster != NULL) {
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os_ << "  subgraph cluster_BasicBlock" << control_cluster->id() << " {\n";
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "  ID" << node->id() << " [\n";
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    AnnotateNode(node);
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "  ]\n";
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (control_cluster != NULL) os_ << "  }\n";
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    all_nodes_.insert(node);
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (use_to_def_) white_nodes_.insert(node);
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return GenericGraphVisit::CONTINUE;
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochGenericGraphVisit::Control GraphVisualizer::PreEdge(Node* from, int index,
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                                    Node* to) {
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (use_to_def_) return GenericGraphVisit::CONTINUE;
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // When going from def to use, only consider white -> other edges, which are
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // the dead nodes that use live nodes. We're probably not interested in
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // dead nodes that only use other dead nodes.
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (white_nodes_.count(from) > 0) return GenericGraphVisit::CONTINUE;
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return GenericGraphVisit::SKIP;
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass Escaped {
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public:
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  explicit Escaped(const OStringStream& os) : str_(os.c_str()) {}
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  friend OStream& operator<<(OStream& os, const Escaped& e) {
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (const char* s = e.str_; *s != '\0'; ++s) {
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (needs_escape(*s)) os << "\\";
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os << *s;
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return os;
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private:
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  static bool needs_escape(char ch) {
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    switch (ch) {
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      case '>':
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      case '<':
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      case '|':
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      case '}':
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      case '{':
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return true;
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      default:
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return false;
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const char* const str_;
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic bool IsLikelyBackEdge(Node* from, int index, Node* to) {
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (from->opcode() == IrOpcode::kPhi ||
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      from->opcode() == IrOpcode::kEffectPhi) {
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Node* control = NodeProperties::GetControlInput(from, 0);
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return control->opcode() != IrOpcode::kMerge && control != to && index != 0;
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else if (from->opcode() == IrOpcode::kLoop) {
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return index != 0;
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return false;
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid GraphVisualizer::AnnotateNode(Node* node) {
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!use_to_def_) {
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "    style=\"filled\"\n"
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << "    fillcolor=\"" DEAD_COLOR "\"\n";
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "    shape=\"record\"\n";
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  switch (node->opcode()) {
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kEnd:
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kDead:
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kStart:
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os_ << "    style=\"diagonals\"\n";
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      break;
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kMerge:
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kIfTrue:
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kIfFalse:
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    case IrOpcode::kLoop:
150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os_ << "    style=\"rounded\"\n";
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      break;
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    default:
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      break;
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  OStringStream label;
157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  label << *node->op();
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "    label=\"{{#" << node->id() << ":" << Escaped(label);
159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  InputIter i = node->inputs().begin();
161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch       ++i, j--) {
163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "|<I" << i.index() << ">#" << (*i)->id();
164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch       ++i, j--) {
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "|<I" << i.index() << ">X #" << (*i)->id();
168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0;
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch       ++i, j--) {
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "|<I" << i.index() << ">F #" << (*i)->id();
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch       ++i, j--) {
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "|<I" << i.index() << ">E #" << (*i)->id();
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (!use_to_def_ || OperatorProperties::IsBasicBlockBegin(node->op()) ||
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      GetControlCluster(node) == NULL) {
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch         ++i, j--) {
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os_ << "|<I" << i.index() << ">C #" << (*i)->id();
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "}";
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (FLAG_trace_turbo_types && !NodeProperties::IsControl(node)) {
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Bounds bounds = NodeProperties::GetBounds(node);
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    OStringStream upper;
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    bounds.upper->PrintTo(upper);
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    OStringStream lower;
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    bounds.lower->PrintTo(lower);
193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << "|" << Escaped(upper) << "|" << Escaped(lower);
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "}\"\n";
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid GraphVisualizer::PrintEdge(Node::Edge edge) {
200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Node* from = edge.from();
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  int index = edge.index();
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Node* to = edge.to();
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  bool unconstrained = IsLikelyBackEdge(from, index, to);
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "  ID" << from->id();
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (all_nodes_.count(to) == 0) {
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << ":I" << index << ":n -> DEAD_INPUT";
207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else if (OperatorProperties::IsBasicBlockBegin(from->op()) ||
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             GetControlCluster(from) == NULL ||
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             (OperatorProperties::GetControlInputCount(from->op()) > 0 &&
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              NodeProperties::GetControlInput(from) != to)) {
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << ":I" << index << ":n -> ID" << to->id() << ":s"
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << "[" << (unconstrained ? "constraint=false, " : "")
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "")
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "")
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]";
216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    os_ << " -> ID" << to->id() << ":s [color=transparent, "
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << (unconstrained ? "constraint=false, " : "")
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]";
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "\n";
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid GraphVisualizer::Print() {
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "digraph D {\n"
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  node [fontsize=8,height=0.25]\n"
228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  rankdir=\"BT\"\n"
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  ranksep=\"1.2 equally\"\n"
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  overlap=\"false\"\n"
231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  splines=\"true\"\n"
232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  concentrate=\"true\"\n"
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  \n";
234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Make sure all nodes have been output before writing out the edges.
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  use_to_def_ = true;
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // TODO(svenpanne) Remove the need for the const_casts.
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  const_cast<Graph*>(graph_)->VisitNodeInputsFromEnd(this);
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  white_nodes_.insert(const_cast<Graph*>(graph_)->start());
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Visit all uses of white nodes.
242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  use_to_def_ = false;
243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GenericGraphVisit::Visit<GraphVisualizer, NodeUseIterationTraits<Node> >(
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      const_cast<Graph*>(graph_), zone_, white_nodes_.begin(),
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      white_nodes_.end(), this);
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "  DEAD_INPUT [\n"
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "    style=\"filled\" \n"
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "    fillcolor=\"" DEAD_COLOR "\"\n"
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "  ]\n"
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      << "\n";
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // With all the nodes written, add the edges.
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (NodeSetIter i = all_nodes_.begin(); i != all_nodes_.end(); ++i) {
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    Node::Inputs inputs = (*i)->inputs();
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch         ++iter) {
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintEdge(iter.edge());
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  os_ << "}\n";
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochGraphVisualizer::GraphVisualizer(OStream& os, Zone* zone,
266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                 const Graph* graph)  // NOLINT
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    : zone_(zone),
268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      all_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)),
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      white_nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)),
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      use_to_def_(true),
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      os_(os),
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      graph_(graph) {}
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochOStream& operator<<(OStream& os, const AsDOT& ad) {
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  Zone tmp_zone(ad.graph.zone()->isolate());
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  GraphVisualizer(os, &tmp_zone, &ad.graph).Print();
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return os;
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}  // namespace v8::internal::compiler
283