| Index: src/compiler/graph-visualizer.cc
|
| diff --git a/src/compiler/graph-visualizer.cc b/src/compiler/graph-visualizer.cc
|
| index 5bd8de7aafb82e5a66e69936aa39c02f8ad52f38..4340c250b5159f947be30c54fcf649d99a9d3d90 100644
|
| --- a/src/compiler/graph-visualizer.cc
|
| +++ b/src/compiler/graph-visualizer.cc
|
| @@ -17,6 +17,9 @@
|
| #include "src/compiler/node-properties-inl.h"
|
| #include "src/compiler/opcodes.h"
|
| #include "src/compiler/operator.h"
|
| +#include "src/compiler/register-allocator.h"
|
| +#include "src/compiler/schedule.h"
|
| +#include "src/compiler/scheduler.h"
|
| #include "src/ostreams.h"
|
|
|
| namespace v8 {
|
| @@ -389,6 +392,395 @@ std::ostream& operator<<(std::ostream& os, const AsDOT& ad) {
|
| GraphVisualizer(os, &tmp_zone, &ad.graph).Print();
|
| return os;
|
| }
|
| +
|
| +
|
| +class GraphC1Visualizer {
|
| + public:
|
| + GraphC1Visualizer(std::ostream& os, Zone* zone); // NOLINT
|
| +
|
| + void PrintCompilation(const CompilationInfo* info);
|
| + void PrintSchedule(const char* phase, const Schedule* schedule,
|
| + const SourcePositionTable* positions,
|
| + const InstructionSequence* instructions);
|
| + void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
|
| + Zone* zone() const { return zone_; }
|
| +
|
| + private:
|
| + void PrintIndent();
|
| + void PrintStringProperty(const char* name, const char* value);
|
| + void PrintLongProperty(const char* name, int64_t value);
|
| + void PrintIntProperty(const char* name, int value);
|
| + void PrintBlockProperty(const char* name, BasicBlock::Id block_id);
|
| + void PrintNodeId(Node* n);
|
| + void PrintNode(Node* n);
|
| + void PrintInputs(Node* n);
|
| + void PrintInputs(InputIter* i, int count, const char* prefix);
|
| + void PrintType(Node* node);
|
| +
|
| + void PrintLiveRange(LiveRange* range, const char* type);
|
| + class Tag FINAL BASE_EMBEDDED {
|
| + public:
|
| + Tag(GraphC1Visualizer* visualizer, const char* name) {
|
| + name_ = name;
|
| + visualizer_ = visualizer;
|
| + visualizer->PrintIndent();
|
| + visualizer_->os_ << "begin_" << name << "\n";
|
| + visualizer->indent_++;
|
| + }
|
| +
|
| + ~Tag() {
|
| + visualizer_->indent_--;
|
| + visualizer_->PrintIndent();
|
| + visualizer_->os_ << "end_" << name_ << "\n";
|
| + DCHECK(visualizer_->indent_ >= 0);
|
| + }
|
| +
|
| + private:
|
| + GraphC1Visualizer* visualizer_;
|
| + const char* name_;
|
| + };
|
| +
|
| + std::ostream& os_;
|
| + int indent_;
|
| + Zone* zone_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(GraphC1Visualizer);
|
| +};
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintIndent() {
|
| + for (int i = 0; i < indent_; i++) {
|
| + os_ << " ";
|
| + }
|
| +}
|
| +
|
| +
|
| +GraphC1Visualizer::GraphC1Visualizer(std::ostream& os, Zone* zone)
|
| + : os_(os), indent_(0), zone_(zone) {}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintStringProperty(const char* name,
|
| + const char* value) {
|
| + PrintIndent();
|
| + os_ << name << " \"" << value << "\"\n";
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
|
| + PrintIndent();
|
| + os_ << name << " " << static_cast<int>(value / 1000) << "\n";
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintBlockProperty(const char* name,
|
| + BasicBlock::Id block_id) {
|
| + PrintIndent();
|
| + os_ << name << " \"B" << block_id << "\"\n";
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
|
| + PrintIndent();
|
| + os_ << name << " " << value << "\n";
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintCompilation(const CompilationInfo* info) {
|
| + Tag tag(this, "compilation");
|
| + if (info->IsOptimizing()) {
|
| + Handle<String> name = info->function()->debug_name();
|
| + PrintStringProperty("name", name->ToCString().get());
|
| + PrintIndent();
|
| + os_ << "method \"" << name->ToCString().get() << ":"
|
| + << info->optimization_id() << "\"\n";
|
| + } else {
|
| + CodeStub::Major major_key = info->code_stub()->MajorKey();
|
| + PrintStringProperty("name", CodeStub::MajorName(major_key, false));
|
| + PrintStringProperty("method", "stub");
|
| + }
|
| + PrintLongProperty("date",
|
| + static_cast<int64_t>(base::OS::TimeCurrentMillis()));
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintNodeId(Node* n) { os_ << "n" << n->id(); }
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintNode(Node* n) {
|
| + PrintNodeId(n);
|
| + os_ << " " << *n->op() << " ";
|
| + PrintInputs(n);
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintInputs(InputIter* i, int count,
|
| + const char* prefix) {
|
| + if (count > 0) {
|
| + os_ << prefix;
|
| + }
|
| + while (count > 0) {
|
| + os_ << " ";
|
| + PrintNodeId(**i);
|
| + ++(*i);
|
| + count--;
|
| + }
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintInputs(Node* node) {
|
| + InputIter i = node->inputs().begin();
|
| + PrintInputs(&i, OperatorProperties::GetValueInputCount(node->op()), " ");
|
| + PrintInputs(&i, OperatorProperties::GetContextInputCount(node->op()),
|
| + " Ctx:");
|
| + PrintInputs(&i, OperatorProperties::GetFrameStateInputCount(node->op()),
|
| + " FS:");
|
| + PrintInputs(&i, OperatorProperties::GetEffectInputCount(node->op()), " Eff:");
|
| + PrintInputs(&i, OperatorProperties::GetControlInputCount(node->op()),
|
| + " Ctrl:");
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintType(Node* node) {
|
| + Bounds bounds = NodeProperties::GetBounds(node);
|
| + os_ << " type:";
|
| + bounds.upper->PrintTo(os_);
|
| + os_ << "..";
|
| + bounds.lower->PrintTo(os_);
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintSchedule(const char* phase,
|
| + const Schedule* schedule,
|
| + const SourcePositionTable* positions,
|
| + const InstructionSequence* instructions) {
|
| + Tag tag(this, "cfg");
|
| + PrintStringProperty("name", phase);
|
| + const BasicBlockVector* rpo = schedule->rpo_order();
|
| + for (size_t i = 0; i < rpo->size(); i++) {
|
| + BasicBlock* current = (*rpo)[i];
|
| + Tag block_tag(this, "block");
|
| + PrintBlockProperty("name", current->id());
|
| + PrintIntProperty("from_bci", -1);
|
| + PrintIntProperty("to_bci", -1);
|
| +
|
| + PrintIndent();
|
| + os_ << "predecessors";
|
| + for (BasicBlock::Predecessors::iterator j = current->predecessors_begin();
|
| + j != current->predecessors_end(); ++j) {
|
| + os_ << " \"B" << (*j)->id() << "\"";
|
| + }
|
| + os_ << "\n";
|
| +
|
| + PrintIndent();
|
| + os_ << "successors";
|
| + for (BasicBlock::Successors::iterator j = current->successors_begin();
|
| + j != current->successors_end(); ++j) {
|
| + os_ << " \"B" << (*j)->id() << "\"";
|
| + }
|
| + os_ << "\n";
|
| +
|
| + PrintIndent();
|
| + os_ << "xhandlers\n";
|
| +
|
| + PrintIndent();
|
| + os_ << "flags\n";
|
| +
|
| + if (current->dominator() != NULL) {
|
| + PrintBlockProperty("dominator", current->dominator()->id());
|
| + }
|
| +
|
| + PrintIntProperty("loop_depth", current->loop_depth());
|
| +
|
| + if (current->code_start() >= 0) {
|
| + int first_index = current->first_instruction_index();
|
| + int last_index = current->last_instruction_index();
|
| + PrintIntProperty("first_lir_id", LifetimePosition::FromInstructionIndex(
|
| + first_index).Value());
|
| + PrintIntProperty("last_lir_id", LifetimePosition::FromInstructionIndex(
|
| + last_index).Value());
|
| + }
|
| +
|
| + {
|
| + Tag states_tag(this, "states");
|
| + Tag locals_tag(this, "locals");
|
| + int total = 0;
|
| + for (BasicBlock::const_iterator i = current->begin(); i != current->end();
|
| + ++i) {
|
| + if ((*i)->opcode() == IrOpcode::kPhi) total++;
|
| + }
|
| + PrintIntProperty("size", total);
|
| + PrintStringProperty("method", "None");
|
| + int index = 0;
|
| + for (BasicBlock::const_iterator i = current->begin(); i != current->end();
|
| + ++i) {
|
| + if ((*i)->opcode() != IrOpcode::kPhi) continue;
|
| + PrintIndent();
|
| + os_ << index << " ";
|
| + PrintNodeId(*i);
|
| + os_ << " [";
|
| + PrintInputs(*i);
|
| + os_ << "]\n";
|
| + index++;
|
| + }
|
| + }
|
| +
|
| + {
|
| + Tag HIR_tag(this, "HIR");
|
| + for (BasicBlock::const_iterator i = current->begin(); i != current->end();
|
| + ++i) {
|
| + Node* node = *i;
|
| + if (node->opcode() == IrOpcode::kPhi) continue;
|
| + int uses = node->UseCount();
|
| + PrintIndent();
|
| + os_ << "0 " << uses << " ";
|
| + PrintNode(node);
|
| + if (FLAG_trace_turbo_types) {
|
| + os_ << " ";
|
| + PrintType(node);
|
| + }
|
| + if (positions != NULL) {
|
| + SourcePosition position = positions->GetSourcePosition(node);
|
| + if (!position.IsUnknown()) {
|
| + DCHECK(!position.IsInvalid());
|
| + os_ << " pos:" << position.raw();
|
| + }
|
| + }
|
| + os_ << " <|@\n";
|
| + }
|
| +
|
| + BasicBlock::Control control = current->control();
|
| + if (control != BasicBlock::kNone) {
|
| + PrintIndent();
|
| + os_ << "0 0 ";
|
| + if (current->control_input() != NULL) {
|
| + PrintNode(current->control_input());
|
| + } else {
|
| + os_ << -1 - current->id().ToInt() << " Goto";
|
| + }
|
| + os_ << " ->";
|
| + for (BasicBlock::Successors::iterator j = current->successors_begin();
|
| + j != current->successors_end(); ++j) {
|
| + os_ << " B" << (*j)->id();
|
| + }
|
| + if (FLAG_trace_turbo_types && current->control_input() != NULL) {
|
| + os_ << " ";
|
| + PrintType(current->control_input());
|
| + }
|
| + os_ << " <|@\n";
|
| + }
|
| + }
|
| +
|
| + if (instructions != NULL) {
|
| + Tag LIR_tag(this, "LIR");
|
| + for (int j = current->first_instruction_index();
|
| + j <= current->last_instruction_index(); j++) {
|
| + PrintIndent();
|
| + os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n";
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintAllocator(const char* phase,
|
| + const RegisterAllocator* allocator) {
|
| + Tag tag(this, "intervals");
|
| + PrintStringProperty("name", phase);
|
| +
|
| + const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
|
| + for (int i = 0; i < fixed_d->length(); ++i) {
|
| + PrintLiveRange(fixed_d->at(i), "fixed");
|
| + }
|
| +
|
| + const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
|
| + for (int i = 0; i < fixed->length(); ++i) {
|
| + PrintLiveRange(fixed->at(i), "fixed");
|
| + }
|
| +
|
| + const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
|
| + for (int i = 0; i < live_ranges->length(); ++i) {
|
| + PrintLiveRange(live_ranges->at(i), "object");
|
| + }
|
| +}
|
| +
|
| +
|
| +void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
|
| + if (range != NULL && !range->IsEmpty()) {
|
| + PrintIndent();
|
| + os_ << range->id() << " " << type;
|
| + if (range->HasRegisterAssigned()) {
|
| + InstructionOperand* op = range->CreateAssignedOperand(zone());
|
| + int assigned_reg = op->index();
|
| + if (op->IsDoubleRegister()) {
|
| + os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
|
| + << "\"";
|
| + } else {
|
| + DCHECK(op->IsRegister());
|
| + os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
|
| + }
|
| + } else if (range->IsSpilled()) {
|
| + InstructionOperand* op = range->TopLevel()->GetSpillOperand();
|
| + if (op->IsDoubleStackSlot()) {
|
| + os_ << " \"double_stack:" << op->index() << "\"";
|
| + } else if (op->IsStackSlot()) {
|
| + os_ << " \"stack:" << op->index() << "\"";
|
| + } else {
|
| + DCHECK(op->IsConstant());
|
| + os_ << " \"const(nostack):" << op->index() << "\"";
|
| + }
|
| + }
|
| + int parent_index = -1;
|
| + if (range->IsChild()) {
|
| + parent_index = range->parent()->id();
|
| + } else {
|
| + parent_index = range->id();
|
| + }
|
| + InstructionOperand* op = range->FirstHint();
|
| + int hint_index = -1;
|
| + if (op != NULL && op->IsUnallocated()) {
|
| + hint_index = UnallocatedOperand::cast(op)->virtual_register();
|
| + }
|
| + os_ << " " << parent_index << " " << hint_index;
|
| + UseInterval* cur_interval = range->first_interval();
|
| + while (cur_interval != NULL && range->Covers(cur_interval->start())) {
|
| + os_ << " [" << cur_interval->start().Value() << ", "
|
| + << cur_interval->end().Value() << "[";
|
| + cur_interval = cur_interval->next();
|
| + }
|
| +
|
| + UsePosition* current_pos = range->first_pos();
|
| + while (current_pos != NULL) {
|
| + if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
|
| + os_ << " " << current_pos->pos().Value() << " M";
|
| + }
|
| + current_pos = current_pos->next();
|
| + }
|
| +
|
| + os_ << " \"\"\n";
|
| + }
|
| +}
|
| +
|
| +
|
| +std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
|
| + Zone tmp_zone(ac.info_->isolate());
|
| + GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
|
| + return os;
|
| +}
|
| +
|
| +
|
| +std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
|
| + Zone tmp_zone(ac.schedule_->zone()->isolate());
|
| + GraphC1Visualizer(os, &tmp_zone)
|
| + .PrintSchedule(ac.phase_, ac.schedule_, ac.positions_, ac.instructions_);
|
| + return os;
|
| +}
|
| +
|
| +
|
| +std::ostream& operator<<(std::ostream& os, const AsC1VAllocator& ac) {
|
| + Zone tmp_zone(ac.allocator_->code()->zone()->isolate());
|
| + GraphC1Visualizer(os, &tmp_zone).PrintAllocator(ac.phase_, ac.allocator_);
|
| + return os;
|
| +}
|
| }
|
| }
|
| } // namespace v8::internal::compiler
|
|
|