Commit 87668aa9 authored by Jaroslav Sevcik's avatar Jaroslav Sevcik Committed by Commit Bot

[turbofan] Make the scheduler work with non-trimmed graph.

We encode the reachability/liveness in the placement. After we prepare
use counts, the kUnknown placement means that the noe is unreachable.

Bug: v8:5267
Change-Id: Iad27159508f0aefb812b6394a257055f789fbe13
Reviewed-on: https://chromium-review.googlesource.com/646247
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47795}
parent 3972183c
......@@ -76,24 +76,28 @@ Scheduler::SchedulerData* Scheduler::GetData(Node* node) {
return &node_data_[node->id()];
}
Scheduler::Placement Scheduler::GetPlacement(Node* node) {
Scheduler::Placement Scheduler::InitializePlacement(Node* node) {
SchedulerData* data = GetData(node);
if (data->placement_ == kUnknown) { // Compute placement, once, on demand.
switch (node->opcode()) {
case IrOpcode::kParameter:
case IrOpcode::kOsrValue:
// Parameters and OSR values are always fixed to the start block.
data->placement_ = kFixed;
break;
case IrOpcode::kPhi:
case IrOpcode::kEffectPhi: {
// Phis and effect phis are fixed if their control inputs are, whereas
// otherwise they are coupled to a floating control node.
Placement p = GetPlacement(NodeProperties::GetControlInput(node));
data->placement_ = (p == kFixed ? kFixed : kCoupled);
break;
}
if (data->placement_ == kFixed) {
// Nothing to do for control nodes that have been already fixed in
// the schedule.
return data->placement_;
}
DCHECK_EQ(kUnknown, data->placement_);
switch (node->opcode()) {
case IrOpcode::kParameter:
case IrOpcode::kOsrValue:
// Parameters and OSR values are always fixed to the start block.
data->placement_ = kFixed;
break;
case IrOpcode::kPhi:
case IrOpcode::kEffectPhi: {
// Phis and effect phis are fixed if their control inputs are, whereas
// otherwise they are coupled to a floating control node.
Placement p = GetPlacement(NodeProperties::GetControlInput(node));
data->placement_ = (p == kFixed ? kFixed : kCoupled);
break;
}
#define DEFINE_CONTROL_CASE(V) case IrOpcode::k##V:
CONTROL_OP_LIST(DEFINE_CONTROL_CASE)
#undef DEFINE_CONTROL_CASE
......@@ -101,34 +105,46 @@ Scheduler::Placement Scheduler::GetPlacement(Node* node) {
// Control nodes that were not control-reachable from end may float.
data->placement_ = kSchedulable;
break;
}
default:
data->placement_ = kSchedulable;
break;
}
default:
data->placement_ = kSchedulable;
break;
}
return data->placement_;
}
Scheduler::Placement Scheduler::GetPlacement(Node* node) {
return GetData(node)->placement_;
}
bool Scheduler::IsLive(Node* node) { return GetPlacement(node) != kUnknown; }
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);
break;
}
if (data->placement_ == kUnknown) {
// We only update control nodes from {kUnknown} to {kFixed}. Ideally, we
// should check that {node} is a control node (including exceptional calls),
// but that is expensive.
DCHECK_EQ(Scheduler::kFixed, placement);
data->placement_ = placement;
return;
}
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);
break;
}
#define DEFINE_CONTROL_CASE(V) case IrOpcode::k##V:
CONTROL_OP_LIST(DEFINE_CONTROL_CASE)
#undef DEFINE_CONTROL_CASE
......@@ -139,20 +155,19 @@ void Scheduler::UpdatePlacement(Node* node, Placement placement) {
DCHECK_EQ(node, NodeProperties::GetControlInput(use));
UpdatePlacement(use, 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 (Edge const edge : node->input_edges()) {
DecrementUnscheduledUseCount(edge.to(), edge.index(), edge.from());
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 (Edge const edge : node->input_edges()) {
DecrementUnscheduledUseCount(edge.to(), edge.index(), edge.from());
}
data->placement_ = placement;
}
......@@ -1165,7 +1180,7 @@ class PrepareUsesVisitor {
: scheduler_(scheduler), schedule_(scheduler->schedule_) {}
void Pre(Node* node) {
if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
if (scheduler_->InitializePlacement(node) == Scheduler::kFixed) {
// Fixed nodes are always roots for schedule late.
scheduler_->schedule_root_nodes_.push_back(node);
if (!schedule_->IsScheduled(node)) {
......@@ -1269,7 +1284,9 @@ class ScheduleEarlyNodeVisitor {
// Propagate schedule early position.
DCHECK_NOT_NULL(data->minimum_block_);
for (auto use : node->uses()) {
PropagateMinimumPositionToNode(data->minimum_block_, use);
if (scheduler_->IsLive(use)) {
PropagateMinimumPositionToNode(data->minimum_block_, use);
}
}
}
......@@ -1455,6 +1472,7 @@ class ScheduleLateNodeVisitor {
// Check if the {node} has uses in {block}.
for (Edge edge : node->use_edges()) {
if (!scheduler_->IsLive(edge.from())) continue;
BasicBlock* use_block = GetBlockForUse(edge);
if (use_block == nullptr || marked_[use_block->id().ToSize()]) continue;
if (use_block == block) {
......@@ -1497,6 +1515,7 @@ class ScheduleLateNodeVisitor {
// the {node} itself.
ZoneMap<BasicBlock*, Node*> dominators(scheduler_->zone_);
for (Edge edge : node->use_edges()) {
if (!scheduler_->IsLive(edge.from())) continue;
BasicBlock* use_block = GetBlockForUse(edge);
if (use_block == nullptr) continue;
while (marked_[use_block->dominator()->id().ToSize()]) {
......@@ -1545,6 +1564,7 @@ class ScheduleLateNodeVisitor {
BasicBlock* GetCommonDominatorOfUses(Node* node) {
BasicBlock* block = nullptr;
for (Edge edge : node->use_edges()) {
if (!scheduler_->IsLive(edge.from())) continue;
BasicBlock* use_block = GetBlockForUse(edge);
block = block == nullptr
? use_block
......@@ -1735,7 +1755,9 @@ void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
NodeVector propagation_roots(control_flow_builder_->control_);
for (Node* node : control_flow_builder_->control_) {
for (Node* use : node->uses()) {
if (NodeProperties::IsPhi(use)) propagation_roots.push_back(use);
if (NodeProperties::IsPhi(use) && IsLive(use)) {
propagation_roots.push_back(use);
}
}
}
if (FLAG_trace_turbo_scheduler) {
......
......@@ -49,8 +49,13 @@ class V8_EXPORT_PRIVATE Scheduler {
// \ /
// +----> kSchedulable ----+--------> kScheduled
//
// 1) GetPlacement(): kUnknown -> kCoupled|kSchedulable|kFixed
// 1) InitializePlacement(): kUnknown -> kCoupled|kSchedulable|kFixed
// 2) UpdatePlacement(): kCoupled|kSchedulable -> kFixed|kScheduled
//
// We maintain the invariant that all nodes that are not reachable
// from the end have kUnknown placement. After the PrepareUses phase runs,
// also the opposite is true - all nodes with kUnknown placement are not
// reachable from the end.
enum Placement { kUnknown, kSchedulable, kFixed, kCoupled, kScheduled };
// Per-node data tracked during scheduling.
......@@ -81,7 +86,9 @@ class V8_EXPORT_PRIVATE Scheduler {
inline SchedulerData* GetData(Node* node);
Placement GetPlacement(Node* node);
Placement InitializePlacement(Node* node);
void UpdatePlacement(Node* node, Placement placement);
bool IsLive(Node* node);
inline bool IsCoupledControlEdge(Node* node, int index);
void IncrementUnscheduledUseCount(Node* node, int index, Node* from);
......
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