Index: src/compiler/schedule.cc |
diff --git a/src/compiler/schedule.cc b/src/compiler/schedule.cc |
index 08e078ef5ac89654445c78e33a7a03451a3e7cf2..6bd1a17be0603476585442eaea760ce2b1ad3eb4 100644 |
--- a/src/compiler/schedule.cc |
+++ b/src/compiler/schedule.cc |
@@ -315,41 +315,87 @@ void Schedule::InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw, |
SetControlInput(block, sw); |
} |
-void Schedule::EnsureSplitEdgeForm() { |
+void Schedule::EnsureCFGWellFormedness() { |
// Make a copy of all the blocks for the iteration, since adding the split |
// edges will allocate new blocks. |
BasicBlockVector all_blocks_copy(all_blocks_); |
// Insert missing split edge blocks. |
for (auto block : all_blocks_copy) { |
- if (block->PredecessorCount() > 1 && block != end_) { |
- for (auto current_pred = block->predecessors().begin(); |
- current_pred != block->predecessors().end(); ++current_pred) { |
- BasicBlock* pred = *current_pred; |
- if (pred->SuccessorCount() > 1) { |
- // Found a predecessor block with multiple successors. |
- BasicBlock* split_edge_block = NewBasicBlock(); |
- split_edge_block->set_control(BasicBlock::kGoto); |
- split_edge_block->successors().push_back(block); |
- split_edge_block->predecessors().push_back(pred); |
- split_edge_block->set_deferred(pred->deferred()); |
- *current_pred = split_edge_block; |
- // Find a corresponding successor in the previous block, replace it |
- // with the split edge block... but only do it once, since we only |
- // replace the previous blocks in the current block one at a time. |
- for (auto successor = pred->successors().begin(); |
- successor != pred->successors().end(); ++successor) { |
- if (*successor == block) { |
- *successor = split_edge_block; |
- break; |
- } |
- } |
+ if (block->PredecessorCount() > 1) { |
+ if (block != end_) { |
+ EnsureSplitEdgeForm(block); |
+ } |
+ if (block->deferred()) { |
+ EnsureDeferredCodeSingleEntryPoint(block); |
+ } |
+ } |
+ } |
+} |
+ |
+void Schedule::EnsureSplitEdgeForm(BasicBlock* block) { |
+ DCHECK(block->PredecessorCount() > 1 && block != end_); |
+ for (auto current_pred = block->predecessors().begin(); |
+ current_pred != block->predecessors().end(); ++current_pred) { |
+ BasicBlock* pred = *current_pred; |
+ if (pred->SuccessorCount() > 1) { |
+ // Found a predecessor block with multiple successors. |
+ BasicBlock* split_edge_block = NewBasicBlock(); |
+ split_edge_block->set_control(BasicBlock::kGoto); |
+ split_edge_block->successors().push_back(block); |
+ split_edge_block->predecessors().push_back(pred); |
+ split_edge_block->set_deferred(pred->deferred()); |
+ *current_pred = split_edge_block; |
+ // Find a corresponding successor in the previous block, replace it |
+ // with the split edge block... but only do it once, since we only |
+ // replace the previous blocks in the current block one at a time. |
+ for (auto successor = pred->successors().begin(); |
+ successor != pred->successors().end(); ++successor) { |
+ if (*successor == block) { |
+ *successor = split_edge_block; |
+ break; |
} |
} |
} |
} |
} |
+void Schedule::EnsureDeferredCodeSingleEntryPoint(BasicBlock* block) { |
+ // If a deferred block has multiple predecessors, they have to |
+ // all be deferred. Otherwise, we can run into a situation where a range |
+ // that spills only in deferred blocks inserts its spill in the block, but |
+ // other ranges need moves inserted by ResolveControlFlow in the predecessors, |
+ // which may clobber the register of this range. |
+ // To ensure that, when a deferred block has multiple predecessors, and some |
+ // are not deferred, we add a non-deferred block to collect all such edges. |
+ |
+ DCHECK(block->deferred() && block->PredecessorCount() > 1); |
+ bool all_deferred = true; |
+ for (auto current_pred = block->predecessors().begin(); |
+ current_pred != block->predecessors().end(); ++current_pred) { |
+ BasicBlock* pred = *current_pred; |
+ if (!pred->deferred()) { |
+ all_deferred = false; |
+ break; |
+ } |
+ } |
+ |
+ if (all_deferred) return; |
+ BasicBlock* merger = NewBasicBlock(); |
+ merger->set_control(BasicBlock::kGoto); |
+ merger->successors().push_back(block); |
+ for (auto current_pred = block->predecessors().begin(); |
+ current_pred != block->predecessors().end(); ++current_pred) { |
+ BasicBlock* pred = *current_pred; |
+ merger->predecessors().push_back(pred); |
+ pred->successors().clear(); |
+ pred->successors().push_back(merger); |
+ } |
+ merger->set_deferred(false); |
+ block->predecessors().clear(); |
+ block->predecessors().push_back(merger); |
+} |
+ |
void Schedule::PropagateDeferredMark() { |
// Push forward the deferred block marks through newly inserted blocks and |
// other improperly marked blocks until a fixed point is reached. |