Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Unified Diff: runtime/vm/flow_graph.cc

Issue 11092102: Avoid rediscovering blocks on each call to FlowGraph::InlineCall. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
« no previous file with comments | « runtime/vm/flow_graph.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698