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