diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc index e07c6b990d..6a84591fc1 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(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(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 diff --git a/src/compiler/scheduler.h b/src/compiler/scheduler.h index 854e27d420..9e806814de 100644 --- a/src/compiler/scheduler.h +++ b/src/compiler/scheduler.h @@ -19,17 +19,13 @@ namespace compiler { // ordering the basic blocks in the special RPO order. class Scheduler { public: - // The complete scheduling algorithm. - // Create a new schedule and place all nodes from the graph into it. + // The complete scheduling algorithm. Creates a new schedule and places all + // nodes from the graph into it. static Schedule* ComputeSchedule(Graph* graph); // Compute the RPO of blocks in an existing schedule. static BasicBlockVector* ComputeSpecialRPO(Schedule* schedule); - // (Exposed for testing only) - // Build and connect the CFG for a node graph, but don't schedule nodes. - static void ComputeCFG(Graph* graph, Schedule* schedule); - private: enum Placement { kUnknown, kSchedulable, kFixed }; @@ -61,8 +57,6 @@ class Scheduler { return &node_data_[node->id()]; } - void BuildCFG(); - Placement GetPlacement(Node* node); int GetRPONumber(BasicBlock* block) { @@ -73,26 +67,31 @@ class Scheduler { return block->rpo_number(); } - void GenerateImmediateDominatorTree(); BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2); + // Phase 1: Build control-flow graph and dominator tree. friend class CFGBuilder; + void BuildCFG(); + void GenerateImmediateDominatorTree(); - friend class ScheduleEarlyNodeVisitor; - void ScheduleEarly(); - + // Phase 2: Prepare use counts for nodes. friend class PrepareUsesVisitor; void PrepareUses(); + // Phase 3: Schedule nodes early. + friend class ScheduleEarlyNodeVisitor; + void ScheduleEarly(); + + // Phase 4: Schedule nodes late. friend class ScheduleLateNodeVisitor; void ScheduleLate(); bool ConnectFloatingControl(); - void ConnectFloatingControlSubgraph(BasicBlock* block, Node* node); }; -} -} -} // namespace v8::internal::compiler + +} // namespace compiler +} // namespace internal +} // namespace v8 #endif // V8_COMPILER_SCHEDULER_H_