Index: src/compiler/scheduler.cc |
diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc |
index 674b89ef66762d0b5ffa5c5b052e094d3ac0d290..3e7d353cb7bf8e675b177b10f79079a71d09d536 100644 |
--- a/src/compiler/scheduler.cc |
+++ b/src/compiler/scheduler.cc |
@@ -587,7 +587,8 @@ class SpecialRPONumberer : public ZoneObject { |
loops_(zone), |
backedges_(zone), |
stack_(zone), |
- previous_block_count_(0) {} |
+ previous_block_count_(0), |
+ empty_(0, zone) {} |
// Computes the special reverse-post-order for the main control flow graph, |
// that is for the graph spanned between the schedule's start and end blocks. |
@@ -624,6 +625,14 @@ class SpecialRPONumberer : public ZoneObject { |
#endif |
} |
+ const ZoneList<BasicBlock*>& GetOutgoingBlocks(BasicBlock* block) { |
+ if (HasLoopNumber(block)) { |
+ LoopInfo const& loop = loops_[GetLoopNumber(block)]; |
+ if (loop.outgoing) return *loop.outgoing; |
+ } |
+ return empty_; |
+ } |
+ |
private: |
typedef std::pair<BasicBlock*, size_t> Backedge; |
@@ -1046,6 +1055,7 @@ class SpecialRPONumberer : public ZoneObject { |
ZoneVector<Backedge> backedges_; |
ZoneVector<SpecialRPOStackFrame> stack_; |
size_t previous_block_count_; |
+ ZoneList<BasicBlock*> const empty_; |
}; |
@@ -1346,7 +1356,7 @@ class ScheduleLateNodeVisitor { |
// Hoist nodes out of loops if possible. Nodes can be hoisted iteratively |
// into enclosing loop pre-headers until they would preceed their schedule |
// early position. |
- BasicBlock* hoist_block = GetPreHeader(block); |
+ BasicBlock* hoist_block = GetHoistBlock(block); |
if (hoist_block && |
hoist_block->dominator_depth() >= min_block->dominator_depth()) { |
do { |
@@ -1354,7 +1364,7 @@ class ScheduleLateNodeVisitor { |
node->op()->mnemonic(), hoist_block->id().ToInt()); |
DCHECK_LT(hoist_block->loop_depth(), block->loop_depth()); |
block = hoist_block; |
- hoist_block = GetPreHeader(hoist_block); |
+ hoist_block = GetHoistBlock(hoist_block); |
} while (hoist_block && |
hoist_block->dominator_depth() >= min_block->dominator_depth()); |
} else if (scheduler_->flags_ & Scheduler::kSplitNodes) { |
@@ -1465,14 +1475,23 @@ class ScheduleLateNodeVisitor { |
return block; |
} |
- BasicBlock* GetPreHeader(BasicBlock* block) { |
- if (block->IsLoopHeader()) { |
- return block->dominator(); |
- } else if (block->loop_header() != NULL) { |
- return block->loop_header()->dominator(); |
- } else { |
- return NULL; |
+ BasicBlock* GetHoistBlock(BasicBlock* block) { |
+ if (block->IsLoopHeader()) return block->dominator(); |
+ // We have to check to make sure that the {block} dominates all |
+ // of the outgoing blocks. If it doesn't, then there is a path |
+ // out of the loop which does not execute this {block}, so we |
+ // can't hoist operations from this {block} out of the loop, as |
+ // that would introduce additional computations. |
+ if (BasicBlock* header_block = block->loop_header()) { |
+ for (BasicBlock* outgoing_block : |
+ scheduler_->special_rpo_->GetOutgoingBlocks(header_block)) { |
+ if (BasicBlock::GetCommonDominator(block, outgoing_block) != block) { |
+ return nullptr; |
+ } |
+ } |
+ return header_block->dominator(); |
} |
+ return nullptr; |
} |
BasicBlock* GetCommonDominatorOfUses(Node* node) { |