Chromium Code Reviews| Index: runtime/vm/flow_graph.cc |
| diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc |
| index 3a4cfe8ae5c955a391ccc1eff3094d38af94f6be..779716bc888bee80d8749b670688c06e5640c0c5 100644 |
| --- a/runtime/vm/flow_graph.cc |
| +++ b/runtime/vm/flow_graph.cc |
| @@ -30,7 +30,8 @@ FlowGraph::FlowGraph(const FlowGraphBuilder& builder, |
| preorder_(), |
| postorder_(), |
| reverse_postorder_(), |
| - exits_(NULL) { |
| + exits_(NULL), |
| + invalid_dominator_tree_(true) { |
| DiscoverBlocks(); |
| } |
| @@ -304,6 +305,7 @@ void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number) { |
| // (preorder block numbers of) blocks in the dominance frontier. |
| void FlowGraph::ComputeDominators( |
| GrowableArray<BitVector*>* dominance_frontier) { |
| + invalid_dominator_tree_ = false; |
| // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass |
| // version of the Lengauer-Tarjan algorithm (LT is normally three passes) |
| // that eliminates a pass by using nearest-common ancestor (NCA) to |
| @@ -725,37 +727,67 @@ void FlowGraph::Bailout(const char* reason) const { |
| } |
| -// Helper to reorder phis after splitting a block. The last instruction(s) of |
| -// the split block will now have a larger block id than any previously known |
| -// blocks. If the last instruction jumps to a join, we must reorder phi inputs |
| -// according to the block order, ie, we move this predecessor to the end. |
| -static void ReorderPhis(BlockEntryInstr* block) { |
| - GotoInstr* jump = block->last_instruction()->AsGoto(); |
| +// Helper to reorder predecessors and phis after splitting a block. For each |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
Comment needs some updating---it's no longer calle
zerny-google
2012/10/22 13:21:31
Done.
|
| +// successor of 'old_block', the predecessors will be reordered to preserve |
| +// block order sorting. If the successor is a join, also the phi inputs will be |
| +// updated. |
| +// Prerequisite: the last-instruction pointers must not have been updated yet. |
| +void FlowGraph::ReorderPredecessors(BlockEntryInstr* old_block, |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
I find the naming and emphasis (on reordering) a b
zerny-google
2012/10/22 13:21:31
I renamed it to ReplaceBlock, but that is not enti
|
| + BlockEntryInstr* new_block) { |
| + // If the last instruction is a branch, update the predecessor of the targets. |
| + BranchInstr* branch = old_block->last_instruction()->AsBranch(); |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
It doesn't make a huge difference, but this code c
zerny-google
2012/10/22 13:21:31
Done.
|
| + if (branch != NULL) { |
| + for (intptr_t i = 0; i < branch->SuccessorCount(); ++i) { |
| + TargetEntryInstr* target = branch->SuccessorAt(i)->AsTargetEntry(); |
| + ASSERT(target != NULL); |
| + target->predecessor_ = new_block; |
| + } |
| + return; |
| + } |
| + // If the last instruction is a jump, update the join's predecessors and phis. |
| + GotoInstr* jump = old_block->last_instruction()->AsGoto(); |
| if (jump == NULL) return; |
| + // Find the old predecessor index |
| JoinEntryInstr* join = jump->successor(); |
| - intptr_t pred_index = join->IndexOfPredecessor(block); |
| + intptr_t pred_index = join->IndexOfPredecessor(old_block); |
| intptr_t pred_count = join->PredecessorCount(); |
| ASSERT(pred_index >= 0); |
| ASSERT(pred_index < pred_count); |
| - // If the predecessor index is the last index there is nothing to update. |
| - if ((join->phis() == NULL) || (pred_index + 1 == pred_count)) return; |
| - // Otherwise, move the predecessor use to the end in each phi. |
| + // Find the new predecessor index |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
It seems like we could do the search and move in t
zerny-google
2012/10/22 13:21:31
Done.
|
| + intptr_t new_block_id = new_block->block_id(); |
| + intptr_t new_pred_index = -1; |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
Is it simpler to understand this if you shift the
zerny-google
2012/10/22 13:21:31
No longer an issue with the new "find predecessor
|
| + while (new_pred_index < pred_count - 1) { |
| + ++new_pred_index; |
| + if (join->predecessors_[new_pred_index]->block_id() > new_block_id) break; |
| + } |
| + // Reorder the predecessors of the join. |
| + intptr_t step = (new_pred_index > pred_index) ? 1 : -1; |
| + intptr_t i = pred_index; |
| + while (i != new_pred_index) { |
|
zerny-google
2012/10/12 11:52:05
I'll rewrite this to a for loop again (still using
|
| + join->predecessors_[i] = join->predecessors_[i + step]; |
| + i += step; |
| + } |
| + join->predecessors_[new_pred_index] = new_block; |
| + // If the new and old predecessor index match there is nothing to update. |
| + if ((join->phis() == NULL) || (pred_index == new_pred_index)) return; |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
Can't you can skip the reordering of the predecess
zerny-google
2012/10/22 13:21:31
No, we still need to write the new_block at the ne
|
| + // Otherwise, reorder the predecessor uses in each phi. |
| for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| PhiInstr* phi = (*join->phis())[i]; |
| if (phi == NULL) continue; |
| ASSERT(pred_count == phi->InputCount()); |
| // Save the predecessor use. |
| Value* pred_use = phi->InputAt(pred_index); |
| - // Move each of the following uses back by one. |
| - ASSERT(pred_index < pred_count - 1); // Will move at least one index. |
| - for (intptr_t i = pred_index; i < pred_count - 1; ++i) { |
| - Value* use = phi->InputAt(i + 1); |
| - phi->SetInputAt(i, use); |
| - use->set_use_index(i); |
| - } |
| - // Write the predecessor use at the end. |
| - phi->SetInputAt(pred_count - 1, pred_use); |
| - pred_use->set_use_index(pred_count - 1); |
| + // Move uses between old and new. |
| + intptr_t use_idx = pred_index; |
| + while (use_idx != new_pred_index) { |
|
zerny-google
2012/10/12 11:52:05
I'll rewrite this to a for loop again (still using
|
| + Value* use = phi->InputAt(use_idx + step); |
| + phi->SetInputAt(use_idx, use); |
| + use->set_use_index(use_idx); |
| + use_idx += step; |
| + } |
| + // Write the predecessor use. |
| + phi->SetInputAt(new_pred_index, pred_use); |
| + pred_use->set_use_index(new_pred_index); |
| } |
| } |
| @@ -820,15 +852,19 @@ void FlowGraph::InlineCall(Definition* call, FlowGraph* callee_graph) { |
| call->ReplaceUsesWith(exit->value()->definition()); |
| call->previous()->LinkTo(callee_entry->next()); |
| exit->previous()->LinkTo(call->next()); |
| - // In case of control flow, locally update the dominator tree. |
| + // In case of control flow, locally update the predecessors, phis and |
| + // dominator tree. |
| + // TODO(zerny): should we leave the dominator tree since we recompute it |
| + // after a full inlining pass. |
| if (callee_graph->preorder().length() > 2) { |
| - // The caller block is split and the new block id is that of the exit |
| - // block. If the caller block had outgoing edges, reorder the phis so they |
| - // are still ordered by block id. |
| - ReorderPhis(caller_entry); |
| + BlockEntryInstr* exit_block = exit->GetBlock(); |
| + // The caller block is split and the predecessors might need reordering. |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
'the predecessors' is unclear. "The caller block
zerny-google
2012/10/22 13:21:31
Done.
|
| + // The caller entry becomes the block of the callee entry block. |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
I don't think I understand this comment at all :)
zerny-google
2012/10/22 13:21:31
Done.
|
| + ReorderPredecessors(callee_entry, caller_entry); |
| + // The callee exit block becomes the block of the caller entry block. |
| + ReorderPredecessors(caller_entry, exit_block); |
| // The callee return is now the immediate dominator of blocks whose |
| // immediate dominator was the caller entry. |
| - BlockEntryInstr* exit_block = exit->GetBlock(); |
| ASSERT(exit_block->dominated_blocks().is_empty()); |
| for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) { |
| BlockEntryInstr* block = caller_entry->dominated_blocks()[i]; |
| @@ -843,8 +879,9 @@ void FlowGraph::InlineCall(Definition* call, FlowGraph* callee_graph) { |
| block->set_dominator(caller_entry); |
| caller_entry->AddDominatedBlock(block); |
| } |
| - // Recompute the block orders. |
| - DiscoverBlocks(); |
| + // Update the last-instruction pointers. |
| + exit_block->set_last_instruction(caller_entry->last_instruction()); |
|
Kevin Millikin (Google)
2012/10/22 09:10:37
It seems like this could also be moved into Reorde
zerny-google
2012/10/22 13:21:31
Done.
|
| + caller_entry->set_last_instruction(callee_entry->last_instruction()); |
| } |
| } else { |
| // Sort the list of exits by block id. |
| @@ -884,16 +921,31 @@ void FlowGraph::InlineCall(Definition* call, FlowGraph* callee_graph) { |
| // Replace uses of the call with the phi. |
| call->ReplaceUsesWith(phi); |
| } |
| - // Remove the call from the graph. |
| + // Remove the call from the graph. |
| call->previous()->LinkTo(callee_entry->next()); |
| join->LinkTo(call->next()); |
| - // The caller block is split and the new block id is that of the join |
| - // block. If the caller block had outgoing edges, reorder the phis so they |
| - // are still ordered by block id. |
| - ReorderPhis(caller_entry); |
| - // Adjust pre/post orders and update the dominator tree. |
| - DiscoverBlocks(); |
| + // The caller block is split and the predecessors might need reordering. |
| + // The caller entry becomes the block of the callee entry block. |
| + ReorderPredecessors(callee_entry, caller_entry); |
| + // The join block becomes the block of the caller entry block. |
| + ReorderPredecessors(caller_entry, join); |
| + // Update the last instruction pointers. |
| + join->set_last_instruction(caller_entry->last_instruction()); |
| + caller_entry->set_last_instruction(callee_entry->last_instruction()); |
| + for (intptr_t i = 0; i < exits.length(); ++i) { |
| + exits[i]->set_last_instruction( |
| + exits[i]->last_instruction()->previous()->next()); |
| + } |
| + // Mark that the dominator tree is invalid. |
| // TODO(zerny): Compute the dominator frontier locally. |
| + invalid_dominator_tree_ = true; |
| + } |
| +} |
| + |
| + |
| +void FlowGraph::RepairGraphAfterInlining() { |
| + DiscoverBlocks(); |
| + if (invalid_dominator_tree_) { |
| GrowableArray<BitVector*> dominance_frontier; |
| ComputeDominators(&dominance_frontier); |
| } |