1 // 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
7 #include <memory>
8 #include <sstream>
9 #include <string>
10
11 #include "src/code-stubs.h"
12 #include "src/compilation-info.h"
13 #include "src/compiler/all-nodes.h"
14 #include "src/compiler/compiler-source-position-table.h"
15 #include "src/compiler/graph.h"
16 #include "src/compiler/node-properties.h"
17 #include "src/compiler/node.h"
18 #include "src/compiler/opcodes.h"
19 #include "src/compiler/operator-properties.h"
20 #include "src/compiler/operator.h"
21 #include "src/compiler/register-allocator.h"
22 #include "src/compiler/schedule.h"
23 #include "src/compiler/scheduler.h"
24 #include "src/interpreter/bytecodes.h"
25 #include "src/objects-inl.h"
26 #include "src/ostreams.h"
27
28 namespace v8 {
29 namespace internal {
30 namespace compiler {
31
GetVisualizerLogFileName(CompilationInfo * info,const char * phase,const char * suffix)32 std::unique_ptr<char[]> GetVisualizerLogFileName(CompilationInfo* info,
33 const char* phase,
34 const char* suffix) {
35 EmbeddedVector<char, 256> filename(0);
36 std::unique_ptr<char[]> debug_name = info->GetDebugName();
37 if (strlen(debug_name.get()) > 0) {
38 if (info->has_shared_info()) {
39 int attempt = info->shared_info()->opt_count();
40 SNPrintF(filename, "turbo-%s-%i", debug_name.get(), attempt);
41 } else {
42 SNPrintF(filename, "turbo-%s", debug_name.get());
43 }
44 } else if (info->has_shared_info()) {
45 int attempt = info->shared_info()->opt_count();
46 SNPrintF(filename, "turbo-%p-%i", static_cast<void*>(info), attempt);
47 } else {
48 SNPrintF(filename, "turbo-none-%s", phase);
49 }
50 EmbeddedVector<char, 256> source_file(0);
51 bool source_available = false;
52 if (FLAG_trace_file_names && info->parse_info()) {
53 Object* source_name = info->script()->name();
54 if (source_name->IsString()) {
55 String* str = String::cast(source_name);
56 if (str->length() > 0) {
57 SNPrintF(source_file, "%s", str->ToCString().get());
58 std::replace(source_file.start(),
59 source_file.start() + source_file.length(), '/', '_');
60 source_available = true;
61 }
62 }
63 }
64 std::replace(filename.start(), filename.start() + filename.length(), ' ',
65 '_');
66
67 EmbeddedVector<char, 256> full_filename;
68 if (phase == nullptr && !source_available) {
69 SNPrintF(full_filename, "%s.%s", filename.start(), suffix);
70 } else if (phase != nullptr && !source_available) {
71 SNPrintF(full_filename, "%s-%s.%s", filename.start(), phase, suffix);
72 } else if (phase == nullptr && source_available) {
73 SNPrintF(full_filename, "%s_%s.%s", filename.start(), source_file.start(),
74 suffix);
75 } else {
76 SNPrintF(full_filename, "%s_%s-%s.%s", filename.start(),
77 source_file.start(), phase, suffix);
78 }
79
80 char* buffer = new char[full_filename.length() + 1];
81 memcpy(buffer, full_filename.start(), full_filename.length());
82 buffer[full_filename.length()] = '\0';
83 return std::unique_ptr<char[]>(buffer);
84 }
85
86
SafeId(Node * node)87 static int SafeId(Node* node) { return node == nullptr ? -1 : node->id(); }
SafeMnemonic(Node * node)88 static const char* SafeMnemonic(Node* node) {
89 return node == nullptr ? "null" : node->op()->mnemonic();
90 }
91
92 class JSONEscaped {
93 public:
JSONEscaped(const std::ostringstream & os)94 explicit JSONEscaped(const std::ostringstream& os) : str_(os.str()) {}
95
operator <<(std::ostream & os,const JSONEscaped & e)96 friend std::ostream& operator<<(std::ostream& os, const JSONEscaped& e) {
97 for (char c : e.str_) PipeCharacter(os, c);
98 return os;
99 }
100
101 private:
PipeCharacter(std::ostream & os,char c)102 static std::ostream& PipeCharacter(std::ostream& os, char c) {
103 if (c == '"') return os << "\\\"";
104 if (c == '\\') return os << "\\\\";
105 if (c == '\b') return os << "\\b";
106 if (c == '\f') return os << "\\f";
107 if (c == '\n') return os << "\\n";
108 if (c == '\r') return os << "\\r";
109 if (c == '\t') return os << "\\t";
110 return os << c;
111 }
112
113 const std::string str_;
114 };
115
116 class JSONGraphNodeWriter {
117 public:
JSONGraphNodeWriter(std::ostream & os,Zone * zone,const Graph * graph,const SourcePositionTable * positions)118 JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
119 const SourcePositionTable* positions)
120 : os_(os),
121 all_(zone, graph, false),
122 live_(zone, graph, true),
123 positions_(positions),
124 first_node_(true) {}
125
Print()126 void Print() {
127 for (Node* const node : all_.reachable) PrintNode(node);
128 os_ << "\n";
129 }
130
PrintNode(Node * node)131 void PrintNode(Node* node) {
132 if (first_node_) {
133 first_node_ = false;
134 } else {
135 os_ << ",\n";
136 }
137 std::ostringstream label, title, properties;
138 node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
139 node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
140 node->op()->PrintPropsTo(properties);
141 os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
142 << "\""
143 << ",\"title\":\"" << JSONEscaped(title) << "\""
144 << ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
145 << ",\"properties\":\"" << JSONEscaped(properties) << "\"";
146 IrOpcode::Value opcode = node->opcode();
147 if (IrOpcode::IsPhiOpcode(opcode)) {
148 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
149 << "]";
150 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
151 << "]";
152 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
153 opcode == IrOpcode::kLoop) {
154 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
155 << "]";
156 }
157 if (opcode == IrOpcode::kBranch) {
158 os_ << ",\"rankInputs\":[0]";
159 }
160 SourcePosition position = positions_->GetSourcePosition(node);
161 if (position.IsKnown()) {
162 os_ << ",\"pos\":" << position.ScriptOffset();
163 }
164 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
165 os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true"
166 : "false");
167 os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
168 << node->op()->EffectInputCount() << " eff "
169 << node->op()->ControlInputCount() << " ctrl in, "
170 << node->op()->ValueOutputCount() << " v "
171 << node->op()->EffectOutputCount() << " eff "
172 << node->op()->ControlOutputCount() << " ctrl out\"";
173 if (NodeProperties::IsTyped(node)) {
174 Type* type = NodeProperties::GetType(node);
175 std::ostringstream type_out;
176 type->PrintTo(type_out);
177 os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
178 }
179 os_ << "}";
180 }
181
182 private:
183 std::ostream& os_;
184 AllNodes all_;
185 AllNodes live_;
186 const SourcePositionTable* positions_;
187 bool first_node_;
188
189 DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter);
190 };
191
192
193 class JSONGraphEdgeWriter {
194 public:
JSONGraphEdgeWriter(std::ostream & os,Zone * zone,const Graph * graph)195 JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
196 : os_(os), all_(zone, graph, false), first_edge_(true) {}
197
Print()198 void Print() {
199 for (Node* const node : all_.reachable) PrintEdges(node);
200 os_ << "\n";
201 }
202
PrintEdges(Node * node)203 void PrintEdges(Node* node) {
204 for (int i = 0; i < node->InputCount(); i++) {
205 Node* input = node->InputAt(i);
206 if (input == nullptr) continue;
207 PrintEdge(node, i, input);
208 }
209 }
210
PrintEdge(Node * from,int index,Node * to)211 void PrintEdge(Node* from, int index, Node* to) {
212 if (first_edge_) {
213 first_edge_ = false;
214 } else {
215 os_ << ",\n";
216 }
217 const char* edge_type = nullptr;
218 if (index < NodeProperties::FirstValueIndex(from)) {
219 edge_type = "unknown";
220 } else if (index < NodeProperties::FirstContextIndex(from)) {
221 edge_type = "value";
222 } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
223 edge_type = "context";
224 } else if (index < NodeProperties::FirstEffectIndex(from)) {
225 edge_type = "frame-state";
226 } else if (index < NodeProperties::FirstControlIndex(from)) {
227 edge_type = "effect";
228 } else {
229 edge_type = "control";
230 }
231 os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
232 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
233 }
234
235 private:
236 std::ostream& os_;
237 AllNodes all_;
238 bool first_edge_;
239
240 DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter);
241 };
242
243
operator <<(std::ostream & os,const AsJSON & ad)244 std::ostream& operator<<(std::ostream& os, const AsJSON& ad) {
245 AccountingAllocator allocator;
246 Zone tmp_zone(&allocator, ZONE_NAME);
247 os << "{\n\"nodes\":[";
248 JSONGraphNodeWriter(os, &tmp_zone, &ad.graph, ad.positions).Print();
249 os << "],\n\"edges\":[";
250 JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print();
251 os << "]}";
252 return os;
253 }
254
255
256 class GraphC1Visualizer {
257 public:
258 GraphC1Visualizer(std::ostream& os, Zone* zone); // NOLINT
259
260 void PrintCompilation(const CompilationInfo* info);
261 void PrintSchedule(const char* phase, const Schedule* schedule,
262 const SourcePositionTable* positions,
263 const InstructionSequence* instructions);
264 void PrintLiveRanges(const char* phase, const RegisterAllocationData* data);
zone() const265 Zone* zone() const { return zone_; }
266
267 private:
268 void PrintIndent();
269 void PrintStringProperty(const char* name, const char* value);
270 void PrintLongProperty(const char* name, int64_t value);
271 void PrintIntProperty(const char* name, int value);
272 void PrintBlockProperty(const char* name, int rpo_number);
273 void PrintNodeId(Node* n);
274 void PrintNode(Node* n);
275 void PrintInputs(Node* n);
276 template <typename InputIterator>
277 void PrintInputs(InputIterator* i, int count, const char* prefix);
278 void PrintType(Node* node);
279
280 void PrintLiveRange(const LiveRange* range, const char* type, int vreg);
281 void PrintLiveRangeChain(const TopLevelLiveRange* range, const char* type);
282
283 class Tag final BASE_EMBEDDED {
284 public:
Tag(GraphC1Visualizer * visualizer,const char * name)285 Tag(GraphC1Visualizer* visualizer, const char* name) {
286 name_ = name;
287 visualizer_ = visualizer;
288 visualizer->PrintIndent();
289 visualizer_->os_ << "begin_" << name << "\n";
290 visualizer->indent_++;
291 }
292
~Tag()293 ~Tag() {
294 visualizer_->indent_--;
295 visualizer_->PrintIndent();
296 visualizer_->os_ << "end_" << name_ << "\n";
297 DCHECK(visualizer_->indent_ >= 0);
298 }
299
300 private:
301 GraphC1Visualizer* visualizer_;
302 const char* name_;
303 };
304
305 std::ostream& os_;
306 int indent_;
307 Zone* zone_;
308
309 DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
310 };
311
312
PrintIndent()313 void GraphC1Visualizer::PrintIndent() {
314 for (int i = 0; i < indent_; i++) {
315 os_ << " ";
316 }
317 }
318
319
GraphC1Visualizer(std::ostream & os,Zone * zone)320 GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
321 : os_(os), indent_(0), zone_(zone) {}
322
323
PrintStringProperty(const char * name,const char * value)324 void GraphC1Visualizer::PrintStringProperty(const char* name,
325 const char* value) {
326 PrintIndent();
327 os_ << name << " \"" << value << "\"\n";
328 }
329
330
PrintLongProperty(const char * name,int64_t value)331 void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
332 PrintIndent();
333 os_ << name << " " << static_cast<int>(value / 1000) << "\n";
334 }
335
336
PrintBlockProperty(const char * name,int rpo_number)337 void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
338 PrintIndent();
339 os_ << name << " \"B" << rpo_number << "\"\n";
340 }
341
342
PrintIntProperty(const char * name,int value)343 void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
344 PrintIndent();
345 os_ << name << " " << value << "\n";
346 }
347
348
PrintCompilation(const CompilationInfo * info)349 void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
350 Tag tag(this, "compilation");
351 std::unique_ptr<char[]> name = info->GetDebugName();
352 if (info->IsOptimizing()) {
353 PrintStringProperty("name", name.get());
354 PrintIndent();
355 os_ << "method \"" << name.get() << ":" << info->optimization_id()
356 << "\"\n";
357 } else {
358 PrintStringProperty("name", name.get());
359 PrintStringProperty("method", "stub");
360 }
361 PrintLongProperty("date",
362 static_cast<int64_t>(base::OS::TimeCurrentMillis()));
363 }
364
365
PrintNodeId(Node * n)366 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << SafeId(n); }
367
368
PrintNode(Node * n)369 void GraphC1Visualizer::PrintNode(Node* n) {
370 PrintNodeId(n);
371 os_ << " " << *n->op() << " ";
372 PrintInputs(n);
373 }
374
375
376 template <typename InputIterator>
PrintInputs(InputIterator * i,int count,const char * prefix)377 void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
378 const char* prefix) {
379 if (count > 0) {
380 os_ << prefix;
381 }
382 while (count > 0) {
383 os_ << " ";
384 PrintNodeId(**i);
385 ++(*i);
386 count--;
387 }
388 }
389
390
PrintInputs(Node * node)391 void GraphC1Visualizer::PrintInputs(Node* node) {
392 auto i = node->inputs().begin();
393 PrintInputs(&i, node->op()->ValueInputCount(), " ");
394 PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
395 " Ctx:");
396 PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
397 " FS:");
398 PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
399 PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
400 }
401
402
PrintType(Node * node)403 void GraphC1Visualizer::PrintType(Node* node) {
404 if (NodeProperties::IsTyped(node)) {
405 Type* type = NodeProperties::GetType(node);
406 os_ << " type:";
407 type->PrintTo(os_);
408 }
409 }
410
411
PrintSchedule(const char * phase,const Schedule * schedule,const SourcePositionTable * positions,const InstructionSequence * instructions)412 void GraphC1Visualizer::PrintSchedule(const char* phase,
413 const Schedule* schedule,
414 const SourcePositionTable* positions,
415 const InstructionSequence* instructions) {
416 Tag tag(this, "cfg");
417 PrintStringProperty("name", phase);
418 const BasicBlockVector* rpo = schedule->rpo_order();
419 for (size_t i = 0; i < rpo->size(); i++) {
420 BasicBlock* current = (*rpo)[i];
421 Tag block_tag(this, "block");
422 PrintBlockProperty("name", current->rpo_number());
423 PrintIntProperty("from_bci", -1);
424 PrintIntProperty("to_bci", -1);
425
426 PrintIndent();
427 os_ << "predecessors";
428 for (BasicBlock* predecessor : current->predecessors()) {
429 os_ << " \"B" << predecessor->rpo_number() << "\"";
430 }
431 os_ << "\n";
432
433 PrintIndent();
434 os_ << "successors";
435 for (BasicBlock* successor : current->successors()) {
436 os_ << " \"B" << successor->rpo_number() << "\"";
437 }
438 os_ << "\n";
439
440 PrintIndent();
441 os_ << "xhandlers\n";
442
443 PrintIndent();
444 os_ << "flags\n";
445
446 if (current->dominator() != nullptr) {
447 PrintBlockProperty("dominator", current->dominator()->rpo_number());
448 }
449
450 PrintIntProperty("loop_depth", current->loop_depth());
451
452 const InstructionBlock* instruction_block =
453 instructions->InstructionBlockAt(
454 RpoNumber::FromInt(current->rpo_number()));
455 if (instruction_block->code_start() >= 0) {
456 int first_index = instruction_block->first_instruction_index();
457 int last_index = instruction_block->last_instruction_index();
458 PrintIntProperty(
459 "first_lir_id",
460 LifetimePosition::GapFromInstructionIndex(first_index).value());
461 PrintIntProperty("last_lir_id",
462 LifetimePosition::InstructionFromInstructionIndex(
463 last_index).value());
464 }
465
466 {
467 Tag states_tag(this, "states");
468 Tag locals_tag(this, "locals");
469 int total = 0;
470 for (BasicBlock::const_iterator i = current->begin(); i != current->end();
471 ++i) {
472 if ((*i)->opcode() == IrOpcode::kPhi) total++;
473 }
474 PrintIntProperty("size", total);
475 PrintStringProperty("method", "None");
476 int index = 0;
477 for (BasicBlock::const_iterator i = current->begin(); i != current->end();
478 ++i) {
479 if ((*i)->opcode() != IrOpcode::kPhi) continue;
480 PrintIndent();
481 os_ << index << " ";
482 PrintNodeId(*i);
483 os_ << " [";
484 PrintInputs(*i);
485 os_ << "]\n";
486 index++;
487 }
488 }
489
490 {
491 Tag HIR_tag(this, "HIR");
492 for (BasicBlock::const_iterator i = current->begin(); i != current->end();
493 ++i) {
494 Node* node = *i;
495 if (node->opcode() == IrOpcode::kPhi) continue;
496 int uses = node->UseCount();
497 PrintIndent();
498 os_ << "0 " << uses << " ";
499 PrintNode(node);
500 if (FLAG_trace_turbo_types) {
501 os_ << " ";
502 PrintType(node);
503 }
504 if (positions != nullptr) {
505 SourcePosition position = positions->GetSourcePosition(node);
506 if (position.IsKnown()) {
507 os_ << " pos:";
508 if (position.isInlined()) {
509 os_ << "inlining(" << position.InliningId() << "),";
510 }
511 os_ << position.ScriptOffset();
512 }
513 }
514 os_ << " <|@\n";
515 }
516
517 BasicBlock::Control control = current->control();
518 if (control != BasicBlock::kNone) {
519 PrintIndent();
520 os_ << "0 0 ";
521 if (current->control_input() != nullptr) {
522 PrintNode(current->control_input());
523 } else {
524 os_ << -1 - current->rpo_number() << " Goto";
525 }
526 os_ << " ->";
527 for (BasicBlock* successor : current->successors()) {
528 os_ << " B" << successor->rpo_number();
529 }
530 if (FLAG_trace_turbo_types && current->control_input() != nullptr) {
531 os_ << " ";
532 PrintType(current->control_input());
533 }
534 os_ << " <|@\n";
535 }
536 }
537
538 if (instructions != nullptr) {
539 Tag LIR_tag(this, "LIR");
540 for (int j = instruction_block->first_instruction_index();
541 j <= instruction_block->last_instruction_index(); j++) {
542 PrintIndent();
543 PrintableInstruction printable = {RegisterConfiguration::Turbofan(),
544 instructions->InstructionAt(j)};
545 os_ << j << " " << printable << " <|@\n";
546 }
547 }
548 }
549 }
550
551
PrintLiveRanges(const char * phase,const RegisterAllocationData * data)552 void GraphC1Visualizer::PrintLiveRanges(const char* phase,
553 const RegisterAllocationData* data) {
554 Tag tag(this, "intervals");
555 PrintStringProperty("name", phase);
556
557 for (const TopLevelLiveRange* range : data->fixed_double_live_ranges()) {
558 PrintLiveRangeChain(range, "fixed");
559 }
560
561 for (const TopLevelLiveRange* range : data->fixed_live_ranges()) {
562 PrintLiveRangeChain(range, "fixed");
563 }
564
565 for (const TopLevelLiveRange* range : data->live_ranges()) {
566 PrintLiveRangeChain(range, "object");
567 }
568 }
569
PrintLiveRangeChain(const TopLevelLiveRange * range,const char * type)570 void GraphC1Visualizer::PrintLiveRangeChain(const TopLevelLiveRange* range,
571 const char* type) {
572 if (range == nullptr || range->IsEmpty()) return;
573 int vreg = range->vreg();
574 for (const LiveRange* child = range; child != nullptr;
575 child = child->next()) {
576 PrintLiveRange(child, type, vreg);
577 }
578 }
579
PrintLiveRange(const LiveRange * range,const char * type,int vreg)580 void GraphC1Visualizer::PrintLiveRange(const LiveRange* range, const char* type,
581 int vreg) {
582 if (range != nullptr && !range->IsEmpty()) {
583 PrintIndent();
584 os_ << vreg << ":" << range->relative_id() << " " << type;
585 if (range->HasRegisterAssigned()) {
586 AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
587 const auto config = RegisterConfiguration::Turbofan();
588 if (op.IsRegister()) {
589 os_ << " \"" << config->GetGeneralRegisterName(op.register_code())
590 << "\"";
591 } else if (op.IsDoubleRegister()) {
592 os_ << " \"" << config->GetDoubleRegisterName(op.register_code())
593 << "\"";
594 } else {
595 DCHECK(op.IsFloatRegister());
596 os_ << " \"" << config->GetFloatRegisterName(op.register_code())
597 << "\"";
598 }
599 } else if (range->spilled()) {
600 const TopLevelLiveRange* top = range->TopLevel();
601 int index = -1;
602 if (top->HasSpillRange()) {
603 index = kMaxInt; // This hasn't been set yet.
604 } else if (top->GetSpillOperand()->IsConstant()) {
605 os_ << " \"const(nostack):"
606 << ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
607 << "\"";
608 } else {
609 index = AllocatedOperand::cast(top->GetSpillOperand())->index();
610 if (IsFloatingPoint(top->representation())) {
611 os_ << " \"fp_stack:" << index << "\"";
612 } else {
613 os_ << " \"stack:" << index << "\"";
614 }
615 }
616 }
617
618 os_ << " " << vreg;
619 for (const UseInterval* interval = range->first_interval();
620 interval != nullptr; interval = interval->next()) {
621 os_ << " [" << interval->start().value() << ", "
622 << interval->end().value() << "[";
623 }
624
625 UsePosition* current_pos = range->first_pos();
626 while (current_pos != nullptr) {
627 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
628 os_ << " " << current_pos->pos().value() << " M";
629 }
630 current_pos = current_pos->next();
631 }
632
633 os_ << " \"\"\n";
634 }
635 }
636
637
operator <<(std::ostream & os,const AsC1VCompilation & ac)638 std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
639 AccountingAllocator allocator;
640 Zone tmp_zone(&allocator, ZONE_NAME);
641 GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
642 return os;
643 }
644
645
operator <<(std::ostream & os,const AsC1V & ac)646 std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
647 AccountingAllocator allocator;
648 Zone tmp_zone(&allocator, ZONE_NAME);
649 GraphC1Visualizer(os, &tmp_zone)
650 .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
651 return os;
652 }
653
654
operator <<(std::ostream & os,const AsC1VRegisterAllocationData & ac)655 std::ostream& operator<<(std::ostream& os,
656 const AsC1VRegisterAllocationData& ac) {
657 AccountingAllocator allocator;
658 Zone tmp_zone(&allocator, ZONE_NAME);
659 GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
660 return os;
661 }
662
663 const int kUnvisited = 0;
664 const int kOnStack = 1;
665 const int kVisited = 2;
666
operator <<(std::ostream & os,const AsRPO & ar)667 std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
668 AccountingAllocator allocator;
669 Zone local_zone(&allocator, ZONE_NAME);
670
671 // Do a post-order depth-first search on the RPO graph. For every node,
672 // print:
673 //
674 // - the node id
675 // - the operator mnemonic
676 // - in square brackets its parameter (if present)
677 // - in parentheses the list of argument ids and their mnemonics
678 // - the node type (if it is typed)
679
680 // Post-order guarantees that all inputs of a node will be printed before
681 // the node itself, if there are no cycles. Any cycles are broken
682 // arbitrarily.
683
684 ZoneVector<byte> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
685 ZoneStack<Node*> stack(&local_zone);
686
687 stack.push(ar.graph.end());
688 state[ar.graph.end()->id()] = kOnStack;
689 while (!stack.empty()) {
690 Node* n = stack.top();
691 bool pop = true;
692 for (Node* const i : n->inputs()) {
693 if (state[i->id()] == kUnvisited) {
694 state[i->id()] = kOnStack;
695 stack.push(i);
696 pop = false;
697 break;
698 }
699 }
700 if (pop) {
701 state[n->id()] = kVisited;
702 stack.pop();
703 os << "#" << n->id() << ":" << *n->op() << "(";
704 // Print the inputs.
705 int j = 0;
706 for (Node* const i : n->inputs()) {
707 if (j++ > 0) os << ", ";
708 os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
709 }
710 os << ")";
711 // Print the node type, if any.
712 if (NodeProperties::IsTyped(n)) {
713 os << " [Type: ";
714 NodeProperties::GetType(n)->PrintTo(os);
715 os << "]";
716 }
717 os << std::endl;
718 }
719 }
720 return os;
721 }
722 } // namespace compiler
723 } // namespace internal
724 } // namespace v8
725