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

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 13910003: Revert "Incrementally recompute dominators when inlining." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_builder.h" 5 #include "vm/flow_graph_builder.h"
6 6
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "vm/ast_printer.h" 8 #include "vm/ast_printer.h"
9 #include "vm/code_descriptors.h" 9 #include "vm/code_descriptors.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), 55 last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
56 try_index_(CatchClauseNode::kInvalidTryIndex), 56 try_index_(CatchClauseNode::kInvalidTryIndex),
57 graph_entry_(NULL) { } 57 graph_entry_(NULL) { }
58 58
59 59
60 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { 60 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) {
61 graph_entry_->AddCatchEntry(entry); 61 graph_entry_->AddCatchEntry(entry);
62 } 62 }
63 63
64 64
65 void InliningContext::PrepareGraphs(FlowGraph* callee_graph) { 65 void InliningContext::PrepareGraphs(FlowGraph* caller_graph,
66 Definition* call,
67 FlowGraph* callee_graph) {
66 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); 68 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
67 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); 69 ASSERT(callee_graph->max_block_id() > caller_graph->max_block_id());
68 ASSERT(callee_graph->max_virtual_register_number() > 70 ASSERT(callee_graph->max_virtual_register_number() >
69 caller_graph_->max_virtual_register_number()); 71 caller_graph->max_virtual_register_number());
70 72
71 // Adjust the caller's maximum block id and current SSA temp index. 73 // Adjust the caller's maximum block id and current SSA temp index.
72 caller_graph_->set_max_block_id(callee_graph->max_block_id()); 74 caller_graph->set_max_block_id(callee_graph->max_block_id());
73 caller_graph_->set_current_ssa_temp_index( 75 caller_graph->set_current_ssa_temp_index(
74 callee_graph->max_virtual_register_number()); 76 callee_graph->max_virtual_register_number());
75 77
76 // Attach the outer environment on each instruction in the callee graph. 78 // Attach the outer environment on each instruction in the callee graph.
77 for (BlockIterator block_it = callee_graph->postorder_iterator(); 79 for (BlockIterator block_it = callee_graph->postorder_iterator();
78 !block_it.Done(); 80 !block_it.Done();
79 block_it.Advance()) { 81 block_it.Advance()) {
80 for (ForwardInstructionIterator it(block_it.Current()); 82 for (ForwardInstructionIterator it(block_it.Current());
81 !it.Done(); 83 !it.Done();
82 it.Advance()) { 84 it.Advance()) {
83 Instruction* instr = it.Current(); 85 Instruction* instr = it.Current();
84 // TODO(zerny): Avoid creating unnecessary environments. Note that some 86 // TODO(zerny): Avoid creating unnecessary environments. Note that some
85 // optimizations need deoptimization info for non-deoptable instructions, 87 // optimizations need deoptimization info for non-deoptable instructions,
86 // eg, LICM on GOTOs. 88 // eg, LICM on GOTOs.
87 if (instr->env() != NULL) call_->env()->DeepCopyToOuter(instr); 89 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr);
88 } 90 }
89 } 91 }
90 } 92 }
91 93
92 94
93 void InliningContext::AddExit(ReturnInstr* exit) { 95 void InliningContext::AddExit(ReturnInstr* exit) {
94 Data data = { NULL, exit }; 96 Data data = { NULL, exit };
95 exits_.Add(data); 97 exits_.Add(data);
96 } 98 }
97 99
98 100
99 int InliningContext::LowestBlockIdFirst(const Data* a, const Data* b) { 101 int InliningContext::LowestBlockIdFirst(const Data* a, const Data* b) {
100 return (a->exit_block->block_id() - b->exit_block->block_id()); 102 return (a->exit_block->block_id() - b->exit_block->block_id());
101 } 103 }
102 104
103 105
104 void InliningContext::SortExits() { 106 void InliningContext::SortExits() {
105 // Assign block entries here because we did not necessarily know them when 107 // Assign block entries here because we did not necessarily know them when
106 // the return exit was added to the array. 108 // the return exit was added to the array.
107 for (int i = 0; i < exits_.length(); ++i) { 109 for (int i = 0; i < exits_.length(); ++i) {
108 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); 110 exits_[i].exit_block = exits_[i].exit_return->GetBlock();
109 } 111 }
110 exits_.Sort(LowestBlockIdFirst); 112 exits_.Sort(LowestBlockIdFirst);
111 } 113 }
112 114
113 115
114 Definition* InliningContext::JoinReturns(BlockEntryInstr** exit_block, 116 void InliningContext::ReplaceCall(FlowGraph* caller_graph,
115 Instruction** last_instruction) { 117 Definition* call,
116 // First sort the list of exits by block id (caching return instruction 118 FlowGraph* callee_graph) {
117 // block entries as a side effect). 119 ASSERT(call->previous() != NULL);
120 ASSERT(call->next() != NULL);
121 PrepareGraphs(caller_graph, call, callee_graph);
122
123 BlockEntryInstr* caller_entry = call->GetBlock();
124 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry();
125
126 // Insert the callee graph into the caller graph. First sort the list of
127 // exits by block id (recording block entries as a side effect).
118 SortExits(); 128 SortExits();
119 intptr_t num_exits = exits_.length(); 129 intptr_t num_exits = exits_.length();
120 if (num_exits == 0) { 130 if (num_exits == 0) {
121 // TODO(zerny): Add support for non-local exits, such as throw. 131 // TODO(zerny): Add support for non-local exits, such as throw.
122 UNREACHABLE(); 132 UNREACHABLE();
123 return NULL;
124 } else if (num_exits == 1) { 133 } else if (num_exits == 1) {
134 // For just one exit, replace the uses and remove the call from the graph.
135 call->ReplaceUsesWith(ValueAt(0)->definition());
125 ValueAt(0)->RemoveFromUseList(); 136 ValueAt(0)->RemoveFromUseList();
126 *exit_block = ExitBlockAt(0); 137 call->previous()->LinkTo(callee_entry->next());
127 *last_instruction = LastInstructionAt(0); 138 LastInstructionAt(0)->LinkTo(call->next());
128 return call_->HasUses() ? ValueAt(0)->definition() : NULL; 139 // In case of control flow, locally update the predecessors, phis and
140 // dominator tree.
141 // TODO(zerny): should we leave the dominator tree since we recompute it
142 // after a full inlining pass?
143 if (callee_graph->preorder().length() > 2) {
144 BlockEntryInstr* exit_block = ExitBlockAt(0);
145 // Pictorially, the graph structure is:
146 //
147 // Bc : caller_entry Bi : callee_entry
148 // before_call inlined_head
149 // call ... other blocks ...
150 // after_call Be : exit_block
151 // inlined_foot
152 // And becomes:
153 //
154 // Bc : caller_entry
155 // before_call
156 // inlined_head
157 // ... other blocks ...
158 // Be : exit_block
159 // inlined_foot
160 // after_call
161 //
162 // For 'after_call', caller entry (Bc) is replaced by callee exit (Be).
163 caller_entry->ReplaceAsPredecessorWith(exit_block);
164 // For 'inlined_head', callee entry (Bi) is replaced by caller entry (Bc).
165 callee_entry->ReplaceAsPredecessorWith(caller_entry);
166 // The callee exit is now the immediate dominator of blocks whose
167 // immediate dominator was the caller entry.
168 ASSERT(exit_block->dominated_blocks().is_empty());
169 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) {
170 BlockEntryInstr* block = caller_entry->dominated_blocks()[i];
171 block->set_dominator(exit_block);
172 exit_block->AddDominatedBlock(block);
173 }
174 // The caller entry is now the immediate dominator of blocks whose
175 // immediate dominator was the callee entry.
176 caller_entry->ClearDominatedBlocks();
177 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
178 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
179 block->set_dominator(caller_entry);
180 caller_entry->AddDominatedBlock(block);
181 }
182 }
129 } else { 183 } else {
130 // Create a join of the returns. 184 // Create a join of the returns.
131 intptr_t join_id = caller_graph_->max_block_id() + 1; 185 intptr_t join_id = caller_graph->max_block_id() + 1;
132 caller_graph_->set_max_block_id(join_id); 186 caller_graph->set_max_block_id(join_id);
133 JoinEntryInstr* join = 187 JoinEntryInstr* join =
134 new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex); 188 new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex);
135
136 // The dominator set of the join is the intersection of the dominator
137 // sets of all the predecessors. If we keep the dominator sets ordered
138 // by height in the dominator tree, we can also get the immediate
139 // dominator of the join node from the intersection.
140 //
141 // block_dominators is the dominator set for each block, ordered from
142 // the immediate dominator to the root of the dominator tree. This is
143 // the order we collect them in (adding at the end).
144 //
145 // join_dominators is the join's dominators ordered from the root of the
146 // dominator tree to the immediate dominator. This order supports
147 // removing during intersection by truncating the list.
148 GrowableArray<BlockEntryInstr*> block_dominators;
149 GrowableArray<BlockEntryInstr*> join_dominators;
150 for (intptr_t i = 0; i < num_exits; ++i) { 189 for (intptr_t i = 0; i < num_exits; ++i) {
151 // Add the control-flow edge.
152 LastInstructionAt(i)->Goto(join); 190 LastInstructionAt(i)->Goto(join);
153 ExitBlockAt(i)->set_last_instruction(LastInstructionAt(i)->next()); 191 // Directly add the predecessors of the join in ascending block id order.
154 join->predecessors_.Add(ExitBlockAt(i)); 192 join->predecessors_.Add(ExitBlockAt(i));
155
156 // Collect the block's dominators.
157 block_dominators.Clear();
158 BlockEntryInstr* dominator = ExitBlockAt(i)->dominator();
159 while (dominator != NULL) {
160 block_dominators.Add(dominator);
161 dominator = dominator->dominator();
162 }
163
164 if (i == 0) {
165 // The initial dominator set is the first predecessor's dominator
166 // set. Reverse it.
167 for (intptr_t j = block_dominators.length() - 1; j >= 0; --j) {
168 join_dominators.Add(block_dominators[j]);
169 }
170 } else {
171 // Intersect the block's dominators with the join's dominators so far.
172 intptr_t last = block_dominators.length() - 1;
173 for (intptr_t j = 0; j < join_dominators.length(); ++j) {
174 intptr_t k = last - j; // Corresponding index in block_dominators.
175 if ((k < 0) || (join_dominators[j] != block_dominators[k])) {
176 // We either exhausted the dominators for this block before
177 // exhausting the current intersection, or else we found a block
178 // on the path from the root of the tree that is not in common.
179 ASSERT(j >= 1);
180 join_dominators.TruncateTo(j - 1);
181 break;
182 }
183 }
184 }
185 } 193 }
186 // The immediate dominator of the join is the last one in the ordered
187 // intersection.
188 join->set_dominator(join_dominators.Last());
189 join_dominators.Last()->AddDominatedBlock(join);
190 *exit_block = join;
191 *last_instruction = join;
192
193 // If the call has uses, create a phi of the returns. 194 // If the call has uses, create a phi of the returns.
194 if (call_->HasUses()) { 195 if (call->HasUses()) {
195 // Add a phi of the return values. 196 // Add a phi of the return values.
196 PhiInstr* phi = new PhiInstr(join, num_exits); 197 PhiInstr* phi = new PhiInstr(join, num_exits);
197 phi->set_ssa_temp_index(caller_graph_->alloc_ssa_temp_index()); 198 phi->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index());
198 phi->mark_alive(); 199 phi->mark_alive();
199 for (intptr_t i = 0; i < num_exits; ++i) { 200 for (intptr_t i = 0; i < num_exits; ++i) {
200 phi->SetInputAt(i, ValueAt(i)); 201 phi->SetInputAt(i, ValueAt(i));
201 } 202 }
202 join->InsertPhi(phi); 203 join->InsertPhi(phi);
203 return phi; 204 // Replace uses of the call with the phi.
205 call->ReplaceUsesWith(phi);
204 } else { 206 } else {
205 // In the case that the result is unused, remove the return value uses 207 // In the case that the result is unused, remove the return value uses
206 // from their definition's use list. 208 // from their definition's use list.
207 for (intptr_t i = 0; i < num_exits; ++i) { 209 for (intptr_t i = 0; i < num_exits; ++i) {
208 ValueAt(i)->RemoveFromUseList(); 210 ValueAt(i)->RemoveFromUseList();
209 } 211 }
210 return NULL;
211 } 212 }
213 // Remove the call from the graph.
214 call->previous()->LinkTo(callee_entry->next());
215 join->LinkTo(call->next());
216 // Replace the blocks after splitting (see comment in the len=1 case above).
217 caller_entry->ReplaceAsPredecessorWith(join);
218 callee_entry->ReplaceAsPredecessorWith(caller_entry);
219 // Update the last instruction pointers on each exit block to the new goto.
220 for (intptr_t i = 0; i < num_exits; ++i) {
221 ExitBlockAt(i)->set_last_instruction(LastInstructionAt(i)->next());
222 }
223 // Mark that the dominator tree is invalid.
224 // TODO(zerny): Compute the dominator frontier locally.
225 caller_graph->InvalidateDominatorTree();
212 } 226 }
213 } 227 }
214 228
215
216 void InliningContext::ReplaceCall(FlowGraph* callee_graph) {
217 ASSERT(call_->previous() != NULL);
218 ASSERT(call_->next() != NULL);
219 PrepareGraphs(callee_graph);
220
221 BlockEntryInstr* call_block = call_->GetBlock();
222 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry();
223
224 // Insert the callee graph into the caller graph.
225 BlockEntryInstr* callee_exit = NULL;
226 Instruction* callee_last_instruction = NULL;
227 Definition* callee_result = JoinReturns(&callee_exit,
228 &callee_last_instruction);
229 if (callee_result != NULL) {
230 call_->ReplaceUsesWith(callee_result);
231 }
232 if (callee_last_instruction == callee_entry) {
233 // There are no instructions in the inlined function (e.g., it might be
234 // a return of a parameter or a return of a constant defined in the
235 // initial definitions).
236 call_->previous()->LinkTo(call_->next());
237 } else {
238 call_->previous()->LinkTo(callee_entry->next());
239 callee_last_instruction->LinkTo(call_->next());
240 }
241 if (callee_exit != callee_entry) {
242 // In case of control flow, locally update the predecessors, phis and
243 // dominator tree.
244 //
245 // Pictorially, the graph structure is:
246 //
247 // Bc : call_block Bi : callee_entry
248 // before_call inlined_head
249 // call ... other blocks ...
250 // after_call Be : callee_exit
251 // inlined_foot
252 // And becomes:
253 //
254 // Bc : call_block
255 // before_call
256 // inlined_head
257 // ... other blocks ...
258 // Be : callee_exit
259 // inlined_foot
260 // after_call
261 //
262 // For successors of 'after_call', the call block (Bc) is replaced as a
263 // predecessor by the callee exit (Be).
264 call_block->ReplaceAsPredecessorWith(callee_exit);
265 // For successors of 'inlined_head', the callee entry (Bi) is replaced
266 // as a predecessor by the call block (Bc).
267 callee_entry->ReplaceAsPredecessorWith(call_block);
268
269 // The callee exit is now the immediate dominator of blocks whose
270 // immediate dominator was the call block.
271 ASSERT(callee_exit->dominated_blocks().is_empty());
272 for (intptr_t i = 0; i < call_block->dominated_blocks().length(); ++i) {
273 BlockEntryInstr* block = call_block->dominated_blocks()[i];
274 block->set_dominator(callee_exit);
275 callee_exit->AddDominatedBlock(block);
276 }
277 // The call block is now the immediate dominator of blocks whose
278 // immediate dominator was the callee entry.
279 call_block->ClearDominatedBlocks();
280 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
281 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
282 block->set_dominator(call_block);
283 call_block->AddDominatedBlock(block);
284 }
285 }
286 }
287
288 229
289 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { 230 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) {
290 ASSERT(is_open()); 231 ASSERT(is_open());
291 if (other_fragment.is_empty()) return; 232 if (other_fragment.is_empty()) return;
292 if (is_empty()) { 233 if (is_empty()) {
293 entry_ = other_fragment.entry(); 234 entry_ = other_fragment.entry();
294 exit_ = other_fragment.exit(); 235 exit_ = other_fragment.exit();
295 } else { 236 } else {
296 exit()->LinkTo(other_fragment.entry()); 237 exit()->LinkTo(other_fragment.entry());
297 exit_ = other_fragment.exit(); 238 exit_ = other_fragment.exit();
(...skipping 3105 matching lines...) Expand 10 before | Expand all | Expand 10 after
3403 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 3344 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
3404 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 3345 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
3405 OS::SNPrint(chars, len, kFormat, function_name, reason); 3346 OS::SNPrint(chars, len, kFormat, function_name, reason);
3406 const Error& error = Error::Handle( 3347 const Error& error = Error::Handle(
3407 LanguageError::New(String::Handle(String::New(chars)))); 3348 LanguageError::New(String::Handle(String::New(chars))));
3408 Isolate::Current()->long_jump_base()->Jump(1, error); 3349 Isolate::Current()->long_jump_base()->Jump(1, error);
3409 } 3350 }
3410 3351
3411 3352
3412 } // namespace dart 3353 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698