| Index: src/compiler/scheduler.cc
|
| diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
|
| index a21d650ed318b86623065150027120cdf98f0fc4..4be254cd2fd12e25ab7fad686f9f58ef9a0f4484 100644
|
| --- a/src/compiler/scheduler.cc
|
| +++ b/src/compiler/scheduler.cc
|
| @@ -286,7 +286,7 @@ class CFGBuilder : public ZoneObject {
|
| }
|
|
|
| private:
|
| - // TODO(mstarzinger): Only for Scheduler::FuseFloatingControl.
|
| + friend class ScheduleLateNodeVisitor;
|
| friend class Scheduler;
|
|
|
| void FixNode(BasicBlock* block, Node* node) {
|
| @@ -320,6 +320,11 @@ class CFGBuilder : public ZoneObject {
|
| case IrOpcode::kSwitch:
|
| BuildBlocksForSuccessors(node);
|
| break;
|
| + case IrOpcode::kCall:
|
| + if (IsExceptionalCall(node)) {
|
| + BuildBlocksForSuccessors(node);
|
| + }
|
| + break;
|
| default:
|
| break;
|
| }
|
| @@ -347,6 +352,12 @@ class CFGBuilder : public ZoneObject {
|
| scheduler_->UpdatePlacement(node, Scheduler::kFixed);
|
| ConnectThrow(node);
|
| break;
|
| + case IrOpcode::kCall:
|
| + if (IsExceptionalCall(node)) {
|
| + scheduler_->UpdatePlacement(node, Scheduler::kFixed);
|
| + ConnectCall(node);
|
| + }
|
| + break;
|
| default:
|
| break;
|
| }
|
| @@ -373,20 +384,17 @@ class CFGBuilder : public ZoneObject {
|
| }
|
|
|
| // Collect the branch-related projections from a node, such as IfTrue,
|
| - // IfFalse, Case and Default.
|
| + // IfFalse, IfSuccess, IfException, IfValue and IfDefault.
|
| void CollectSuccessorProjections(Node* node, Node** successors,
|
| size_t successor_count) {
|
| #ifdef DEBUG
|
| - DCHECK_EQ(static_cast<int>(successor_count), node->UseCount());
|
| + DCHECK_LE(static_cast<int>(successor_count), node->UseCount());
|
| std::memset(successors, 0, sizeof(*successors) * successor_count);
|
| #endif
|
| size_t if_value_index = 0;
|
| for (Node* const use : node->uses()) {
|
| size_t index;
|
| switch (use->opcode()) {
|
| - default:
|
| - UNREACHABLE();
|
| - // Fall through.
|
| case IrOpcode::kIfTrue:
|
| DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
| index = 0;
|
| @@ -395,6 +403,14 @@ class CFGBuilder : public ZoneObject {
|
| DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
| index = 1;
|
| break;
|
| + case IrOpcode::kIfSuccess:
|
| + DCHECK_EQ(IrOpcode::kCall, node->opcode());
|
| + index = 0;
|
| + break;
|
| + case IrOpcode::kIfException:
|
| + DCHECK_EQ(IrOpcode::kCall, node->opcode());
|
| + index = 1;
|
| + break;
|
| case IrOpcode::kIfValue:
|
| DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
|
| index = if_value_index++;
|
| @@ -403,6 +419,8 @@ class CFGBuilder : public ZoneObject {
|
| DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
|
| index = successor_count - 1;
|
| break;
|
| + default:
|
| + continue;
|
| }
|
| DCHECK_LT(if_value_index, successor_count);
|
| DCHECK_LT(index, successor_count);
|
| @@ -425,6 +443,31 @@ class CFGBuilder : public ZoneObject {
|
| }
|
| }
|
|
|
| + BasicBlock* FindPredecessorBlock(Node* node) {
|
| + BasicBlock* predecessor_block = nullptr;
|
| + while (true) {
|
| + predecessor_block = schedule_->block(node);
|
| + if (predecessor_block != nullptr) break;
|
| + node = NodeProperties::GetControlInput(node);
|
| + }
|
| + return predecessor_block;
|
| + }
|
| +
|
| + void ConnectCall(Node* call) {
|
| + BasicBlock* successor_blocks[2];
|
| + CollectSuccessorBlocks(call, successor_blocks, arraysize(successor_blocks));
|
| +
|
| + // Consider the exception continuation to be deferred.
|
| + successor_blocks[1]->set_deferred(true);
|
| +
|
| + Node* call_control = NodeProperties::GetControlInput(call);
|
| + BasicBlock* call_block = FindPredecessorBlock(call_control);
|
| + TraceConnect(call, call_block, successor_blocks[0]);
|
| + TraceConnect(call, call_block, successor_blocks[1]);
|
| + schedule_->AddCall(call_block, call, successor_blocks[0],
|
| + successor_blocks[1]);
|
| + }
|
| +
|
| void ConnectBranch(Node* branch) {
|
| BasicBlock* successor_blocks[2];
|
| CollectSuccessorBlocks(branch, successor_blocks,
|
| @@ -448,10 +491,8 @@ class CFGBuilder : public ZoneObject {
|
| 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_NOT_NULL(branch_block);
|
| -
|
| + Node* branch_control = NodeProperties::GetControlInput(branch);
|
| + BasicBlock* branch_block = FindPredecessorBlock(branch_control);
|
| TraceConnect(branch, branch_block, successor_blocks[0]);
|
| TraceConnect(branch, branch_block, successor_blocks[1]);
|
| schedule_->AddBranch(branch_block, branch, successor_blocks[0],
|
| @@ -472,14 +513,12 @@ class CFGBuilder : public ZoneObject {
|
| schedule_->InsertSwitch(component_start_, component_end_, sw,
|
| successor_blocks, successor_count);
|
| } else {
|
| - Node* sw_block_node = NodeProperties::GetControlInput(sw);
|
| - BasicBlock* sw_block = schedule_->block(sw_block_node);
|
| - DCHECK_NOT_NULL(sw_block);
|
| -
|
| + Node* switch_control = NodeProperties::GetControlInput(sw);
|
| + BasicBlock* switch_block = FindPredecessorBlock(switch_control);
|
| for (size_t index = 0; index < successor_count; ++index) {
|
| - TraceConnect(sw, sw_block, successor_blocks[index]);
|
| + TraceConnect(sw, switch_block, successor_blocks[index]);
|
| }
|
| - schedule_->AddSwitch(sw_block, sw, successor_blocks, successor_count);
|
| + schedule_->AddSwitch(switch_block, sw, successor_blocks, successor_count);
|
| }
|
| }
|
|
|
| @@ -492,22 +531,22 @@ class CFGBuilder : public ZoneObject {
|
| // For all of the merge's control inputs, add a goto at the end to the
|
| // merge's basic block.
|
| for (Node* const input : merge->inputs()) {
|
| - BasicBlock* predecessor_block = schedule_->block(input);
|
| + BasicBlock* predecessor_block = FindPredecessorBlock(input);
|
| TraceConnect(merge, predecessor_block, block);
|
| schedule_->AddGoto(predecessor_block, block);
|
| }
|
| }
|
|
|
| void ConnectReturn(Node* ret) {
|
| - Node* return_block_node = NodeProperties::GetControlInput(ret);
|
| - BasicBlock* return_block = schedule_->block(return_block_node);
|
| + Node* return_control = NodeProperties::GetControlInput(ret);
|
| + BasicBlock* return_block = FindPredecessorBlock(return_control);
|
| TraceConnect(ret, return_block, NULL);
|
| schedule_->AddReturn(return_block, ret);
|
| }
|
|
|
| void ConnectThrow(Node* thr) {
|
| - Node* throw_block_node = NodeProperties::GetControlInput(thr);
|
| - BasicBlock* throw_block = schedule_->block(throw_block_node);
|
| + Node* throw_control = NodeProperties::GetControlInput(thr);
|
| + BasicBlock* throw_block = FindPredecessorBlock(throw_control);
|
| TraceConnect(thr, throw_block, NULL);
|
| schedule_->AddThrow(throw_block, thr);
|
| }
|
| @@ -523,6 +562,13 @@ class CFGBuilder : public ZoneObject {
|
| }
|
| }
|
|
|
| + bool IsExceptionalCall(Node* node) {
|
| + for (Node* const use : node->uses()) {
|
| + if (use->opcode() == IrOpcode::kIfException) return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| bool IsFinalMerge(Node* node) {
|
| return (node->opcode() == IrOpcode::kMerge &&
|
| node == scheduler_->graph_->end()->InputAt(0));
|
| @@ -1368,7 +1414,7 @@ class ScheduleLateNodeVisitor {
|
| }
|
|
|
| // Schedule the node or a floating control structure.
|
| - if (NodeProperties::IsControl(node)) {
|
| + if (IrOpcode::IsMergeOpcode(node->opcode())) {
|
| ScheduleFloatingControl(block, node);
|
| } else {
|
| ScheduleNode(block, node);
|
| @@ -1492,10 +1538,13 @@ class ScheduleLateNodeVisitor {
|
| return block;
|
| }
|
|
|
| + BasicBlock* FindPredecessorBlock(Node* node) {
|
| + return scheduler_->control_flow_builder_->FindPredecessorBlock(node);
|
| + }
|
| +
|
| BasicBlock* GetBlockForUse(Edge edge) {
|
| Node* use = edge.from();
|
| - IrOpcode::Value opcode = use->opcode();
|
| - if (IrOpcode::IsPhiOpcode(opcode)) {
|
| + if (IrOpcode::IsPhiOpcode(use->opcode())) {
|
| // 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) {
|
| @@ -1504,15 +1553,23 @@ class ScheduleLateNodeVisitor {
|
| 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
|
| - // of the corresponding control input to the merge.
|
| + // If the use is from a fixed (i.e. non-floating) phi, we use the
|
| + // predecessor block of the corresponding control input to the merge.
|
| if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
|
| Trace(" input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
|
| use->op()->mnemonic());
|
| Node* merge = NodeProperties::GetControlInput(use, 0);
|
| - opcode = merge->opcode();
|
| - DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
|
| - use = NodeProperties::GetControlInput(merge, edge.index());
|
| + DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
|
| + Node* input = NodeProperties::GetControlInput(merge, edge.index());
|
| + return FindPredecessorBlock(input);
|
| + }
|
| + } else if (IrOpcode::IsMergeOpcode(use->opcode())) {
|
| + // If the use is from a fixed (i.e. non-floating) merge, we use the
|
| + // predecessor block of the current input to the merge.
|
| + if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
|
| + Trace(" input@%d into a fixed merge #%d:%s\n", edge.index(), use->id(),
|
| + use->op()->mnemonic());
|
| + return FindPredecessorBlock(edge.to());
|
| }
|
| }
|
| BasicBlock* result = schedule_->block(use);
|
|
|