Index: src/compiler/scheduler.cc |
diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc |
index 6e105e37131a3a326a9c4b97ce8e640dfc988259..8cbc05ebf71f6cc9bc3496e77de4069ba6020f59 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; |
} |
@@ -381,6 +392,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, |
@@ -404,10 +440,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], |
@@ -428,14 +462,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); |
} |
} |
@@ -448,22 +480,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); |
} |
@@ -479,6 +511,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)); |
@@ -1324,7 +1363,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); |
@@ -1448,10 +1487,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) { |
@@ -1460,15 +1502,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); |