OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/graph-visualizer.h" | 5 #include "src/compiler/graph-visualizer.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "src/compiler/generic-algorithm.h" | 10 #include "src/compiler/generic-algorithm.h" |
11 #include "src/compiler/generic-node.h" | 11 #include "src/compiler/generic-node.h" |
12 #include "src/compiler/generic-node-inl.h" | 12 #include "src/compiler/generic-node-inl.h" |
13 #include "src/compiler/graph.h" | 13 #include "src/compiler/graph.h" |
14 #include "src/compiler/graph-inl.h" | 14 #include "src/compiler/graph-inl.h" |
15 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
16 #include "src/compiler/node-properties.h" | 16 #include "src/compiler/node-properties.h" |
17 #include "src/compiler/node-properties-inl.h" | 17 #include "src/compiler/node-properties-inl.h" |
18 #include "src/compiler/opcodes.h" | 18 #include "src/compiler/opcodes.h" |
19 #include "src/compiler/operator.h" | 19 #include "src/compiler/operator.h" |
20 #include "src/compiler/register-allocator.h" | |
21 #include "src/compiler/schedule.h" | |
22 #include "src/compiler/scheduler.h" | |
20 #include "src/ostreams.h" | 23 #include "src/ostreams.h" |
21 | 24 |
22 namespace v8 { | 25 namespace v8 { |
23 namespace internal { | 26 namespace internal { |
24 namespace compiler { | 27 namespace compiler { |
25 | 28 |
26 #define DEAD_COLOR "#999999" | 29 #define DEAD_COLOR "#999999" |
27 | 30 |
28 class Escaped { | 31 class Escaped { |
29 public: | 32 public: |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 use_to_def_(true), | 385 use_to_def_(true), |
383 os_(os), | 386 os_(os), |
384 graph_(graph) {} | 387 graph_(graph) {} |
385 | 388 |
386 | 389 |
387 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { | 390 std::ostream& operator<<(std::ostream& os, const AsDOT& ad) { |
388 Zone tmp_zone(ad.graph.zone()->isolate()); | 391 Zone tmp_zone(ad.graph.zone()->isolate()); |
389 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); | 392 GraphVisualizer(os, &tmp_zone, &ad.graph).Print(); |
390 return os; | 393 return os; |
391 } | 394 } |
395 | |
396 | |
397 class GraphC1Visualizer { | |
398 public: | |
399 GraphC1Visualizer(std::ostream& os, Zone* zone); // NOLINT | |
400 | |
401 void PrintCompilation(const CompilationInfo* info); | |
402 void PrintSchedule(const char* phase, const Schedule* schedule, | |
403 const InstructionSequence* instructions); | |
404 void PrintAllocator(const char* phase, const RegisterAllocator* allocator); | |
405 Zone* zone() const { return zone_; } | |
406 | |
407 private: | |
408 void PrintIndent(); | |
409 void PrintStringProperty(const char* name, const char* value); | |
410 void PrintLongProperty(const char* name, int64_t value); | |
411 void PrintIntProperty(const char* name, int value); | |
412 void PrintBlockProperty(const char* name, BasicBlock::Id block_id); | |
413 void PrintNodeId(Node* n); | |
414 void PrintNode(Node* n); | |
415 void PrintInputs(Node* n); | |
416 void PrintInputs(InputIter* i, int count, const char* prefix); | |
417 void PrintType(Node* node); | |
418 | |
419 void PrintLiveRange(LiveRange* range, const char* type); | |
420 class Tag FINAL BASE_EMBEDDED { | |
421 public: | |
422 Tag(GraphC1Visualizer* visualizer, const char* name) { | |
423 name_ = name; | |
424 visualizer_ = visualizer; | |
425 visualizer->PrintIndent(); | |
426 visualizer_->os_ << "begin_" << name << "\n"; | |
427 visualizer->indent_++; | |
428 } | |
429 | |
430 ~Tag() { | |
431 visualizer_->indent_--; | |
432 visualizer_->PrintIndent(); | |
433 visualizer_->os_ << "end_" << name_ << "\n"; | |
434 DCHECK(visualizer_->indent_ >= 0); | |
435 } | |
436 | |
437 private: | |
438 GraphC1Visualizer* visualizer_; | |
439 const char* name_; | |
440 }; | |
441 | |
442 std::ostream& os_; | |
443 int indent_; | |
444 Zone* zone_; | |
445 | |
446 DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer); | |
447 }; | |
448 | |
449 | |
450 void GraphC1Visualizer::PrintIndent() { | |
451 for (int i = 0; i < indent_; i++) { | |
452 os_ << " "; | |
453 } | |
454 } | |
455 | |
456 | |
457 GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone) | |
458 : os_(os), indent_(0), zone_(zone) {} | |
459 | |
460 | |
461 void GraphC1Visualizer::PrintStringProperty(const char* name, | |
462 const char* value) { | |
463 PrintIndent(); | |
464 os_ << name << " \"" << value << "\"\n"; | |
465 } | |
466 | |
467 | |
468 void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) { | |
469 PrintIndent(); | |
470 os_ << name << " " << static_cast<int>(value / 1000) << "\n"; | |
471 } | |
472 | |
473 | |
474 void GraphC1Visualizer::PrintBlockProperty(const char* name, | |
475 BasicBlock::Id block_id) { | |
476 PrintIndent(); | |
477 os_ << name << " \"B" << block_id << "\"\n"; | |
478 } | |
479 | |
480 | |
481 void GraphC1Visualizer::PrintIntProperty(const char* name, int value) { | |
482 PrintIndent(); | |
483 os_ << name << " " << value << "\n"; | |
484 } | |
485 | |
486 | |
487 void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) { | |
488 Tag tag(this, "compilation"); | |
489 if (info->IsOptimizing()) { | |
490 Handle<String> name = info->function()->debug_name(); | |
491 PrintStringProperty("name", name->ToCString().get()); | |
492 PrintIndent(); | |
493 os_ << "method \"" << name->ToCString().get() << ":" | |
494 << info->optimization_id() << "\"\n"; | |
495 } else { | |
496 CodeStub::Major major_key = info->code_stub()->MajorKey(); | |
497 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | |
498 PrintStringProperty("method", "stub"); | |
499 } | |
500 PrintLongProperty("date", | |
501 static_cast<int64_t>(base::OS::TimeCurrentMillis())); | |
502 } | |
503 | |
504 | |
505 void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << n->id(); } | |
506 | |
507 | |
508 void GraphC1Visualizer::PrintNode(Node* n) { | |
509 PrintNodeId(n); | |
510 os_ << " " << *n->op() << " "; | |
511 PrintInputs(n); | |
512 } | |
513 | |
514 | |
515 void GraphC1Visualizer::PrintInputs(InputIter* i, int count, | |
516 const char* prefix) { | |
517 if (count > 0) { | |
518 os_ << prefix; | |
519 } | |
520 while (count > 0) { | |
521 os_ << " "; | |
522 PrintNodeId(**i); | |
523 ++(*i); | |
524 count--; | |
525 } | |
526 } | |
527 | |
528 | |
529 void GraphC1Visualizer::PrintInputs(Node* node) { | |
530 InputIter i = node->inputs().begin(); | |
531 PrintInputs(&i, OperatorProperties::GetValueInputCount(node->op()), " "); | |
532 PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()), | |
533 " Ctx:"); | |
534 PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()), | |
535 " FS:"); | |
536 PrintInputs(&i, OperatorProperties::GetEffectInputCount(node->op()), " Eff:"); | |
537 PrintInputs(&i, OperatorProperties::GetControlInputCount(node->op()), | |
538 " Ctrl:"); | |
539 } | |
540 | |
541 | |
542 void GraphC1Visualizer::PrintType(Node* node) { | |
543 Bounds bounds = NodeProperties::GetBounds(node); | |
544 os_ << " type:"; | |
545 bounds.upper->PrintTo(os_); | |
546 os_ << ".."; | |
547 bounds.lower->PrintTo(os_); | |
548 } | |
549 | |
550 | |
551 void GraphC1Visualizer::PrintSchedule(const char* phase, | |
552 const Schedule* schedule, | |
553 const InstructionSequence* instructions) { | |
554 Tag tag(this, "cfg"); | |
555 PrintStringProperty("name", phase); | |
556 const BasicBlockVector* rpo = schedule->rpo_order(); | |
557 for (size_t i = 0; i < rpo->size(); i++) { | |
558 BasicBlock* current = (*rpo)[i]; | |
559 Tag block_tag(this, "block"); | |
560 PrintBlockProperty("name", current->id()); | |
561 PrintIntProperty("from_bci", -1); | |
562 PrintIntProperty("to_bci", -1); | |
563 | |
564 PrintIndent(); | |
565 os_ << "predecessors"; | |
566 for (BasicBlock::Predecessors::iterator j = current->predecessors_begin(); | |
567 j != current->predecessors_end(); ++j) { | |
568 os_ << " \"B" << (*j)->id() << "\""; | |
569 } | |
570 os_ << "\n"; | |
571 | |
572 PrintIndent(); | |
573 os_ << "successors"; | |
574 for (BasicBlock::Successors::iterator j = current->successors_begin(); | |
575 j != current->successors_end(); ++j) { | |
576 os_ << " \"B" << (*j)->id() << "\""; | |
577 } | |
578 os_ << "\n"; | |
579 | |
580 PrintIndent(); | |
581 os_ << "xhandlers\n"; | |
582 | |
583 PrintIndent(); | |
584 os_ << "flags\n"; | |
585 | |
586 if (current->dominator() != NULL) { | |
587 PrintBlockProperty("dominator", current->dominator()->id()); | |
588 } | |
589 | |
590 PrintIntProperty("loop_depth", current->loop_depth()); | |
591 | |
592 if (current->code_start() >= 0) { | |
593 int first_index = current->first_instruction_index(); | |
594 int last_index = current->last_instruction_index(); | |
595 PrintIntProperty("first_lir_id", LifetimePosition::FromInstructionIndex( | |
596 first_index).Value()); | |
597 PrintIntProperty("last_lir_id", LifetimePosition::FromInstructionIndex( | |
598 last_index).Value()); | |
599 } | |
600 | |
601 { | |
602 Tag states_tag(this, "states"); | |
603 Tag locals_tag(this, "locals"); | |
604 int total = 0; | |
605 for (BasicBlock::const_iterator i = current->begin(); i != current->end(); | |
606 ++i) { | |
607 if ((*i)->opcode() == IrOpcode::kPhi) total++; | |
608 } | |
609 PrintIntProperty("size", total); | |
610 PrintStringProperty("method", "None"); | |
611 int index = 0; | |
612 for (BasicBlock::const_iterator i = current->begin(); i != current->end(); | |
613 ++i) { | |
614 if ((*i)->opcode() != IrOpcode::kPhi) continue; | |
615 PrintIndent(); | |
616 os_ << index << " "; | |
617 PrintNodeId(*i); | |
618 os_ << " ["; | |
619 PrintInputs(*i); | |
620 os_ << "]\n"; | |
621 index++; | |
622 } | |
623 } | |
624 | |
625 { | |
626 Tag HIR_tag(this, "HIR"); | |
627 for (BasicBlock::const_iterator i = current->begin(); i != current->end(); | |
628 ++i) { | |
629 Node* node = *i; | |
630 int uses = node->UseCount(); | |
631 PrintIndent(); | |
632 os_ << "0 " << uses << " "; | |
633 PrintNode(node); | |
634 if (FLAG_trace_turbo_types) { | |
635 os_ << " "; | |
636 PrintType(node); | |
637 } | |
638 os_ << " <|@\n"; | |
Vyacheslav Egorov (Google)
2014/10/13 07:42:10
could you also print source position here whenever
| |
639 } | |
640 | |
641 BasicBlock::Control control = current->control(); | |
642 if (control != BasicBlock::kNone) { | |
643 PrintIndent(); | |
644 os_ << "0 0 "; | |
645 if (current->control_input() != NULL) { | |
646 PrintNode(current->control_input()); | |
647 } else { | |
648 os_ << -1 - current->id().ToInt() << " Goto"; | |
649 } | |
650 os_ << " ->"; | |
651 for (BasicBlock::Successors::iterator j = current->successors_begin(); | |
652 j != current->successors_end(); ++j) { | |
653 os_ << " B" << (*j)->id(); | |
654 } | |
655 if (FLAG_trace_turbo_types && current->control_input() != NULL) { | |
656 os_ << " "; | |
657 PrintType(current->control_input()); | |
658 } | |
659 os_ << " <|@\n"; | |
660 } | |
661 } | |
662 | |
663 if (instructions != NULL) { | |
664 Tag LIR_tag(this, "LIR"); | |
665 for (int j = current->first_instruction_index(); | |
666 j <= current->last_instruction_index(); j++) { | |
667 PrintIndent(); | |
668 os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n"; | |
669 } | |
670 } | |
671 } | |
672 } | |
673 | |
674 | |
675 void GraphC1Visualizer::PrintAllocator(const char* phase, | |
676 const RegisterAllocator* allocator) { | |
677 Tag tag(this, "intervals"); | |
678 PrintStringProperty("name", phase); | |
679 | |
680 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges(); | |
681 for (int i = 0; i < fixed_d->length(); ++i) { | |
682 PrintLiveRange(fixed_d->at(i), "fixed"); | |
683 } | |
684 | |
685 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges(); | |
686 for (int i = 0; i < fixed->length(); ++i) { | |
687 PrintLiveRange(fixed->at(i), "fixed"); | |
688 } | |
689 | |
690 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); | |
691 for (int i = 0; i < live_ranges->length(); ++i) { | |
692 PrintLiveRange(live_ranges->at(i), "object"); | |
693 } | |
694 } | |
695 | |
696 | |
697 void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) { | |
698 if (range != NULL && !range->IsEmpty()) { | |
699 PrintIndent(); | |
700 os_ << range->id() << " " << type; | |
701 if (range->HasRegisterAssigned()) { | |
702 InstructionOperand* op = range->CreateAssignedOperand(zone()); | |
703 int assigned_reg = op->index(); | |
704 if (op->IsDoubleRegister()) { | |
705 os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg) | |
706 << "\""; | |
707 } else { | |
708 DCHECK(op->IsRegister()); | |
709 os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\""; | |
710 } | |
711 } else if (range->IsSpilled()) { | |
712 InstructionOperand* op = range->TopLevel()->GetSpillOperand(); | |
713 if (op->IsDoubleStackSlot()) { | |
714 os_ << " \"double_stack:" << op->index() << "\""; | |
715 } else if (op->IsStackSlot()) { | |
716 os_ << " \"stack:" << op->index() << "\""; | |
717 } else { | |
718 DCHECK(op->IsConstant()); | |
719 os_ << " \"const(nostack):" << op->index() << "\""; | |
720 } | |
721 } | |
722 int parent_index = -1; | |
723 if (range->IsChild()) { | |
724 parent_index = range->parent()->id(); | |
725 } else { | |
726 parent_index = range->id(); | |
727 } | |
728 InstructionOperand* op = range->FirstHint(); | |
729 int hint_index = -1; | |
730 if (op != NULL && op->IsUnallocated()) { | |
731 hint_index = UnallocatedOperand::cast(op)->virtual_register(); | |
732 } | |
733 os_ << " " << parent_index << " " << hint_index; | |
734 UseInterval* cur_interval = range->first_interval(); | |
735 while (cur_interval != NULL && range->Covers(cur_interval->start())) { | |
736 os_ << " [" << cur_interval->start().Value() << ", " | |
737 << cur_interval->end().Value() << "["; | |
738 cur_interval = cur_interval->next(); | |
739 } | |
740 | |
741 UsePosition* current_pos = range->first_pos(); | |
742 while (current_pos != NULL) { | |
743 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { | |
744 os_ << " " << current_pos->pos().Value() << " M"; | |
745 } | |
746 current_pos = current_pos->next(); | |
747 } | |
748 | |
749 os_ << " \"\"\n"; | |
750 } | |
751 } | |
752 | |
753 | |
754 std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) { | |
755 Zone tmp_zone(ac.info_->isolate()); | |
756 GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_); | |
757 return os; | |
758 } | |
759 | |
760 | |
761 std::ostream& operator<<(std::ostream& os, const AsC1V& ac) { | |
762 Zone tmp_zone(ac.schedule_->zone()->isolate()); | |
763 GraphC1Visualizer(os, &tmp_zone) | |
764 .PrintSchedule(ac.phase_, ac.schedule_, ac.instructions_); | |
765 return os; | |
766 } | |
767 | |
768 | |
769 std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) { | |
770 Zone tmp_zone(ac.allocator_->code()->zone()->isolate()); | |
771 GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_); | |
772 return os; | |
773 } | |
392 } | 774 } |
393 } | 775 } |
394 } // namespace v8::internal::compiler | 776 } // namespace v8::internal::compiler |
OLD | NEW |