Commit 0f5949d6 authored by sigurds@chromium.org's avatar sigurds@chromium.org

Fix scheduler to correctly schedule nested diamonds.

The scheduler rewires control based on the last *control*
node that appears in the schedule of a block. This is not
sufficient to account for dependencies.

This patch adds additional dependencies to floating control
nodes. Given a floating control node A, every non-control
dependency of every node B that depends on A is introduces
as an additional dependency of A.

This allows the scheduler to correctly schedule two
diamonds A, B, if their only correct schedule is to
schedule B into the ifTrue successor in A.

TEST=cctest/test-scheduler/NestedFloatingDiamonds
R=mstarzinger@chromium.org, titzer@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24561 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 952690a1
...@@ -34,7 +34,7 @@ Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) ...@@ -34,7 +34,7 @@ Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
schedule_(schedule), schedule_(schedule),
scheduled_nodes_(zone), scheduled_nodes_(zone),
schedule_root_nodes_(zone), schedule_root_nodes_(zone),
node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone), node_data_(graph_->NodeCount(), DefaultSchedulerData(zone), zone),
has_floating_control_(false) {} has_floating_control_(false) {}
...@@ -62,8 +62,8 @@ Schedule* Scheduler::ComputeSchedule(Graph* graph) { ...@@ -62,8 +62,8 @@ Schedule* Scheduler::ComputeSchedule(Graph* graph) {
} }
Scheduler::SchedulerData Scheduler::DefaultSchedulerData() { Scheduler::SchedulerData Scheduler::DefaultSchedulerData(Zone* zone) {
SchedulerData def = {0, -1, false, false, kUnknown}; SchedulerData def = {0, -1, false, false, kUnknown, NodeVector(zone)};
return def; return def;
} }
...@@ -182,6 +182,7 @@ class CFGBuilder { ...@@ -182,6 +182,7 @@ class CFGBuilder {
} }
} }
void BuildBlocks(Node* node) { void BuildBlocks(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kLoop: case IrOpcode::kLoop:
...@@ -395,6 +396,26 @@ class PrepareUsesVisitor : public NullNodeVisitor { ...@@ -395,6 +396,26 @@ class PrepareUsesVisitor : public NullNodeVisitor {
Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(), Trace(" Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
to->op()->mnemonic(), from->id(), from->op()->mnemonic(), to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
scheduler_->GetData(to)->unscheduled_count_); 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::SchedulerData* data = scheduler_->GetData(to);
data->additional_dependencies.push_back(*i);
++(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_);
}
}
}
} }
} }
...@@ -509,6 +530,7 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor { ...@@ -509,6 +530,7 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor {
if (schedule_->IsScheduled(node)) { if (schedule_->IsScheduled(node)) {
return GenericGraphVisit::CONTINUE; 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, data->placement_);
...@@ -611,6 +633,24 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor { ...@@ -611,6 +633,24 @@ class ScheduleLateNodeVisitor : public NullNodeVisitor {
} }
} }
} }
Scheduler::SchedulerData* data = scheduler_->GetData(node);
for (NodeVectorIter i = data->additional_dependencies.begin();
i != data->additional_dependencies.end(); ++i) {
Scheduler::SchedulerData* data = scheduler_->GetData(*i);
DCHECK(data->unscheduled_count_ > 0);
--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());
}
}
}
} }
Scheduler* scheduler_; Scheduler* scheduler_;
...@@ -669,16 +709,14 @@ bool Scheduler::ConnectFloatingControl() { ...@@ -669,16 +709,14 @@ bool Scheduler::ConnectFloatingControl() {
// TODO(titzer): we place at most one floating control structure per // TODO(titzer): we place at most one floating control structure per
// basic block because scheduling currently can interleave phis from // basic block because scheduling currently can interleave phis from
// one subgraph with the merges from another subgraph. // one subgraph with the merges from another subgraph.
bool one_placed = false;
for (size_t j = 0; j < block->NodeCount(); j++) { for (size_t j = 0; j < block->NodeCount(); j++) {
Node* node = block->NodeAt(block->NodeCount() - 1 - j); Node* node = block->NodeAt(block->NodeCount() - 1 - j);
SchedulerData* data = GetData(node); SchedulerData* data = GetData(node);
if (data->is_floating_control_ && !data->is_connected_control_ && if (data->is_floating_control_ && !data->is_connected_control_) {
!one_placed) {
Trace(" Floating control #%d:%s was scheduled in B%d\n", node->id(), Trace(" Floating control #%d:%s was scheduled in B%d\n", node->id(),
node->op()->mnemonic(), block->id().ToInt()); node->op()->mnemonic(), block->id().ToInt());
ConnectFloatingControlSubgraph(block, node); ConnectFloatingControlSubgraph(block, node);
one_placed = true; return true;
} }
} }
} }
......
...@@ -36,8 +36,9 @@ class Scheduler { ...@@ -36,8 +36,9 @@ 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_; // Whether the node is fixed, schedulable,
// or not yet known. // or not yet known.
NodeVector additional_dependencies;
}; };
Zone* zone_; Zone* zone_;
...@@ -50,7 +51,7 @@ class Scheduler { ...@@ -50,7 +51,7 @@ class Scheduler {
Scheduler(Zone* zone, Graph* graph, Schedule* schedule); Scheduler(Zone* zone, Graph* graph, Schedule* schedule);
SchedulerData DefaultSchedulerData(); SchedulerData DefaultSchedulerData(Zone* zone);
SchedulerData* GetData(Node* node) { SchedulerData* GetData(Node* node) {
DCHECK(node->id() < static_cast<int>(node_data_.size())); DCHECK(node->id() < static_cast<int>(node_data_.size()));
......
...@@ -271,6 +271,19 @@ static bool HasDominatingDef(Schedule* schedule, Node* node, ...@@ -271,6 +271,19 @@ static bool HasDominatingDef(Schedule* schedule, Node* node,
} }
static bool Dominates(Schedule* schedule, Node* dominator, Node* dominatee) {
BasicBlock* dom = schedule->block(dominator);
BasicBlock* sub = schedule->block(dominatee);
while (sub != NULL) {
if (sub == dom) {
return true;
}
sub = sub->dominator();
}
return false;
}
static void CheckInputsDominate(Schedule* schedule, BasicBlock* block, static void CheckInputsDominate(Schedule* schedule, BasicBlock* block,
Node* node, int use_pos) { Node* node, int use_pos) {
for (int j = OperatorProperties::GetValueInputCount(node->op()) - 1; j >= 0; for (int j = OperatorProperties::GetValueInputCount(node->op()) - 1; j >= 0;
...@@ -289,6 +302,19 @@ static void CheckInputsDominate(Schedule* schedule, BasicBlock* block, ...@@ -289,6 +302,19 @@ static void CheckInputsDominate(Schedule* schedule, BasicBlock* block,
input->id(), input->op()->mnemonic()); input->id(), input->op()->mnemonic());
} }
} }
// Ensure that nodes are dominated by their control inputs;
// kEnd is an exception, as unreachable blocks resulting from kMerge
// are not in the RPO.
if (OperatorProperties::GetControlInputCount(node->op()) == 1 &&
node->opcode() != IrOpcode::kEnd) {
Node* ctl = NodeProperties::GetControlInput(node);
if (!Dominates(schedule, ctl, node)) {
V8_Fatal(__FILE__, __LINE__,
"Node #%d:%s in B%d is not dominated by control input #%d:%s",
node->id(), node->op()->mnemonic(), block->id(), ctl->id(),
ctl->op()->mnemonic());
}
}
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "test/cctest/cctest.h" #include "test/cctest/cctest.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/common-operator.h" #include "src/compiler/common-operator.h"
#include "src/compiler/generic-node-inl.h" #include "src/compiler/generic-node-inl.h"
#include "src/compiler/generic-node.h" #include "src/compiler/generic-node.h"
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
#include "src/compiler/scheduler.h" #include "src/compiler/scheduler.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/verifier.h" #include "src/compiler/verifier.h"
using namespace v8::internal; using namespace v8::internal;
...@@ -1717,4 +1719,85 @@ TEST(FloatingDiamond3) { ...@@ -1717,4 +1719,85 @@ TEST(FloatingDiamond3) {
ComputeAndVerifySchedule(33, &graph); ComputeAndVerifySchedule(33, &graph);
} }
TEST(NestedFloatingDiamonds) {
HandleAndZoneScope scope;
Graph graph(scope.main_zone());
CommonOperatorBuilder common(scope.main_zone());
SimplifiedOperatorBuilder simplified(scope.main_zone());
MachineOperatorBuilder machine;
Node* start = graph.NewNode(common.Start(2));
graph.SetStart(start);
Node* p0 = graph.NewNode(common.Parameter(0), start);
Node* fv = graph.NewNode(common.Int32Constant(7));
Node* br = graph.NewNode(common.Branch(), p0, graph.start());
Node* t = graph.NewNode(common.IfTrue(), br);
Node* f = graph.NewNode(common.IfFalse(), br);
Node* map = graph.NewNode(
simplified.LoadElement(AccessBuilder::ForFixedArrayElement()), p0, p0, p0,
start, f);
Node* br1 = graph.NewNode(common.Branch(), map, graph.start());
Node* t1 = graph.NewNode(common.IfTrue(), br1);
Node* f1 = graph.NewNode(common.IfFalse(), br1);
Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
Node* ttrue = graph.NewNode(common.Int32Constant(1));
Node* ffalse = graph.NewNode(common.Int32Constant(0));
Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), ttrue, ffalse, m1);
Node* m = graph.NewNode(common.Merge(2), t, f);
Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, phi1, m);
Node* ephi1 = graph.NewNode(common.EffectPhi(2), start, map, m);
Node* ret = graph.NewNode(common.Return(), phi, ephi1, start);
Node* end = graph.NewNode(common.End(), ret, start);
graph.SetEnd(end);
ComputeAndVerifySchedule(23, &graph);
}
TEST(PhisPushedDownToDifferentBranches) {
HandleAndZoneScope scope;
Graph graph(scope.main_zone());
CommonOperatorBuilder common(scope.main_zone());
SimplifiedOperatorBuilder simplified(scope.main_zone());
MachineOperatorBuilder machine;
Node* start = graph.NewNode(common.Start(2));
graph.SetStart(start);
Node* p0 = graph.NewNode(common.Parameter(0), start);
Node* p1 = graph.NewNode(common.Parameter(1), start);
Node* v1 = graph.NewNode(common.Int32Constant(1));
Node* v2 = graph.NewNode(common.Int32Constant(2));
Node* v3 = graph.NewNode(common.Int32Constant(3));
Node* v4 = graph.NewNode(common.Int32Constant(4));
Node* br = graph.NewNode(common.Branch(), p0, graph.start());
Node* t = graph.NewNode(common.IfTrue(), br);
Node* f = graph.NewNode(common.IfFalse(), br);
Node* m = graph.NewNode(common.Merge(2), t, f);
Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), v1, v2, m);
Node* phi2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), v3, v4, m);
Node* br2 = graph.NewNode(common.Branch(), p1, graph.start());
Node* t2 = graph.NewNode(common.IfTrue(), br2);
Node* f2 = graph.NewNode(common.IfFalse(), br2);
Node* m2 = graph.NewNode(common.Merge(2), t2, f2);
Node* phi3 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phi, phi2, m2);
Node* ret = graph.NewNode(common.Return(), phi3, start, start);
Node* end = graph.NewNode(common.End(), ret, start);
graph.SetEnd(end);
ComputeAndVerifySchedule(24, &graph);
}
#endif #endif
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