| Index: src/compiler/scheduler.cc
|
| diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
|
| index e07c6b990db0497648bdfefd984e5a9f11eb72c6..6a84591fc1b548ae865bbe58ea176854df315724 100644
|
| --- a/src/compiler/scheduler.cc
|
| +++ b/src/compiler/scheduler.cc
|
| @@ -28,6 +28,102 @@ static inline void Trace(const char* msg, ...) {
|
| }
|
|
|
|
|
| +Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
|
| + : zone_(zone),
|
| + graph_(graph),
|
| + schedule_(schedule),
|
| + scheduled_nodes_(zone),
|
| + schedule_root_nodes_(zone),
|
| + node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
|
| + has_floating_control_(false) {}
|
| +
|
| +
|
| +Schedule* Scheduler::ComputeSchedule(Graph* graph) {
|
| + Schedule* schedule;
|
| + bool had_floating_control = false;
|
| + do {
|
| + Zone tmp_zone(graph->zone()->isolate());
|
| + schedule = new (graph->zone())
|
| + Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
|
| + Scheduler scheduler(&tmp_zone, graph, schedule);
|
| +
|
| + scheduler.BuildCFG();
|
| + Scheduler::ComputeSpecialRPO(schedule);
|
| + scheduler.GenerateImmediateDominatorTree();
|
| +
|
| + scheduler.PrepareUses();
|
| + scheduler.ScheduleEarly();
|
| + scheduler.ScheduleLate();
|
| +
|
| + had_floating_control = scheduler.ConnectFloatingControl();
|
| + } while (had_floating_control);
|
| +
|
| + return schedule;
|
| +}
|
| +
|
| +
|
| +Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
|
| + SchedulerData def = {0, -1, false, false, kUnknown};
|
| + return def;
|
| +}
|
| +
|
| +
|
| +Scheduler::Placement Scheduler::GetPlacement(Node* node) {
|
| + SchedulerData* data = GetData(node);
|
| + if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
|
| + switch (node->opcode()) {
|
| + case IrOpcode::kParameter:
|
| + // Parameters are always fixed to the start node.
|
| + data->placement_ = kFixed;
|
| + break;
|
| + case IrOpcode::kPhi:
|
| + case IrOpcode::kEffectPhi: {
|
| + // Phis and effect phis are fixed if their control inputs are.
|
| + data->placement_ = GetPlacement(NodeProperties::GetControlInput(node));
|
| + break;
|
| + }
|
| +#define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
|
| + CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
|
| +#undef DEFINE_FLOATING_CONTROL_CASE
|
| + {
|
| + // Control nodes that were not control-reachable from end may float.
|
| + data->placement_ = kSchedulable;
|
| + if (!data->is_connected_control_) {
|
| + data->is_floating_control_ = true;
|
| + has_floating_control_ = true;
|
| + Trace("Floating control found: #%d:%s\n", node->id(),
|
| + node->op()->mnemonic());
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + data->placement_ = kSchedulable;
|
| + break;
|
| + }
|
| + }
|
| + return data->placement_;
|
| +}
|
| +
|
| +
|
| +BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
|
| + while (b1 != b2) {
|
| + int b1_rpo = GetRPONumber(b1);
|
| + int b2_rpo = GetRPONumber(b2);
|
| + DCHECK(b1_rpo != b2_rpo);
|
| + if (b1_rpo < b2_rpo) {
|
| + b2 = b2->dominator();
|
| + } else {
|
| + b1 = b1->dominator();
|
| + }
|
| + }
|
| + return b1;
|
| +}
|
| +
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// Phase 1: Build control-flow graph and dominator tree.
|
| +
|
| +
|
| // Internal class to build a control flow graph (i.e the basic blocks and edges
|
| // between them within a Schedule) from the node graph.
|
| // Visits the control edges of the graph backwards from end in order to find
|
| @@ -218,84 +314,6 @@ class CFGBuilder {
|
| };
|
|
|
|
|
| -Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
|
| - SchedulerData def = {0, -1, false, false, kUnknown};
|
| - return def;
|
| -}
|
| -
|
| -
|
| -Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
|
| - : zone_(zone),
|
| - graph_(graph),
|
| - schedule_(schedule),
|
| - scheduled_nodes_(zone),
|
| - schedule_root_nodes_(zone),
|
| - node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
|
| - has_floating_control_(false) {}
|
| -
|
| -
|
| -Schedule* Scheduler::ComputeSchedule(Graph* graph) {
|
| - Schedule* schedule;
|
| - bool had_floating_control = false;
|
| - do {
|
| - Zone tmp_zone(graph->zone()->isolate());
|
| - schedule = new (graph->zone())
|
| - Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
|
| - Scheduler scheduler(&tmp_zone, graph, schedule);
|
| -
|
| - scheduler.BuildCFG();
|
| -
|
| - Scheduler::ComputeSpecialRPO(schedule);
|
| - scheduler.GenerateImmediateDominatorTree();
|
| -
|
| - scheduler.PrepareUses();
|
| - scheduler.ScheduleEarly();
|
| - scheduler.ScheduleLate();
|
| -
|
| - had_floating_control = scheduler.ConnectFloatingControl();
|
| - } while (had_floating_control);
|
| -
|
| - return schedule;
|
| -}
|
| -
|
| -
|
| -Scheduler::Placement Scheduler::GetPlacement(Node* node) {
|
| - SchedulerData* data = GetData(node);
|
| - if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
|
| - switch (node->opcode()) {
|
| - case IrOpcode::kParameter:
|
| - // Parameters are always fixed to the start node.
|
| - data->placement_ = kFixed;
|
| - break;
|
| - case IrOpcode::kPhi:
|
| - case IrOpcode::kEffectPhi: {
|
| - // Phis and effect phis are fixed if their control inputs are.
|
| - data->placement_ = GetPlacement(NodeProperties::GetControlInput(node));
|
| - break;
|
| - }
|
| -#define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
|
| - CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
|
| -#undef DEFINE_FLOATING_CONTROL_CASE
|
| - {
|
| - // Control nodes that were not control-reachable from end may float.
|
| - data->placement_ = kSchedulable;
|
| - if (!data->is_connected_control_) {
|
| - data->is_floating_control_ = true;
|
| - has_floating_control_ = true;
|
| - Trace("Floating control found: #%d:%s\n", node->id(),
|
| - node->op()->mnemonic());
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - data->placement_ = kSchedulable;
|
| - break;
|
| - }
|
| - }
|
| - return data->placement_;
|
| -}
|
| -
|
| -
|
| void Scheduler::BuildCFG() {
|
| Trace("---------------- CREATING CFG ------------------\n");
|
| CFGBuilder cfg_builder(zone_, this);
|
| @@ -305,21 +323,6 @@ void Scheduler::BuildCFG() {
|
| }
|
|
|
|
|
| -BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
|
| - while (b1 != b2) {
|
| - int b1_rpo = GetRPONumber(b1);
|
| - int b2_rpo = GetRPONumber(b2);
|
| - DCHECK(b1_rpo != b2_rpo);
|
| - if (b1_rpo < b2_rpo) {
|
| - b2 = b2->dominator();
|
| - } else {
|
| - b1 = b1->dominator();
|
| - }
|
| - }
|
| - return b1;
|
| -}
|
| -
|
| -
|
| void Scheduler::GenerateImmediateDominatorTree() {
|
| // Build the dominator graph. TODO(danno): consider using Lengauer & Tarjan's
|
| // if this becomes really slow.
|
| @@ -352,6 +355,69 @@ void Scheduler::GenerateImmediateDominatorTree() {
|
| }
|
|
|
|
|
| +// -----------------------------------------------------------------------------
|
| +// Phase 2: Prepare use counts for nodes.
|
| +
|
| +
|
| +class PrepareUsesVisitor : public NullNodeVisitor {
|
| + public:
|
| + explicit PrepareUsesVisitor(Scheduler* scheduler)
|
| + : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
|
| +
|
| + GenericGraphVisit::Control Pre(Node* node) {
|
| + if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
|
| + // Fixed nodes are always roots for schedule late.
|
| + scheduler_->schedule_root_nodes_.push_back(node);
|
| + if (!schedule_->IsScheduled(node)) {
|
| + // Make sure root nodes are scheduled in their respective blocks.
|
| + Trace(" Scheduling fixed position node #%d:%s\n", node->id(),
|
| + node->op()->mnemonic());
|
| + IrOpcode::Value opcode = node->opcode();
|
| + BasicBlock* block =
|
| + opcode == IrOpcode::kParameter
|
| + ? schedule_->start()
|
| + : schedule_->block(NodeProperties::GetControlInput(node));
|
| + DCHECK(block != NULL);
|
| + schedule_->AddNode(block, node);
|
| + }
|
| + }
|
| +
|
| + return GenericGraphVisit::CONTINUE;
|
| + }
|
| +
|
| + void PostEdge(Node* from, int index, Node* to) {
|
| + // If the edge is from an unscheduled node, then tally it in the use count
|
| + // for all of its inputs. The same criterion will be used in ScheduleLate
|
| + // for decrementing use counts.
|
| + if (!schedule_->IsScheduled(from)) {
|
| + DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
|
| + ++(scheduler_->GetData(to)->unscheduled_count_);
|
| + Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
|
| + to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
|
| + scheduler_->GetData(to)->unscheduled_count_);
|
| + }
|
| + }
|
| +
|
| + private:
|
| + Scheduler* scheduler_;
|
| + Schedule* schedule_;
|
| +};
|
| +
|
| +
|
| +void Scheduler::PrepareUses() {
|
| + Trace("------------------- PREPARE USES ------------------\n");
|
| +
|
| + // Count the uses of every node, it will be used to ensure that all of a
|
| + // node's uses are scheduled before the node itself.
|
| + PrepareUsesVisitor prepare_uses(this);
|
| + graph_->VisitNodeInputsFromEnd(&prepare_uses);
|
| +}
|
| +
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// Phase 3: Schedule nodes early.
|
| +
|
| +
|
| class ScheduleEarlyNodeVisitor : public NullNodeVisitor {
|
| public:
|
| explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler)
|
| @@ -429,59 +495,8 @@ void Scheduler::ScheduleEarly() {
|
| }
|
|
|
|
|
| -class PrepareUsesVisitor : public NullNodeVisitor {
|
| - public:
|
| - explicit PrepareUsesVisitor(Scheduler* scheduler)
|
| - : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
|
| -
|
| - GenericGraphVisit::Control Pre(Node* node) {
|
| - if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
|
| - // Fixed nodes are always roots for schedule late.
|
| - scheduler_->schedule_root_nodes_.push_back(node);
|
| - if (!schedule_->IsScheduled(node)) {
|
| - // Make sure root nodes are scheduled in their respective blocks.
|
| - Trace(" Scheduling fixed position node #%d:%s\n", node->id(),
|
| - node->op()->mnemonic());
|
| - IrOpcode::Value opcode = node->opcode();
|
| - BasicBlock* block =
|
| - opcode == IrOpcode::kParameter
|
| - ? schedule_->start()
|
| - : schedule_->block(NodeProperties::GetControlInput(node));
|
| - DCHECK(block != NULL);
|
| - schedule_->AddNode(block, node);
|
| - }
|
| - }
|
| -
|
| - return GenericGraphVisit::CONTINUE;
|
| - }
|
| -
|
| - void PostEdge(Node* from, int index, Node* to) {
|
| - // If the edge is from an unscheduled node, then tally it in the use count
|
| - // for all of its inputs. The same criterion will be used in ScheduleLate
|
| - // for decrementing use counts.
|
| - if (!schedule_->IsScheduled(from)) {
|
| - DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
|
| - ++(scheduler_->GetData(to)->unscheduled_count_);
|
| - Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
|
| - to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
|
| - scheduler_->GetData(to)->unscheduled_count_);
|
| - }
|
| - }
|
| -
|
| - private:
|
| - Scheduler* scheduler_;
|
| - Schedule* schedule_;
|
| -};
|
| -
|
| -
|
| -void Scheduler::PrepareUses() {
|
| - Trace("------------------- PREPARE USES ------------------\n");
|
| -
|
| - // Count the uses of every node, it will be used to ensure that all of a
|
| - // node's uses are scheduled before the node itself.
|
| - PrepareUsesVisitor prepare_uses(this);
|
| - graph_->VisitNodeInputsFromEnd(&prepare_uses);
|
| -}
|
| +// -----------------------------------------------------------------------------
|
| +// Phase 4: Schedule nodes late.
|
|
|
|
|
| class ScheduleLateNodeVisitor : public NullNodeVisitor {
|
| @@ -637,6 +652,9 @@ void Scheduler::ScheduleLate() {
|
| }
|
|
|
|
|
| +// -----------------------------------------------------------------------------
|
| +
|
| +
|
| bool Scheduler::ConnectFloatingControl() {
|
| if (!has_floating_control_) return false;
|
|
|
| @@ -1137,6 +1155,7 @@ BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) {
|
| #endif
|
| return final_order;
|
| }
|
| -}
|
| -}
|
| -} // namespace v8::internal::compiler
|
| +
|
| +} // namespace compiler
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|