Make sure floating phi nodes are coupled to their control.

R=jarin@chromium.org

Review URL: https://codereview.chromium.org/669683002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0c4f8bc6
...@@ -70,6 +70,12 @@ Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { ...@@ -70,6 +70,12 @@ Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
} }
Scheduler::SchedulerData* Scheduler::GetData(Node* node) {
DCHECK(node->id() < static_cast<int>(node_data_.size()));
return &node_data_[node->id()];
}
Scheduler::Placement Scheduler::GetPlacement(Node* node) { Scheduler::Placement Scheduler::GetPlacement(Node* node) {
SchedulerData* data = GetData(node); SchedulerData* data = GetData(node);
if (data->placement_ == kUnknown) { // Compute placement, once, on demand. if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
...@@ -80,8 +86,10 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) { ...@@ -80,8 +86,10 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) {
break; break;
case IrOpcode::kPhi: case IrOpcode::kPhi:
case IrOpcode::kEffectPhi: { case IrOpcode::kEffectPhi: {
// Phis and effect phis are fixed if their control inputs are. // Phis and effect phis are fixed if their control inputs are, whereas
data->placement_ = GetPlacement(NodeProperties::GetControlInput(node)); // otherwise they are coupled to a floating control node.
Placement p = GetPlacement(NodeProperties::GetControlInput(node));
data->placement_ = (p == kFixed ? kFixed : kCoupled);
break; break;
} }
#define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V: #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
...@@ -93,6 +101,8 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) { ...@@ -93,6 +101,8 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) {
if (!data->is_connected_control_) { if (!data->is_connected_control_) {
data->is_floating_control_ = true; data->is_floating_control_ = true;
has_floating_control_ = true; has_floating_control_ = true;
// TODO(mstarzinger): Workaround to fix visitation order.
schedule_root_nodes_.push_back(node);
Trace("Floating control found: #%d:%s\n", node->id(), Trace("Floating control found: #%d:%s\n", node->id(),
node->op()->mnemonic()); node->op()->mnemonic());
} }
...@@ -107,6 +117,48 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) { ...@@ -107,6 +117,48 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) {
} }
void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) {
if (GetPlacement(node) == kCoupled) {
// Use count for coupled nodes is summed up on their control.
Node* control = NodeProperties::GetControlInput(node);
return IncrementUnscheduledUseCount(control, from);
}
++(GetData(node)->unscheduled_count_);
if (FLAG_trace_turbo_scheduler) {
Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(),
node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
GetData(node)->unscheduled_count_);
}
}
void Scheduler::DecrementUnscheduledUseCount(Node* node, Node* from) {
if (GetPlacement(node) == kCoupled) {
// Use count for coupled nodes is summed up on their control.
Node* control = NodeProperties::GetControlInput(node);
return DecrementUnscheduledUseCount(control, from);
}
DCHECK(GetData(node)->unscheduled_count_ > 0);
--(GetData(node)->unscheduled_count_);
if (FLAG_trace_turbo_scheduler) {
Trace(" Use count of #%d:%s (used by #%d:%s)-- = %d\n", node->id(),
node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
GetData(node)->unscheduled_count_);
if (GetData(node)->unscheduled_count_ == 0) {
Trace(" newly eligible #%d:%s\n", node->id(), node->op()->mnemonic());
}
}
}
int Scheduler::GetRPONumber(BasicBlock* block) {
DCHECK(block->rpo_number() >= 0 &&
block->rpo_number() < static_cast<int>(schedule_->rpo_order_.size()));
DCHECK(schedule_->rpo_order_[block->rpo_number()] == block);
return block->rpo_number();
}
BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) { BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
while (b1 != b2) { while (b1 != b2) {
int b1_rpo = GetRPONumber(b1); int b1_rpo = GetRPONumber(b1);
...@@ -399,28 +451,7 @@ class PrepareUsesVisitor : public NullNodeVisitor { ...@@ -399,28 +451,7 @@ class PrepareUsesVisitor : public NullNodeVisitor {
// for decrementing use counts. // for decrementing use counts.
if (!schedule_->IsScheduled(from)) { if (!schedule_->IsScheduled(from)) {
DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from)); DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
++(scheduler_->GetData(to)->unscheduled_count_); scheduler_->IncrementUnscheduledUseCount(to, from);
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_);
if (OperatorProperties::IsBasicBlockBegin(to->op()) &&
(from->opcode() == IrOpcode::kEffectPhi ||
from->opcode() == IrOpcode::kPhi) &&
scheduler_->GetData(to)->is_floating_control_ &&
!scheduler_->GetData(to)->is_connected_control_) {
for (InputIter i = from->inputs().begin(); i != from->inputs().end();
++i) {
if (!NodeProperties::IsControlEdge(i.edge())) {
++(scheduler_->GetData(*i)->unscheduled_count_);
Trace(
" Use count of #%d:%s (additional dependency of #%d:%s)++ = "
"%d\n",
(*i)->id(), (*i)->op()->mnemonic(), to->id(),
to->op()->mnemonic(),
scheduler_->GetData(*i)->unscheduled_count_);
}
}
}
} }
} }
...@@ -532,8 +563,15 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor { ...@@ -532,8 +563,15 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor {
return GenericGraphVisit::CONTINUE; return GenericGraphVisit::CONTINUE;
} }
// Don't schedule coupled nodes on their own.
if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
Node* control = NodeProperties::GetControlInput(node);
scheduler_->DecrementUnscheduledUseCount(control, node);
return GenericGraphVisit::CONTINUE;
}
Scheduler::SchedulerData* data = scheduler_->GetData(node); Scheduler::SchedulerData* data = scheduler_->GetData(node);
DCHECK_EQ(Scheduler::kSchedulable, data->placement_); DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node));
// If all the uses of a node have been scheduled, then the node itself can // If all the uses of a node have been scheduled, then the node itself can
// be scheduled. // be scheduled.
...@@ -544,23 +582,14 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor { ...@@ -544,23 +582,14 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor {
// Determine the dominating block for all of the uses of this node. It is // Determine the dominating block for all of the uses of this node. It is
// the latest block that this node can be scheduled in. // the latest block that this node can be scheduled in.
BasicBlock* block = NULL; BasicBlock* block = GetCommonDominatorOfUses(node);
for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end(); DCHECK_NE(NULL, block);
++i) {
BasicBlock* use_block = GetBlockForUse(i.edge());
block = block == NULL ? use_block : use_block == NULL
? block
: scheduler_->GetCommonDominator(
block, use_block);
}
DCHECK(block != NULL);
int min_rpo = data->minimum_block_->rpo_number(); int min_rpo = data->minimum_block_->rpo_number();
Trace( Trace("Schedule late of #%d:%s is B%d at loop depth %d, minimum_rpo = %d\n",
"Schedule late conservative for #%d:%s is B%d at loop depth %d, " node->id(), node->op()->mnemonic(), block->id().ToInt(),
"minimum_rpo = %d\n", block->loop_depth(), min_rpo);
node->id(), node->op()->mnemonic(), block->id().ToInt(),
block->loop_depth(), min_rpo);
// Hoist nodes out of loops if possible. Nodes can be hoisted iteratively // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
// into enclosing loop pre-headers until they would preceed their // into enclosing loop pre-headers until they would preceed their
// ScheduleEarly position. // ScheduleEarly position.
...@@ -591,20 +620,40 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor { ...@@ -591,20 +620,40 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor {
} }
private: private:
BasicBlock* GetCommonDominatorOfUses(Node* node) {
BasicBlock* block = NULL;
Node::Uses uses = node->uses();
for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
BasicBlock* use_block = GetBlockForUse(i.edge());
block = block == NULL ? use_block : use_block == NULL
? block
: scheduler_->GetCommonDominator(
block, use_block);
}
return block;
}
BasicBlock* GetBlockForUse(Node::Edge edge) { BasicBlock* GetBlockForUse(Node::Edge edge) {
Node* use = edge.from(); Node* use = edge.from();
IrOpcode::Value opcode = use->opcode(); IrOpcode::Value opcode = use->opcode();
if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
// 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(),
use->op()->mnemonic());
DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
return GetCommonDominatorOfUses(use);
}
// If the use is from a fixed (i.e. non-floating) phi, use the block // If the use is from a fixed (i.e. non-floating) phi, use the block
// of the corresponding control input to the merge. // of the corresponding control input to the merge.
int index = edge.index();
if (scheduler_->GetPlacement(use) == Scheduler::kFixed) { if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
Trace(" input@%d into a fixed phi #%d:%s\n", index, use->id(), Trace(" input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
use->op()->mnemonic()); use->op()->mnemonic());
Node* merge = NodeProperties::GetControlInput(use, 0); Node* merge = NodeProperties::GetControlInput(use, 0);
opcode = merge->opcode(); opcode = merge->opcode();
DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop); DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
use = NodeProperties::GetControlInput(merge, index); use = NodeProperties::GetControlInput(merge, edge.index());
} }
} }
BasicBlock* result = schedule_->block(use); BasicBlock* result = schedule_->block(use);
...@@ -621,41 +670,7 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor { ...@@ -621,41 +670,7 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor {
// Reduce the use count of the node's inputs to potentially make them // Reduce the use count of the node's inputs to potentially make them
// schedulable. // schedulable.
for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) { for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
Scheduler::SchedulerData* data = scheduler_->GetData(*i); scheduler_->DecrementUnscheduledUseCount(*i, i.edge().from());
DCHECK(data->unscheduled_count_ > 0);
--data->unscheduled_count_;
if (FLAG_trace_turbo_scheduler) {
Trace(" Use count for #%d:%s (used by #%d:%s)-- = %d\n", (*i)->id(),
(*i)->op()->mnemonic(), i.edge().from()->id(),
i.edge().from()->op()->mnemonic(), data->unscheduled_count_);
if (data->unscheduled_count_ == 0) {
Trace(" newly eligible #%d:%s\n", (*i)->id(),
(*i)->op()->mnemonic());
}
}
}
for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
Node* use = *i;
if (use->opcode() == IrOpcode::kPhi ||
use->opcode() == IrOpcode::kEffectPhi) {
Node* control = NodeProperties::GetControlInput(use);
Scheduler::SchedulerData* data = scheduler_->GetData(control);
if (data->is_floating_control_ && !data->is_connected_control_) {
--data->unscheduled_count_;
if (FLAG_trace_turbo_scheduler) {
Trace(
" Use count for #%d:%s (additional dependency of #%d:%s)-- = "
"%d\n",
(*i)->id(), (*i)->op()->mnemonic(), node->id(),
node->op()->mnemonic(), data->unscheduled_count_);
if (data->unscheduled_count_ == 0) {
Trace(" newly eligible #%d:%s\n", (*i)->id(),
(*i)->op()->mnemonic());
}
}
}
}
} }
} }
......
...@@ -29,7 +29,7 @@ class Scheduler { ...@@ -29,7 +29,7 @@ class Scheduler {
Schedule* schedule); Schedule* schedule);
private: private:
enum Placement { kUnknown, kSchedulable, kFixed }; enum Placement { kUnknown, kSchedulable, kFixed, kCoupled };
// Per-node data tracked during scheduling. // Per-node data tracked during scheduling.
struct SchedulerData { struct SchedulerData {
...@@ -38,8 +38,8 @@ class Scheduler { ...@@ -38,8 +38,8 @@ class Scheduler {
bool is_connected_control_; // {true} if control-connected to the end node. bool is_connected_control_; // {true} if control-connected to the end node.
bool is_floating_control_; // {true} if control, but not control-connected bool is_floating_control_; // {true} if control, but not control-connected
// to the end node. // to the end node.
Placement placement_ : 3; // Whether the node is fixed, schedulable, Placement placement_ : 2; // Whether the node is fixed, schedulable,
// or not yet known. // coupled to another node, or not yet known.
}; };
ZonePool* zone_pool_; ZonePool* zone_pool_;
...@@ -53,23 +53,15 @@ class Scheduler { ...@@ -53,23 +53,15 @@ class Scheduler {
Scheduler(ZonePool* zone_pool, Zone* zone, Graph* graph, Schedule* schedule); Scheduler(ZonePool* zone_pool, Zone* zone, Graph* graph, Schedule* schedule);
SchedulerData DefaultSchedulerData(); inline SchedulerData DefaultSchedulerData();
inline SchedulerData* GetData(Node* node);
SchedulerData* GetData(Node* node) {
DCHECK(node->id() < static_cast<int>(node_data_.size()));
return &node_data_[node->id()];
}
Placement GetPlacement(Node* node); Placement GetPlacement(Node* node);
int GetRPONumber(BasicBlock* block) { void IncrementUnscheduledUseCount(Node* node, Node* from);
DCHECK(block->rpo_number() >= 0 && void DecrementUnscheduledUseCount(Node* node, Node* from);
block->rpo_number() <
static_cast<int>(schedule_->rpo_order_.size()));
DCHECK(schedule_->rpo_order_[block->rpo_number()] == block);
return block->rpo_number();
}
inline int GetRPONumber(BasicBlock* block);
BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2); BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2);
// Phase 1: Build control-flow graph and dominator tree. // Phase 1: Build control-flow graph and dominator tree.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment