Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Unified Diff: src/compiler/scheduler.cc

Issue 685773002: Switch scheduler to iterative floating control placement. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments by Jaro. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/scheduler.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/scheduler.cc
diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
index d1da320bd0d48dd23e299a2de1ff52a75f207d96..d9e67ee20a875e24f75d8f6972bc646a863e4ca7 100644
--- a/src/compiler/scheduler.cc
+++ b/src/compiler/scheduler.cc
@@ -35,29 +35,22 @@ Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
scheduled_nodes_(zone),
schedule_root_nodes_(zone),
schedule_queue_(zone),
- node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
- has_floating_control_(false) {}
+ node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone) {}
Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) {
- Schedule* schedule;
- bool had_floating_control = false;
- do {
- ZonePool::Scope zone_scope(zone_pool);
- schedule = new (graph->zone())
- Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
- Scheduler scheduler(zone_scope.zone(), graph, schedule);
-
- scheduler.BuildCFG();
- scheduler.ComputeSpecialRPONumbering();
- scheduler.GenerateImmediateDominatorTree();
+ ZonePool::Scope zone_scope(zone_pool);
+ Schedule* schedule = new (graph->zone())
+ Schedule(graph->zone(), static_cast<size_t>(graph->NodeCount()));
+ Scheduler scheduler(zone_scope.zone(), graph, schedule);
- scheduler.PrepareUses();
- scheduler.ScheduleEarly();
- scheduler.ScheduleLate();
+ scheduler.BuildCFG();
+ scheduler.ComputeSpecialRPONumbering();
+ scheduler.GenerateImmediateDominatorTree();
- had_floating_control = scheduler.ConnectFloatingControl();
- } while (had_floating_control);
+ scheduler.PrepareUses();
+ scheduler.ScheduleEarly();
+ scheduler.ScheduleLate();
return schedule;
}
@@ -92,19 +85,18 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) {
break;
}
#define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
- CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
+ 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;
+ {
+ // Control nodes that were not control-reachable from end may float.
+ data->placement_ = kSchedulable;
+ if (!data->is_connected_control_) {
+ data->is_floating_control_ = true;
+ Trace("Floating control found: #%d:%s\n", node->id(),
+ node->op()->mnemonic());
}
+ break;
+ }
default:
data->placement_ = kSchedulable;
break;
@@ -114,6 +106,60 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) {
}
+void Scheduler::UpdatePlacement(Node* node, Placement placement) {
+ SchedulerData* data = GetData(node);
+ if (data->placement_ != kUnknown) { // Trap on mutation, not initialization.
+ switch (node->opcode()) {
+ case IrOpcode::kParameter:
+ // Parameters are fixed once and for all.
+ UNREACHABLE();
+ break;
+ case IrOpcode::kPhi:
+ case IrOpcode::kEffectPhi: {
+ // Phis and effect phis are coupled to their respective blocks.
+ DCHECK_EQ(Scheduler::kCoupled, data->placement_);
+ DCHECK_EQ(Scheduler::kFixed, placement);
+ Node* control = NodeProperties::GetControlInput(node);
+ BasicBlock* block = schedule_->block(control);
+ schedule_->AddNode(block, node);
+ // TODO(mstarzinger): Cheap hack to make sure unscheduled use count of
+ // control does not drop below zero. This might cause the control to be
+ // queued for scheduling more than once, which makes this ugly!
+ ++(GetData(control)->unscheduled_count_);
+ 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 force coupled uses to be placed.
+ Node::Uses uses = node->uses();
+ for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
+ if (GetPlacement(*i) == Scheduler::kCoupled) {
+ DCHECK_EQ(node, NodeProperties::GetControlInput(*i));
+ UpdatePlacement(*i, placement);
+ }
+ }
+ break;
+ }
+ default:
+ DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
+ DCHECK_EQ(Scheduler::kScheduled, placement);
+ break;
+ }
+ // Reduce the use count of the node's inputs to potentially make them
+ // schedulable. If all the uses of a node have been scheduled, then the node
+ // itself can be scheduled.
+ for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
+ // TODO(mstarzinger): Another cheap hack for use counts.
+ if (GetData(*i)->placement_ == kFixed) continue;
+ DecrementUnscheduledUseCount(*i, i.edge().from());
+ }
+ }
+ data->placement_ = placement;
+}
+
+
void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) {
if (GetPlacement(node) == kCoupled) {
// Use count for coupled nodes is summed up on their control.
@@ -177,21 +223,19 @@ BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
// 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
-// the connected control subgraph, needed for scheduling.
+// between them within a Schedule) from the node graph. Visits control edges of
+// the graph backwards from an end node in order to find the connected control
+// subgraph, needed for scheduling.
class CFGBuilder {
public:
- Scheduler* scheduler_;
- Schedule* schedule_;
- ZoneQueue<Node*> queue_;
- NodeVector control_;
-
CFGBuilder(Zone* zone, Scheduler* scheduler)
: scheduler_(scheduler),
schedule_(scheduler->schedule_),
queue_(zone),
- control_(zone) {}
+ control_(zone),
+ component_head_(NULL),
+ component_start_(NULL),
+ component_end_(NULL) {}
// Run the control flow graph construction algorithm by walking the graph
// backwards from end through control edges, building and connecting the
@@ -217,10 +261,40 @@ class CFGBuilder {
FixNode(schedule_->end(), graph->end());
}
+ // Run the control flow graph construction for a minimal control-connected
+ // component ending in {node} and merge that component into an existing
+ // control flow graph at the bottom of {block}.
+ void Run(BasicBlock* block, Node* node) {
+ Queue(node);
+
+ component_start_ = block;
+ component_end_ = schedule_->block(node);
+ while (!queue_.empty()) { // Breadth-first backwards traversal.
+ Node* node = queue_.front();
+ queue_.pop();
+ bool is_dom = true;
+ int max = NodeProperties::PastControlIndex(node);
+ for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
+ is_dom = is_dom &&
+ !scheduler_->GetData(node->InputAt(i))->is_floating_control_;
+ Queue(node->InputAt(i));
+ }
+ // TODO(mstarzinger): This is a hacky way to find component dominator.
+ if (is_dom) component_head_ = node;
+ }
+ DCHECK_NOT_NULL(component_head_);
+
+ for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
+ scheduler_->GetData(*i)->is_floating_control_ = false;
+ ConnectBlocks(*i); // Connect block to its predecessor/successors.
+ }
+ }
+
+ private:
void FixNode(BasicBlock* block, Node* node) {
schedule_->AddNode(block, node);
scheduler_->GetData(node)->is_connected_control_ = true;
- scheduler_->GetData(node)->placement_ = Scheduler::kFixed;
+ scheduler_->UpdatePlacement(node, Scheduler::kFixed);
}
void Queue(Node* node) {
@@ -257,11 +331,11 @@ class CFGBuilder {
ConnectMerge(node);
break;
case IrOpcode::kBranch:
- scheduler_->schedule_root_nodes_.push_back(node);
+ scheduler_->UpdatePlacement(node, Scheduler::kFixed);
ConnectBranch(node);
break;
case IrOpcode::kReturn:
- scheduler_->schedule_root_nodes_.push_back(node);
+ scheduler_->UpdatePlacement(node, Scheduler::kFixed);
ConnectReturn(node);
break;
default:
@@ -318,17 +392,10 @@ class CFGBuilder {
}
void ConnectBranch(Node* branch) {
- Node* branch_block_node = NodeProperties::GetControlInput(branch);
- BasicBlock* branch_block = schedule_->block(branch_block_node);
- DCHECK(branch_block != NULL);
-
BasicBlock* successor_blocks[2];
CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue,
IrOpcode::kIfFalse);
- TraceConnect(branch, branch_block, successor_blocks[0]);
- TraceConnect(branch, branch_block, successor_blocks[1]);
-
// Consider branch hints.
// TODO(turbofan): Propagate the deferred flag to all blocks dominated by
// this IfTrue/IfFalse later.
@@ -343,8 +410,21 @@ class CFGBuilder {
break;
}
- schedule_->AddBranch(branch_block, branch, successor_blocks[0],
- successor_blocks[1]);
+ if (branch == component_head_) {
+ TraceConnect(branch, component_start_, successor_blocks[0]);
+ TraceConnect(branch, component_start_, successor_blocks[1]);
+ schedule_->InsertBranch(component_start_, component_end_, branch,
+ successor_blocks[0], successor_blocks[1]);
+ } else {
+ Node* branch_block_node = NodeProperties::GetControlInput(branch);
+ BasicBlock* branch_block = schedule_->block(branch_block_node);
+ DCHECK(branch_block != NULL);
+
+ TraceConnect(branch, branch_block, successor_blocks[0]);
+ TraceConnect(branch, branch_block, successor_blocks[1]);
+ schedule_->AddBranch(branch_block, branch, successor_blocks[0],
+ successor_blocks[1]);
+ }
}
void ConnectMerge(Node* merge) {
@@ -385,13 +465,25 @@ class CFGBuilder {
return (node->opcode() == IrOpcode::kMerge &&
node == scheduler_->graph_->end()->InputAt(0));
}
+
+ Scheduler* scheduler_;
+ Schedule* schedule_;
+ ZoneQueue<Node*> queue_;
+ NodeVector control_;
+ Node* component_head_;
+ BasicBlock* component_start_;
+ BasicBlock* component_end_;
};
void Scheduler::BuildCFG() {
Trace("--- CREATING CFG -------------------------------------------\n");
+
+ // Build a control-flow graph for the main control-connected component that
+ // is being spanned by the graph's start and end nodes.
CFGBuilder cfg_builder(zone_, this);
cfg_builder.Run();
+
// Initialize per-block data.
scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_));
}
@@ -867,7 +959,7 @@ void Scheduler::GenerateImmediateDominatorTree() {
DCHECK(current_pred != end);
BasicBlock* dominator = *current_pred;
++current_pred;
- // For multiple predecessors, walk up the rpo ordering until a common
+ // For multiple predecessors, walk up the RPO ordering until a common
// dominator is found.
int current_rpo_pos = GetRPONumber(current_rpo);
while (current_pred != end) {
@@ -1091,6 +1183,7 @@ class ScheduleLateNodeVisitor {
// Determine the dominating block for all of the uses of this node. It is
// the latest block that this node can be scheduled in.
+ Trace("Scheduling #%d:%s\n", node->id(), node->op()->mnemonic());
BasicBlock* block = GetCommonDominatorOfUses(node);
DCHECK_NOT_NULL(block);
@@ -1111,7 +1204,12 @@ class ScheduleLateNodeVisitor {
hoist_block = GetPreHeader(hoist_block);
}
- ScheduleNode(block, node);
+ // Schedule the node or a floating control structure.
+ if (NodeProperties::IsControl(node)) {
+ ScheduleFloatingControl(block, node);
+ } else {
+ ScheduleNode(block, node);
+ }
}
BasicBlock* GetPreHeader(BasicBlock* block) {
@@ -1144,7 +1242,7 @@ class ScheduleLateNodeVisitor {
// If the use is from a coupled (i.e. floating) phi, compute the common
// dominator of its uses. This will not recurse more than one level.
if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
- Trace(" inspecting uses of coupled phi #%d:%s\n", use->id(),
+ Trace(" inspecting uses of coupled #%d:%s\n", use->id(),
use->op()->mnemonic());
DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
return GetCommonDominatorOfUses(use);
@@ -1167,16 +1265,15 @@ class ScheduleLateNodeVisitor {
return result;
}
+ void ScheduleFloatingControl(BasicBlock* block, Node* node) {
+ DCHECK(scheduler_->GetData(node)->is_floating_control_);
+ scheduler_->FuseFloatingControl(block, node);
+ }
+
void ScheduleNode(BasicBlock* block, Node* node) {
schedule_->PlanNode(block, node);
scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node);
-
- // Reduce the use count of the node's inputs to potentially make them
- // schedulable. If all the uses of a node have been scheduled, then the node
- // itself can be scheduled.
- for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
- scheduler_->DecrementUnscheduledUseCount(*i, i.edge().from());
- }
+ scheduler_->UpdatePlacement(node, Scheduler::kScheduled);
}
Scheduler* scheduler_;
@@ -1214,97 +1311,53 @@ void Scheduler::ScheduleLate() {
// -----------------------------------------------------------------------------
-bool Scheduler::ConnectFloatingControl() {
- if (!has_floating_control_) return false;
-
- Trace("Connecting floating control...\n");
-
- // Process blocks and instructions backwards to find and connect floating
- // control nodes into the control graph according to the block they were
- // scheduled into.
- int max = static_cast<int>(schedule_->rpo_order()->size());
- for (int i = max - 1; i >= 0; i--) {
- BasicBlock* block = schedule_->rpo_order()->at(i);
- // TODO(titzer): we place at most one floating control structure per
- // basic block because scheduling currently can interleave phis from
- // one subgraph with the merges from another subgraph.
- for (size_t j = 0; j < block->NodeCount(); j++) {
- Node* node = block->NodeAt(block->NodeCount() - 1 - j);
- SchedulerData* data = GetData(node);
- if (data->is_floating_control_ && !data->is_connected_control_) {
- Trace(" Floating control #%d:%s was scheduled in B%d\n", node->id(),
- node->op()->mnemonic(), block->id().ToInt());
- ConnectFloatingControlSubgraph(block, node);
- break;
- }
- }
+void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
+ Trace("--- FUSE FLOATING CONTROL ----------------------------------\n");
+ if (FLAG_trace_turbo_scheduler) {
+ OFStream os(stdout);
+ os << "Schedule before control flow fusion:\n" << *schedule_;
}
- return true;
-}
+ // Iterate on phase 1: Build control-flow graph.
+ CFGBuilder cfg_builder(zone_, this);
+ cfg_builder.Run(block, node);
+
+ // Iterate on phase 2: Compute special RPO and dominator tree.
+ // TODO(mstarzinger): Currently "iterate on" means "re-run". Fix that.
+ BasicBlockVector* rpo = schedule_->rpo_order();
+ for (BasicBlockVectorIter i = rpo->begin(); i != rpo->end(); ++i) {
+ BasicBlock* block = *i;
+ block->set_rpo_number(-1);
+ block->set_loop_header(NULL);
+ block->set_loop_depth(0);
+ block->set_loop_end(-1);
+ }
+ schedule_->rpo_order()->clear();
+ SpecialRPONumberer numberer(zone_, schedule_);
+ numberer.ComputeSpecialRPO();
+ GenerateImmediateDominatorTree();
+ scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_));
+ // Move previously planned nodes.
+ // TODO(mstarzinger): Improve that by supporting bulk moves.
+ MovePlannedNodes(block, schedule_->block(node));
-void Scheduler::ConnectFloatingControlSubgraph(BasicBlock* block, Node* end) {
- Node* block_start = block->NodeAt(0);
- DCHECK(IrOpcode::IsControlOpcode(block_start->opcode()));
- // Find the current "control successor" of the node that starts the block
- // by searching the control uses for a control input edge from a connected
- // control node.
- Node* control_succ = NULL;
- for (UseIter i = block_start->uses().begin(); i != block_start->uses().end();
- ++i) {
- Node::Edge edge = i.edge();
- if (NodeProperties::IsControlEdge(edge) &&
- GetData(edge.from())->is_connected_control_) {
- DCHECK_EQ(NULL, control_succ);
- control_succ = edge.from();
- control_succ->ReplaceInput(edge.index(), end);
- }
- }
- DCHECK_NE(NULL, control_succ);
- Trace(" Inserting floating control end %d:%s between %d:%s -> %d:%s\n",
- end->id(), end->op()->mnemonic(), control_succ->id(),
- control_succ->op()->mnemonic(), block_start->id(),
- block_start->op()->mnemonic());
-
- // Find the "start" node of the control subgraph, which should be the
- // unique node that is itself floating control but has a control input that
- // is not floating.
- Node* start = NULL;
- ZoneQueue<Node*> queue(zone_);
- queue.push(end);
- GetData(end)->is_connected_control_ = true;
- while (!queue.empty()) {
- Node* node = queue.front();
- queue.pop();
- Trace(" Search #%d:%s for control subgraph start\n", node->id(),
- node->op()->mnemonic());
- int max = NodeProperties::PastControlIndex(node);
- for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
- Node* input = node->InputAt(i);
- SchedulerData* data = GetData(input);
- if (data->is_floating_control_) {
- // {input} is floating control.
- if (!data->is_connected_control_) {
- // First time seeing {input} during this traversal, queue it.
- queue.push(input);
- data->is_connected_control_ = true;
- }
- } else {
- // Otherwise, {node} is the start node, because it is floating control
- // but is connected to {input} that is not floating control.
- DCHECK_EQ(NULL, start); // There can be only one.
- start = node;
- }
- }
+ if (FLAG_trace_turbo_scheduler) {
+ OFStream os(stdout);
+ os << "Schedule after control flow fusion:" << *schedule_;
}
+}
- DCHECK_NE(NULL, start);
- start->ReplaceInput(NodeProperties::FirstControlIndex(start), block_start);
- Trace(" Connecting floating control start %d:%s to %d:%s\n", start->id(),
- start->op()->mnemonic(), block_start->id(),
- block_start->op()->mnemonic());
+void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
+ Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(),
+ to->id().ToInt());
+ NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]);
+ for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) {
+ schedule_->SetBlockForNode(to, *i);
+ scheduled_nodes_[to->id().ToSize()].push_back(*i);
+ }
+ nodes->clear();
}
} // namespace compiler
« no previous file with comments | « src/compiler/scheduler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698