blob: e018c7ac198a65bb0389b5e83b9d537562d18491 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/graph-visualizer.h"
6
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#include <sstream>
8#include <string>
9
10#include "src/code-stubs.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/compiler/graph.h"
12#include "src/compiler/graph-inl.h"
13#include "src/compiler/node.h"
14#include "src/compiler/node-properties.h"
15#include "src/compiler/node-properties-inl.h"
16#include "src/compiler/opcodes.h"
17#include "src/compiler/operator.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018#include "src/compiler/register-allocator.h"
19#include "src/compiler/schedule.h"
20#include "src/compiler/scheduler.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021#include "src/ostreams.h"
22
23namespace v8 {
24namespace internal {
25namespace compiler {
26
Emily Bernierd0a1eb72015-03-24 16:35:39 -040027static int SafeId(Node* node) { return node == NULL ? -1 : node->id(); }
28static const char* SafeMnemonic(Node* node) {
29 return node == NULL ? "null" : node->op()->mnemonic();
30}
31
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#define DEAD_COLOR "#999999"
33
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034class AllNodes {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 enum State { kDead, kGray, kLive };
37
38 AllNodes(Zone* local_zone, const Graph* graph)
39 : state(graph->NodeCount(), kDead, local_zone),
40 live(local_zone),
41 gray(local_zone) {
42 Node* end = graph->end();
43 state[end->id()] = kLive;
44 live.push_back(end);
45 // Find all live nodes reachable from end.
46 for (size_t i = 0; i < live.size(); i++) {
47 for (Node* const input : live[i]->inputs()) {
48 if (input == NULL) {
49 // TODO(titzer): print a warning.
50 continue;
51 }
52 if (input->id() >= graph->NodeCount()) {
53 // TODO(titzer): print a warning.
54 continue;
55 }
56 if (state[input->id()] != kLive) {
57 live.push_back(input);
58 state[input->id()] = kLive;
59 }
60 }
61 }
62
63 // Find all nodes that are not reachable from end that use live nodes.
64 for (size_t i = 0; i < live.size(); i++) {
65 for (Node* const use : live[i]->uses()) {
66 if (state[use->id()] == kDead) {
67 gray.push_back(use);
68 state[use->id()] = kGray;
69 }
70 }
71 }
72 }
73
74 bool IsLive(Node* node) {
75 return node != NULL && node->id() < static_cast<int>(state.size()) &&
76 state[node->id()] == kLive;
77 }
78
79 ZoneVector<State> state;
80 NodeVector live;
81 NodeVector gray;
82};
83
84
85class Escaped {
86 public:
87 explicit Escaped(const std::ostringstream& os,
88 const char* escaped_chars = "<>|{}")
89 : str_(os.str()), escaped_chars_(escaped_chars) {}
90
91 friend std::ostream& operator<<(std::ostream& os, const Escaped& e) {
92 for (std::string::const_iterator i = e.str_.begin(); i != e.str_.end();
93 ++i) {
94 if (e.needs_escape(*i)) os << "\\";
95 os << *i;
96 }
97 return os;
98 }
99
100 private:
101 bool needs_escape(char ch) const {
102 for (size_t i = 0; i < strlen(escaped_chars_); ++i) {
103 if (ch == escaped_chars_[i]) return true;
104 }
105 return false;
106 }
107
108 const std::string str_;
109 const char* const escaped_chars_;
110};
111
112class JSONGraphNodeWriter {
113 public:
114 JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph)
115 : os_(os), all_(zone, graph), first_node_(true) {}
116
117 void Print() {
118 for (Node* const node : all_.live) PrintNode(node);
119 }
120
121 void PrintNode(Node* node) {
122 if (first_node_) {
123 first_node_ = false;
124 } else {
125 os_ << ",";
126 }
127 std::ostringstream label;
128 label << *node->op();
129 os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"")
130 << "\"";
131 IrOpcode::Value opcode = node->opcode();
132 if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
133 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
134 << "]";
135 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
136 << "]";
137 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
138 opcode == IrOpcode::kLoop) {
139 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
140 << "]";
141 }
142 if (opcode == IrOpcode::kBranch) {
143 os_ << ",\"rankInputs\":[0]";
144 }
145 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
146 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
147 : "false");
148 os_ << "}";
149 }
150
151 private:
152 std::ostream& os_;
153 AllNodes all_;
154 bool first_node_;
155
156 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
157};
158
159
160class JSONGraphEdgeWriter {
161 public:
162 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
163 : os_(os), all_(zone, graph), first_edge_(true) {}
164
165 void Print() {
166 for (Node* const node : all_.live) PrintEdges(node);
167 }
168
169 void PrintEdges(Node* node) {
170 for (int i = 0; i < node->InputCount(); i++) {
171 Node* input = node->InputAt(i);
172 if (input == NULL) continue;
173 PrintEdge(node, i, input);
174 }
175 }
176
177 void PrintEdge(Node* from, int index, Node* to) {
178 if (first_edge_) {
179 first_edge_ = false;
180 } else {
181 os_ << ",";
182 }
183 const char* edge_type = NULL;
184 if (index < NodeProperties::FirstValueIndex(from)) {
185 edge_type = "unknown";
186 } else if (index < NodeProperties::FirstContextIndex(from)) {
187 edge_type = "value";
188 } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
189 edge_type = "context";
190 } else if (index < NodeProperties::FirstEffectIndex(from)) {
191 edge_type = "frame-state";
192 } else if (index < NodeProperties::FirstControlIndex(from)) {
193 edge_type = "effect";
194 } else {
195 edge_type = "control";
196 }
197 os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
198 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
199 }
200
201 private:
202 std::ostream& os_;
203 AllNodes all_;
204 bool first_edge_;
205
206 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
207};
208
209
210std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
211 Zone tmp_zone(ad.graph.zone()->isolate());
212 os << "{\"nodes\":[";
213 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print();
214 os << "],\"edges\":[";
215 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
216 os << "]}";
217 return os;
218}
219
220
221class GraphVisualizer {
222 public:
223 GraphVisualizer(std::ostream& os, Zone* zone, const Graph* graph)
224 : all_(zone, graph), os_(os) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225
226 void Print();
227
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400228 void PrintNode(Node* node, bool gray);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229
230 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 void PrintEdge(Edge edge);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233 AllNodes all_;
234 std::ostream& os_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235
236 DISALLOW_COPY_AND_ASSIGN(GraphVisualizer);
237};
238
239
240static Node* GetControlCluster(Node* node) {
241 if (OperatorProperties::IsBasicBlockBegin(node->op())) {
242 return node;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243 } else if (node->op()->ControlInputCount() == 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 Node* control = NodeProperties::GetControlInput(node, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245 return control != NULL &&
246 OperatorProperties::IsBasicBlockBegin(control->op())
247 ? control
248 : NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 } else {
250 return NULL;
251 }
252}
253
254
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400255void GraphVisualizer::PrintNode(Node* node, bool gray) {
256 Node* control_cluster = GetControlCluster(node);
257 if (control_cluster != NULL) {
258 os_ << " subgraph cluster_BasicBlock" << control_cluster->id() << " {\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400260 os_ << " ID" << SafeId(node) << " [\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261
262 os_ << " shape=\"record\"\n";
263 switch (node->opcode()) {
264 case IrOpcode::kEnd:
265 case IrOpcode::kDead:
266 case IrOpcode::kStart:
267 os_ << " style=\"diagonals\"\n";
268 break;
269 case IrOpcode::kMerge:
270 case IrOpcode::kIfTrue:
271 case IrOpcode::kIfFalse:
272 case IrOpcode::kLoop:
273 os_ << " style=\"rounded\"\n";
274 break;
275 default:
276 break;
277 }
278
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400279 if (gray) {
280 os_ << " style=\"filled\"\n"
281 << " fillcolor=\"" DEAD_COLOR "\"\n";
282 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400284 std::ostringstream label;
285 label << *node->op();
286 os_ << " label=\"{{#" << SafeId(node) << ":" << Escaped(label);
287
288 auto i = node->input_edges().begin();
289 for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
290 os_ << "|<I" << (*i).index() << ">#" << SafeId((*i).to());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 }
292 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
293 ++i, j--) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 os_ << "|<I" << (*i).index() << ">X #" << SafeId((*i).to());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 }
296 for (int j = OperatorProperties::GetFrameStateInputCount(node->op()); j > 0;
297 ++i, j--) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400298 os_ << "|<I" << (*i).index() << ">F #" << SafeId((*i).to());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400300 for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
301 os_ << "|<I" << (*i).index() << ">E #" << SafeId((*i).to());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 }
303
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400304 if (OperatorProperties::IsBasicBlockBegin(node->op()) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 GetControlCluster(node) == NULL) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400306 for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
307 os_ << "|<I" << (*i).index() << ">C #" << SafeId((*i).to());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000308 }
309 }
310 os_ << "}";
311
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 if (FLAG_trace_turbo_types && NodeProperties::IsTyped(node)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000313 Bounds bounds = NodeProperties::GetBounds(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400314 std::ostringstream upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 bounds.upper->PrintTo(upper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400316 std::ostringstream lower;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 bounds.lower->PrintTo(lower);
318 os_ << "|" << Escaped(upper) << "|" << Escaped(lower);
319 }
320 os_ << "}\"\n";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400321
322 os_ << " ]\n";
323 if (control_cluster != NULL) os_ << " }\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324}
325
326
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400327static bool IsLikelyBackEdge(Node* from, int index, Node* to) {
328 if (from->opcode() == IrOpcode::kPhi ||
329 from->opcode() == IrOpcode::kEffectPhi) {
330 Node* control = NodeProperties::GetControlInput(from, 0);
331 return control != NULL && control->opcode() != IrOpcode::kMerge &&
332 control != to && index != 0;
333 } else if (from->opcode() == IrOpcode::kLoop) {
334 return index != 0;
335 } else {
336 return false;
337 }
338}
339
340
341void GraphVisualizer::PrintEdge(Edge edge) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 Node* from = edge.from();
343 int index = edge.index();
344 Node* to = edge.to();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400345
346 if (!all_.IsLive(to)) return; // skip inputs that point to dead or NULL.
347
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348 bool unconstrained = IsLikelyBackEdge(from, index, to);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400349 os_ << " ID" << SafeId(from);
350
351 if (OperatorProperties::IsBasicBlockBegin(from->op()) ||
352 GetControlCluster(from) == NULL ||
353 (from->op()->ControlInputCount() > 0 &&
354 NodeProperties::GetControlInput(from) != to)) {
355 os_ << ":I" << index << ":n -> ID" << SafeId(to) << ":s"
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356 << "[" << (unconstrained ? "constraint=false, " : "")
357 << (NodeProperties::IsControlEdge(edge) ? "style=bold, " : "")
358 << (NodeProperties::IsEffectEdge(edge) ? "style=dotted, " : "")
359 << (NodeProperties::IsContextEdge(edge) ? "style=dashed, " : "") << "]";
360 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400361 os_ << " -> ID" << SafeId(to) << ":s [color=transparent, "
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000362 << (unconstrained ? "constraint=false, " : "")
363 << (NodeProperties::IsControlEdge(edge) ? "style=dashed, " : "") << "]";
364 }
365 os_ << "\n";
366}
367
368
369void GraphVisualizer::Print() {
370 os_ << "digraph D {\n"
371 << " node [fontsize=8,height=0.25]\n"
372 << " rankdir=\"BT\"\n"
373 << " ranksep=\"1.2 equally\"\n"
374 << " overlap=\"false\"\n"
375 << " splines=\"true\"\n"
376 << " concentrate=\"true\"\n"
377 << " \n";
378
379 // Make sure all nodes have been output before writing out the edges.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400380 for (Node* const node : all_.live) PrintNode(node, false);
381 for (Node* const node : all_.gray) PrintNode(node, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382
383 // With all the nodes written, add the edges.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400384 for (Node* const node : all_.live) {
385 for (Edge edge : node->use_edges()) {
386 PrintEdge(edge);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 }
388 }
389 os_ << "}\n";
390}
391
392
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400393std::ostream& operator<<(std::ostream& os, const AsDOT& ad) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 Zone tmp_zone(ad.graph.zone()->isolate());
395 GraphVisualizer(os, &tmp_zone, &ad.graph).Print();
396 return os;
397}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400398
399
400class GraphC1Visualizer {
401 public:
402 GraphC1Visualizer(std::ostream& os, Zone* zone); // NOLINT
403
404 void PrintCompilation(const CompilationInfo* info);
405 void PrintSchedule(const char* phase, const Schedule* schedule,
406 const SourcePositionTable* positions,
407 const InstructionSequence* instructions);
408 void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
409 Zone* zone() const { return zone_; }
410
411 private:
412 void PrintIndent();
413 void PrintStringProperty(const char* name, const char* value);
414 void PrintLongProperty(const char* name, int64_t value);
415 void PrintIntProperty(const char* name, int value);
416 void PrintBlockProperty(const char* name, BasicBlock::Id block_id);
417 void PrintNodeId(Node* n);
418 void PrintNode(Node* n);
419 void PrintInputs(Node* n);
420 void PrintInputs(InputIter* i, int count, const char* prefix);
421 void PrintType(Node* node);
422
423 void PrintLiveRange(LiveRange* range, const char* type);
424 class Tag FINAL BASE_EMBEDDED {
425 public:
426 Tag(GraphC1Visualizer* visualizer, const char* name) {
427 name_ = name;
428 visualizer_ = visualizer;
429 visualizer->PrintIndent();
430 visualizer_->os_ << "begin_" << name << "\n";
431 visualizer->indent_++;
432 }
433
434 ~Tag() {
435 visualizer_->indent_--;
436 visualizer_->PrintIndent();
437 visualizer_->os_ << "end_" << name_ << "\n";
438 DCHECK(visualizer_->indent_ >= 0);
439 }
440
441 private:
442 GraphC1Visualizer* visualizer_;
443 const char* name_;
444 };
445
446 std::ostream& os_;
447 int indent_;
448 Zone* zone_;
449
450 DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
451};
452
453
454void GraphC1Visualizer::PrintIndent() {
455 for (int i = 0; i < indent_; i++) {
456 os_ << " ";
457 }
458}
459
460
461GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
462 : os_(os), indent_(0), zone_(zone) {}
463
464
465void GraphC1Visualizer::PrintStringProperty(const char* name,
466 const char* value) {
467 PrintIndent();
468 os_ << name << " \"" << value << "\"\n";
469}
470
471
472void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
473 PrintIndent();
474 os_ << name << " " << static_cast<int>(value / 1000) << "\n";
475}
476
477
478void GraphC1Visualizer::PrintBlockProperty(const char* name,
479 BasicBlock::Id block_id) {
480 PrintIndent();
481 os_ << name << " \"B" << block_id << "\"\n";
482}
483
484
485void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
486 PrintIndent();
487 os_ << name << " " << value << "\n";
488}
489
490
491void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
492 Tag tag(this, "compilation");
493 if (info->IsOptimizing()) {
494 Handle<String> name = info->function()->debug_name();
495 PrintStringProperty("name", name->ToCString().get());
496 PrintIndent();
497 os_ << "method \"" << name->ToCString().get() << ":"
498 << info->optimization_id() << "\"\n";
499 } else {
500 CodeStub::Major major_key = info->code_stub()->MajorKey();
501 PrintStringProperty("name", CodeStub::MajorName(major_key, false));
502 PrintStringProperty("method", "stub");
503 }
504 PrintLongProperty("date",
505 static_cast<int64_t>(base::OS::TimeCurrentMillis()));
506}
507
508
509void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
510
511
512void GraphC1Visualizer::PrintNode(Node* n) {
513 PrintNodeId(n);
514 os_ << " " << *n->op() << " ";
515 PrintInputs(n);
516}
517
518
519void GraphC1Visualizer::PrintInputs(InputIter* i, int count,
520 const char* prefix) {
521 if (count > 0) {
522 os_ << prefix;
523 }
524 while (count > 0) {
525 os_ << " ";
526 PrintNodeId(**i);
527 ++(*i);
528 count--;
529 }
530}
531
532
533void GraphC1Visualizer::PrintInputs(Node* node) {
534 auto i = node->inputs().begin();
535 PrintInputs(&i, node->op()->ValueInputCount(), " ");
536 PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
537 " Ctx:");
538 PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
539 " FS:");
540 PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
541 PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
542}
543
544
545void GraphC1Visualizer::PrintType(Node* node) {
546 if (NodeProperties::IsTyped(node)) {
547 Bounds bounds = NodeProperties::GetBounds(node);
548 os_ << " type:";
549 bounds.upper->PrintTo(os_);
550 os_ << "..";
551 bounds.lower->PrintTo(os_);
552 }
553}
554
555
556void GraphC1Visualizer::PrintSchedule(const char* phase,
557 const Schedule* schedule,
558 const SourcePositionTable* positions,
559 const InstructionSequence* instructions) {
560 Tag tag(this, "cfg");
561 PrintStringProperty("name", phase);
562 const BasicBlockVector* rpo = schedule->rpo_order();
563 for (size_t i = 0; i < rpo->size(); i++) {
564 BasicBlock* current = (*rpo)[i];
565 Tag block_tag(this, "block");
566 PrintBlockProperty("name", current->id());
567 PrintIntProperty("from_bci", -1);
568 PrintIntProperty("to_bci", -1);
569
570 PrintIndent();
571 os_ << "predecessors";
572 for (BasicBlock::Predecessors::iterator j = current->predecessors_begin();
573 j != current->predecessors_end(); ++j) {
574 os_ << " \"B" << (*j)->id() << "\"";
575 }
576 os_ << "\n";
577
578 PrintIndent();
579 os_ << "successors";
580 for (BasicBlock::Successors::iterator j = current->successors_begin();
581 j != current->successors_end(); ++j) {
582 os_ << " \"B" << (*j)->id() << "\"";
583 }
584 os_ << "\n";
585
586 PrintIndent();
587 os_ << "xhandlers\n";
588
589 PrintIndent();
590 os_ << "flags\n";
591
592 if (current->dominator() != NULL) {
593 PrintBlockProperty("dominator", current->dominator()->id());
594 }
595
596 PrintIntProperty("loop_depth", current->loop_depth());
597
598 const InstructionBlock* instruction_block =
599 instructions->InstructionBlockAt(current->GetRpoNumber());
600 if (instruction_block->code_start() >= 0) {
601 int first_index = instruction_block->first_instruction_index();
602 int last_index = instruction_block->last_instruction_index();
603 PrintIntProperty("first_lir_id", LifetimePosition::FromInstructionIndex(
604 first_index).Value());
605 PrintIntProperty("last_lir_id", LifetimePosition::FromInstructionIndex(
606 last_index).Value());
607 }
608
609 {
610 Tag states_tag(this, "states");
611 Tag locals_tag(this, "locals");
612 int total = 0;
613 for (BasicBlock::const_iterator i = current->begin(); i != current->end();
614 ++i) {
615 if ((*i)->opcode() == IrOpcode::kPhi) total++;
616 }
617 PrintIntProperty("size", total);
618 PrintStringProperty("method", "None");
619 int index = 0;
620 for (BasicBlock::const_iterator i = current->begin(); i != current->end();
621 ++i) {
622 if ((*i)->opcode() != IrOpcode::kPhi) continue;
623 PrintIndent();
624 os_ << index << " ";
625 PrintNodeId(*i);
626 os_ << " [";
627 PrintInputs(*i);
628 os_ << "]\n";
629 index++;
630 }
631 }
632
633 {
634 Tag HIR_tag(this, "HIR");
635 for (BasicBlock::const_iterator i = current->begin(); i != current->end();
636 ++i) {
637 Node* node = *i;
638 if (node->opcode() == IrOpcode::kPhi) continue;
639 int uses = node->UseCount();
640 PrintIndent();
641 os_ << "0 " << uses << " ";
642 PrintNode(node);
643 if (FLAG_trace_turbo_types) {
644 os_ << " ";
645 PrintType(node);
646 }
647 if (positions != NULL) {
648 SourcePosition position = positions->GetSourcePosition(node);
649 if (!position.IsUnknown()) {
650 DCHECK(!position.IsInvalid());
651 os_ << " pos:" << position.raw();
652 }
653 }
654 os_ << " <|@\n";
655 }
656
657 BasicBlock::Control control = current->control();
658 if (control != BasicBlock::kNone) {
659 PrintIndent();
660 os_ << "0 0 ";
661 if (current->control_input() != NULL) {
662 PrintNode(current->control_input());
663 } else {
664 os_ << -1 - current->id().ToInt() << " Goto";
665 }
666 os_ << " ->";
667 for (BasicBlock::Successors::iterator j = current->successors_begin();
668 j != current->successors_end(); ++j) {
669 os_ << " B" << (*j)->id();
670 }
671 if (FLAG_trace_turbo_types && current->control_input() != NULL) {
672 os_ << " ";
673 PrintType(current->control_input());
674 }
675 os_ << " <|@\n";
676 }
677 }
678
679 if (instructions != NULL) {
680 Tag LIR_tag(this, "LIR");
681 for (int j = instruction_block->first_instruction_index();
682 j <= instruction_block->last_instruction_index(); j++) {
683 PrintIndent();
684 PrintableInstruction printable = {RegisterConfiguration::ArchDefault(),
685 instructions->InstructionAt(j)};
686 os_ << j << " " << printable << " <|@\n";
687 }
688 }
689 }
690}
691
692
693void GraphC1Visualizer::PrintAllocator(const char* phase,
694 const RegisterAllocator* allocator) {
695 Tag tag(this, "intervals");
696 PrintStringProperty("name", phase);
697
698 for (auto range : allocator->fixed_double_live_ranges()) {
699 PrintLiveRange(range, "fixed");
700 }
701
702 for (auto range : allocator->fixed_live_ranges()) {
703 PrintLiveRange(range, "fixed");
704 }
705
706 for (auto range : allocator->live_ranges()) {
707 PrintLiveRange(range, "object");
708 }
709}
710
711
712void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
713 if (range != NULL && !range->IsEmpty()) {
714 PrintIndent();
715 os_ << range->id() << " " << type;
716 if (range->HasRegisterAssigned()) {
717 InstructionOperand* op = range->CreateAssignedOperand(zone());
718 int assigned_reg = op->index();
719 if (op->IsDoubleRegister()) {
720 os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
721 << "\"";
722 } else {
723 DCHECK(op->IsRegister());
724 os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
725 }
726 } else if (range->IsSpilled()) {
727 int index = -1;
728 if (range->TopLevel()->HasSpillRange()) {
729 index = kMaxInt; // This hasn't been set yet.
730 } else {
731 index = range->TopLevel()->GetSpillOperand()->index();
732 }
733 if (range->TopLevel()->Kind() == DOUBLE_REGISTERS) {
734 os_ << " \"double_stack:" << index << "\"";
735 } else if (range->TopLevel()->Kind() == GENERAL_REGISTERS) {
736 os_ << " \"stack:" << index << "\"";
737 } else {
738 os_ << " \"const(nostack):" << index << "\"";
739 }
740 }
741 int parent_index = -1;
742 if (range->IsChild()) {
743 parent_index = range->parent()->id();
744 } else {
745 parent_index = range->id();
746 }
747 InstructionOperand* op = range->FirstHint();
748 int hint_index = -1;
749 if (op != NULL && op->IsUnallocated()) {
750 hint_index = UnallocatedOperand::cast(op)->virtual_register();
751 }
752 os_ << " " << parent_index << " " << hint_index;
753 UseInterval* cur_interval = range->first_interval();
754 while (cur_interval != NULL && range->Covers(cur_interval->start())) {
755 os_ << " [" << cur_interval->start().Value() << ", "
756 << cur_interval->end().Value() << "[";
757 cur_interval = cur_interval->next();
758 }
759
760 UsePosition* current_pos = range->first_pos();
761 while (current_pos != NULL) {
762 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
763 os_ << " " << current_pos->pos().Value() << " M";
764 }
765 current_pos = current_pos->next();
766 }
767
768 os_ << " \"\"\n";
769 }
770}
771
772
773std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
774 Zone tmp_zone(ac.info_->isolate());
775 GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
776 return os;
777}
778
779
780std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
781 Zone tmp_zone(ac.schedule_->zone()->isolate());
782 GraphC1Visualizer(os, &tmp_zone)
783 .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
784 return os;
785}
786
787
788std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) {
789 Zone tmp_zone(ac.allocator_->code()->zone()->isolate());
790 GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_);
791 return os;
792}
793
794const int kUnvisited = 0;
795const int kOnStack = 1;
796const int kVisited = 2;
797
798std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
799 Zone local_zone(ar.graph.zone()->isolate());
800 ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
801 ZoneStack<Node*> stack(&local_zone);
802
803 stack.push(ar.graph.end());
804 state[ar.graph.end()->id()] = kOnStack;
805 while (!stack.empty()) {
806 Node* n = stack.top();
807 bool pop = true;
808 for (Node* const i : n->inputs()) {
809 if (state[i->id()] == kUnvisited) {
810 state[i->id()] = kOnStack;
811 stack.push(i);
812 pop = false;
813 break;
814 }
815 }
816 if (pop) {
817 state[n->id()] = kVisited;
818 stack.pop();
819 os << "#" << SafeId(n) << ":" << SafeMnemonic(n) << "(";
820 int j = 0;
821 for (Node* const i : n->inputs()) {
822 if (j++ > 0) os << ", ";
823 os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
824 }
825 os << ")" << std::endl;
826 }
827 }
828 return os;
829}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000830}
831}
832} // namespace v8::internal::compiler