| OLD | NEW |
| 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.h" | 5 #include "vm/flow_graph.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 preorder_(), | 27 preorder_(), |
| 28 postorder_(), | 28 postorder_(), |
| 29 reverse_postorder_(), | 29 reverse_postorder_(), |
| 30 exits_(NULL) { | 30 exits_(NULL) { |
| 31 DiscoverBlocks(); | 31 DiscoverBlocks(); |
| 32 } | 32 } |
| 33 | 33 |
| 34 | 34 |
| 35 void FlowGraph::DiscoverBlocks() { | 35 void FlowGraph::DiscoverBlocks() { |
| 36 // Initialize state. | 36 // Initialize state. |
| 37 preorder_.Clear(); | 37 preorder_.TruncateTo(0); |
| 38 postorder_.Clear(); | 38 postorder_.TruncateTo(0); |
| 39 reverse_postorder_.Clear(); | 39 reverse_postorder_.TruncateTo(0); |
| 40 parent_.Clear(); | 40 parent_.TruncateTo(0); |
| 41 assigned_vars_.Clear(); | 41 assigned_vars_.TruncateTo(0); |
| 42 // Perform a depth-first traversal of the graph to build preorder and | 42 // Perform a depth-first traversal of the graph to build preorder and |
| 43 // postorder block orders. | 43 // postorder block orders. |
| 44 graph_entry_->DiscoverBlocks(NULL, // Entry block predecessor. | 44 graph_entry_->DiscoverBlocks(NULL, // Entry block predecessor. |
| 45 &preorder_, | 45 &preorder_, |
| 46 &postorder_, | 46 &postorder_, |
| 47 &parent_, | 47 &parent_, |
| 48 &assigned_vars_, | 48 &assigned_vars_, |
| 49 variable_count(), | 49 variable_count(), |
| 50 num_non_copied_params()); | 50 num_non_copied_params()); |
| 51 // Number blocks in reverse postorder. | 51 // Number blocks in reverse postorder. |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 ValidateUseListsInInstruction(it.Current()); | 191 ValidateUseListsInInstruction(it.Current()); |
| 192 } | 192 } |
| 193 } | 193 } |
| 194 return true; // Return true so we can ASSERT validation. | 194 return true; // Return true so we can ASSERT validation. |
| 195 } | 195 } |
| 196 #endif // DEBUG | 196 #endif // DEBUG |
| 197 | 197 |
| 198 | 198 |
| 199 static void ClearUseLists(Definition* defn) { | 199 static void ClearUseLists(Definition* defn) { |
| 200 ASSERT(defn != NULL); | 200 ASSERT(defn != NULL); |
| 201 ASSERT(defn->input_use_list() == NULL); | 201 DEBUG_ASSERT(defn->input_use_list() == NULL); |
| 202 ASSERT(defn->env_use_list() == NULL); | 202 DEBUG_ASSERT(defn->env_use_list() == NULL); |
| 203 defn->set_input_use_list(NULL); | 203 defn->set_input_use_list(NULL); |
| 204 defn->set_env_use_list(NULL); | 204 defn->set_env_use_list(NULL); |
| 205 } | 205 } |
| 206 | 206 |
| 207 | 207 |
| 208 static void RecordInputUses(Instruction* instr) { | 208 static void RecordInputUses(Instruction* instr) { |
| 209 ASSERT(instr != NULL); | 209 ASSERT(instr != NULL); |
| 210 for (intptr_t i = 0; i < instr->InputCount(); ++i) { | 210 for (intptr_t i = 0; i < instr->InputCount(); ++i) { |
| 211 Value* use = instr->InputAt(i); | 211 Value* use = instr->InputAt(i); |
| 212 ASSERT(use->instruction() == NULL); | 212 DEBUG_ASSERT(use->instruction() == NULL); |
| 213 ASSERT(use->use_index() == -1); | 213 DEBUG_ASSERT(use->use_index() == -1); |
| 214 ASSERT(use->next_use() == NULL); | 214 DEBUG_ASSERT(use->next_use() == NULL); |
| 215 DEBUG_ASSERT(0 == MembershipCount(use, | 215 DEBUG_ASSERT(0 == MembershipCount(use, |
| 216 use->definition()->input_use_list())); | 216 use->definition()->input_use_list())); |
| 217 use->set_instruction(instr); | 217 use->set_instruction(instr); |
| 218 use->set_use_index(i); | 218 use->set_use_index(i); |
| 219 use->AddToInputUseList(); | 219 use->AddToInputUseList(); |
| 220 } | 220 } |
| 221 } | 221 } |
| 222 | 222 |
| 223 | 223 |
| 224 static void RecordEnvUses(Instruction* instr) { | 224 static void RecordEnvUses(Instruction* instr) { |
| 225 ASSERT(instr != NULL); | 225 ASSERT(instr != NULL); |
| 226 if (instr->env() == NULL) return; | 226 if (instr->env() == NULL) return; |
| 227 intptr_t use_index = 0; | 227 intptr_t use_index = 0; |
| 228 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { | 228 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
| 229 Value* use = it.CurrentValue(); | 229 Value* use = it.CurrentValue(); |
| 230 ASSERT(use->instruction() == NULL); | 230 DEBUG_ASSERT(use->instruction() == NULL); |
| 231 ASSERT(use->use_index() == -1); | 231 DEBUG_ASSERT(use->use_index() == -1); |
| 232 ASSERT(use->next_use() == NULL); | 232 DEBUG_ASSERT(use->next_use() == NULL); |
| 233 DEBUG_ASSERT(0 == MembershipCount(use, use->definition()->env_use_list())); | 233 DEBUG_ASSERT(0 == MembershipCount(use, use->definition()->env_use_list())); |
| 234 use->set_instruction(instr); | 234 use->set_instruction(instr); |
| 235 use->set_use_index(use_index++); | 235 use->set_use_index(use_index++); |
| 236 use->AddToEnvUseList(); | 236 use->AddToEnvUseList(); |
| 237 } | 237 } |
| 238 } | 238 } |
| 239 | 239 |
| 240 | 240 |
| 241 static void ComputeUseListsRecursive(BlockEntryInstr* block) { | 241 static void ComputeUseListsRecursive(BlockEntryInstr* block) { |
| 242 // Clear phi definitions. | 242 // Clear phi definitions. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 263 block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { | 263 block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { |
| 264 JoinEntryInstr* join = | 264 JoinEntryInstr* join = |
| 265 block->last_instruction()->SuccessorAt(0)->AsJoinEntry(); | 265 block->last_instruction()->SuccessorAt(0)->AsJoinEntry(); |
| 266 intptr_t pred_index = join->IndexOfPredecessor(block); | 266 intptr_t pred_index = join->IndexOfPredecessor(block); |
| 267 ASSERT(pred_index >= 0); | 267 ASSERT(pred_index >= 0); |
| 268 if (join->phis() != NULL) { | 268 if (join->phis() != NULL) { |
| 269 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | 269 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| 270 PhiInstr* phi = (*join->phis())[i]; | 270 PhiInstr* phi = (*join->phis())[i]; |
| 271 if (phi == NULL) continue; | 271 if (phi == NULL) continue; |
| 272 Value* use = phi->InputAt(pred_index); | 272 Value* use = phi->InputAt(pred_index); |
| 273 ASSERT(use->instruction() == NULL); | 273 DEBUG_ASSERT(use->instruction() == NULL); |
| 274 ASSERT(use->use_index() == -1); | 274 DEBUG_ASSERT(use->use_index() == -1); |
| 275 ASSERT(use->next_use() == NULL); | 275 DEBUG_ASSERT(use->next_use() == NULL); |
| 276 DEBUG_ASSERT(0 == MembershipCount(use, | 276 DEBUG_ASSERT(0 == MembershipCount(use, |
| 277 use->definition()->input_use_list())); | 277 use->definition()->input_use_list())); |
| 278 use->set_instruction(phi); | 278 use->set_instruction(phi); |
| 279 use->set_use_index(pred_index); | 279 use->set_use_index(pred_index); |
| 280 use->AddToInputUseList(); | 280 use->AddToInputUseList(); |
| 281 } | 281 } |
| 282 } | 282 } |
| 283 } | 283 } |
| 284 } | 284 } |
| 285 | 285 |
| 286 | 286 |
| 287 void FlowGraph::ComputeUseLists() { | 287 void FlowGraph::ComputeUseLists() { |
| 288 DEBUG_ASSERT(ResetUseLists()); | 288 DEBUG_ASSERT(ResetUseLists()); |
| 289 // Clear global constants and definitions in the start environment. | 289 // Clear global constants and definitions in the start environment. |
| 290 ClearUseLists(graph_entry_->constant_null()); | 290 ClearUseLists(graph_entry_->constant_null()); |
| 291 for (intptr_t i = 0; i < graph_entry_->start_env()->Length(); ++i) { | 291 for (intptr_t i = 0; i < graph_entry_->start_env()->Length(); ++i) { |
| 292 ClearUseLists(graph_entry_->start_env()->ValueAt(i)->definition()); | 292 ClearUseLists(graph_entry_->start_env()->ValueAt(i)->definition()); |
| 293 } | 293 } |
| 294 ComputeUseListsRecursive(graph_entry_); | 294 ComputeUseListsRecursive(graph_entry_); |
| 295 DEBUG_ASSERT(ValidateUseLists()); | 295 DEBUG_ASSERT(ValidateUseLists()); |
| 296 } | 296 } |
| 297 | 297 |
| 298 | 298 |
| 299 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number) { | 299 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number) { |
| 300 current_ssa_temp_index_ = next_virtual_register_number; | 300 current_ssa_temp_index_ = next_virtual_register_number; |
| 301 GrowableArray<BitVector*> dominance_frontier; | 301 GrowableArray<BitVector*> dominance_frontier; |
| 302 ComputeDominators(&dominance_frontier); | 302 ComputeDominators(&preorder_, &parent_, &dominance_frontier); |
| 303 InsertPhis(preorder_, assigned_vars_, dominance_frontier); | 303 InsertPhis(preorder_, assigned_vars_, dominance_frontier); |
| 304 GrowableArray<PhiInstr*> live_phis; | 304 GrowableArray<PhiInstr*> live_phis; |
| 305 // Rename uses to reference inserted phis where appropriate. | 305 // Rename uses to reference inserted phis where appropriate. |
| 306 // Collect phis that reach a non-environment use. | 306 // Collect phis that reach a non-environment use. |
| 307 Rename(&live_phis); | 307 Rename(&live_phis); |
| 308 // Propagate alive mark transitively from alive phis. | 308 // Propagate alive mark transitively from alive phis. |
| 309 MarkLivePhis(&live_phis); | 309 MarkLivePhis(&live_phis); |
| 310 } | 310 } |
| 311 | 311 |
| 312 | 312 |
| 313 // Compute immediate dominators and the dominance frontier for each basic | 313 // Compute immediate dominators and the dominance frontier for each basic |
| 314 // block. As a side effect of the algorithm, sets the immediate dominator | 314 // block. As a side effect of the algorithm, sets the immediate dominator |
| 315 // of each basic block. | 315 // of each basic block. |
| 316 // | 316 // |
| 317 // preorder: an input list of basic block entries in preorder. The |
| 318 // algorithm relies on the block ordering. |
| 319 // |
| 320 // parent: an input parameter encoding a depth-first spanning tree of |
| 321 // the control flow graph. The array maps the preorder block |
| 322 // number of a block to the preorder block number of its spanning |
| 323 // tree parent. |
| 324 // |
| 317 // dominance_frontier: an output parameter encoding the dominance frontier. | 325 // dominance_frontier: an output parameter encoding the dominance frontier. |
| 318 // The array maps the preorder block number of a block to the set of | 326 // The array maps the preorder block number of a block to the set of |
| 319 // (preorder block numbers of) blocks in the dominance frontier. | 327 // (preorder block numbers of) blocks in the dominance frontier. |
| 320 void FlowGraph::ComputeDominators( | 328 void FlowGraph::ComputeDominators( |
| 329 GrowableArray<BlockEntryInstr*>* preorder, |
| 330 GrowableArray<intptr_t>* parent, |
| 321 GrowableArray<BitVector*>* dominance_frontier) { | 331 GrowableArray<BitVector*>* dominance_frontier) { |
| 322 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass | 332 // Use the SEMI-NCA algorithm to compute dominators. This is a two-pass |
| 323 // version of the Lengauer-Tarjan algorithm (LT is normally three passes) | 333 // version of the Lengauer-Tarjan algorithm (LT is normally three passes) |
| 324 // that eliminates a pass by using nearest-common ancestor (NCA) to | 334 // that eliminates a pass by using nearest-common ancestor (NCA) to |
| 325 // compute immediate dominators from semidominators. It also removes a | 335 // compute immediate dominators from semidominators. It also removes a |
| 326 // level of indirection in the link-eval forest data structure. | 336 // level of indirection in the link-eval forest data structure. |
| 327 // | 337 // |
| 328 // The algorithm is described in Georgiadis, Tarjan, and Werneck's | 338 // The algorithm is described in Georgiadis, Tarjan, and Werneck's |
| 329 // "Finding Dominators in Practice". | 339 // "Finding Dominators in Practice". |
| 330 // See http://www.cs.princeton.edu/~rwerneck/dominators/ . | 340 // See http://www.cs.princeton.edu/~rwerneck/dominators/ . |
| 331 | 341 |
| 332 // All arrays are maps between preorder basic-block numbers. | 342 // All arrays are maps between preorder basic-block numbers. |
| 333 intptr_t size = parent_.length(); | 343 intptr_t size = parent->length(); |
| 334 GrowableArray<intptr_t> idom(size); // Immediate dominator. | 344 GrowableArray<intptr_t> idom(size); // Immediate dominator. |
| 335 GrowableArray<intptr_t> semi(size); // Semidominator. | 345 GrowableArray<intptr_t> semi(size); // Semidominator. |
| 336 GrowableArray<intptr_t> label(size); // Label for link-eval forest. | 346 GrowableArray<intptr_t> label(size); // Label for link-eval forest. |
| 337 | 347 |
| 338 // 1. First pass: compute semidominators as in Lengauer-Tarjan. | 348 // 1. First pass: compute semidominators as in Lengauer-Tarjan. |
| 339 // Semidominators are computed from a depth-first spanning tree and are an | 349 // Semidominators are computed from a depth-first spanning tree and are an |
| 340 // approximation of immediate dominators. | 350 // approximation of immediate dominators. |
| 341 | 351 |
| 342 // Use a link-eval data structure with path compression. Implement path | 352 // Use a link-eval data structure with path compression. Implement path |
| 343 // compression in place by mutating the parent array. Each block has a | 353 // compression in place by mutating the parent array. Each block has a |
| 344 // label, which is the minimum block number on the compressed path. | 354 // label, which is the minimum block number on the compressed path. |
| 345 | 355 |
| 346 // Initialize idom, semi, and label used by SEMI-NCA. Initialize the | 356 // Initialize idom, semi, and label used by SEMI-NCA. Initialize the |
| 347 // dominance frontier output array. | 357 // dominance frontier output array. |
| 348 for (intptr_t i = 0; i < size; ++i) { | 358 for (intptr_t i = 0; i < size; ++i) { |
| 349 idom.Add(parent_[i]); | 359 idom.Add((*parent)[i]); |
| 350 semi.Add(i); | 360 semi.Add(i); |
| 351 label.Add(i); | 361 label.Add(i); |
| 352 dominance_frontier->Add(new BitVector(size)); | 362 dominance_frontier->Add(new BitVector(size)); |
| 353 } | 363 } |
| 354 | 364 |
| 355 // Loop over the blocks in reverse preorder (not including the graph | 365 // Loop over the blocks in reverse preorder (not including the graph |
| 356 // entry). Clear the dominated blocks in the graph entry in case | 366 // entry). |
| 357 // ComputeDominators is used to recompute them. | |
| 358 preorder_[0]->ClearDominatedBlocks(); | |
| 359 for (intptr_t block_index = size - 1; block_index >= 1; --block_index) { | 367 for (intptr_t block_index = size - 1; block_index >= 1; --block_index) { |
| 360 // Loop over the predecessors. | 368 // Loop over the predecessors. |
| 361 BlockEntryInstr* block = preorder_[block_index]; | 369 BlockEntryInstr* block = (*preorder)[block_index]; |
| 362 // Clear the immediately dominated blocks in case ComputeDominators is | |
| 363 // used to recompute them. | |
| 364 block->ClearDominatedBlocks(); | |
| 365 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { | 370 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { |
| 366 BlockEntryInstr* pred = block->PredecessorAt(i); | 371 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 367 ASSERT(pred != NULL); | 372 ASSERT(pred != NULL); |
| 368 | 373 |
| 369 // Look for the semidominator by ascending the semidominator path | 374 // Look for the semidominator by ascending the semidominator path |
| 370 // starting from pred. | 375 // starting from pred. |
| 371 intptr_t pred_index = pred->preorder_number(); | 376 intptr_t pred_index = pred->preorder_number(); |
| 372 intptr_t best = pred_index; | 377 intptr_t best = pred_index; |
| 373 if (pred_index > block_index) { | 378 if (pred_index > block_index) { |
| 374 CompressPath(block_index, pred_index, &parent_, &label); | 379 CompressPath(block_index, pred_index, parent, &label); |
| 375 best = label[pred_index]; | 380 best = label[pred_index]; |
| 376 } | 381 } |
| 377 | 382 |
| 378 // Update the semidominator if we've found a better one. | 383 // Update the semidominator if we've found a better one. |
| 379 semi[block_index] = Utils::Minimum(semi[block_index], semi[best]); | 384 semi[block_index] = Utils::Minimum(semi[block_index], semi[best]); |
| 380 } | 385 } |
| 381 | 386 |
| 382 // Now use label for the semidominator. | 387 // Now use label for the semidominator. |
| 383 label[block_index] = semi[block_index]; | 388 label[block_index] = semi[block_index]; |
| 384 } | 389 } |
| 385 | 390 |
| 386 // 2. Compute the immediate dominators as the nearest common ancestor of | 391 // 2. Compute the immediate dominators as the nearest common ancestor of |
| 387 // spanning tree parent and semidominator, for all blocks except the entry. | 392 // spanning tree parent and semidominator, for all blocks except the entry. |
| 388 for (intptr_t block_index = 1; block_index < size; ++block_index) { | 393 for (intptr_t block_index = 1; block_index < size; ++block_index) { |
| 389 intptr_t dom_index = idom[block_index]; | 394 intptr_t dom_index = idom[block_index]; |
| 390 while (dom_index > semi[block_index]) { | 395 while (dom_index > semi[block_index]) { |
| 391 dom_index = idom[dom_index]; | 396 dom_index = idom[dom_index]; |
| 392 } | 397 } |
| 393 idom[block_index] = dom_index; | 398 idom[block_index] = dom_index; |
| 394 preorder_[block_index]->set_dominator(preorder_[dom_index]); | 399 (*preorder)[block_index]->set_dominator((*preorder)[dom_index]); |
| 395 preorder_[dom_index]->AddDominatedBlock(preorder_[block_index]); | 400 (*preorder)[dom_index]->AddDominatedBlock((*preorder)[block_index]); |
| 396 } | 401 } |
| 397 | 402 |
| 398 // 3. Now compute the dominance frontier for all blocks. This is | 403 // 3. Now compute the dominance frontier for all blocks. This is |
| 399 // algorithm in "A Simple, Fast Dominance Algorithm" (Figure 5), which is | 404 // algorithm in "A Simple, Fast Dominance Algorithm" (Figure 5), which is |
| 400 // attributed to a paper by Ferrante et al. There is no bookkeeping | 405 // attributed to a paper by Ferrante et al. There is no bookkeeping |
| 401 // required to avoid adding a block twice to the same block's dominance | 406 // required to avoid adding a block twice to the same block's dominance |
| 402 // frontier because we use a set to represent the dominance frontier. | 407 // frontier because we use a set to represent the dominance frontier. |
| 403 for (intptr_t block_index = 0; block_index < size; ++block_index) { | 408 for (intptr_t block_index = 0; block_index < size; ++block_index) { |
| 404 BlockEntryInstr* block = preorder_[block_index]; | 409 BlockEntryInstr* block = (*preorder)[block_index]; |
| 405 intptr_t count = block->PredecessorCount(); | 410 intptr_t count = block->PredecessorCount(); |
| 406 if (count <= 1) continue; | 411 if (count <= 1) continue; |
| 407 for (intptr_t i = 0; i < count; ++i) { | 412 for (intptr_t i = 0; i < count; ++i) { |
| 408 BlockEntryInstr* runner = block->PredecessorAt(i); | 413 BlockEntryInstr* runner = block->PredecessorAt(i); |
| 409 while (runner != block->dominator()) { | 414 while (runner != block->dominator()) { |
| 410 (*dominance_frontier)[runner->preorder_number()]->Add(block_index); | 415 (*dominance_frontier)[runner->preorder_number()]->Add(block_index); |
| 411 runner = runner->dominator(); | 416 runner = runner->dominator(); |
| 412 } | 417 } |
| 413 } | 418 } |
| 414 } | 419 } |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 // TODO(zerny): Support multiple exits. | 807 // TODO(zerny): Support multiple exits. |
| 803 UNREACHABLE(); | 808 UNREACHABLE(); |
| 804 } | 809 } |
| 805 | 810 |
| 806 // TODO(zerny): Adjust pre/post orders. | 811 // TODO(zerny): Adjust pre/post orders. |
| 807 // TODO(zerny): Update dominator tree. | 812 // TODO(zerny): Update dominator tree. |
| 808 } | 813 } |
| 809 | 814 |
| 810 | 815 |
| 811 } // namespace dart | 816 } // namespace dart |
| OLD | NEW |