| 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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 static intptr_t MembershipCount(Value* use, Value* list) { | 118 static intptr_t MembershipCount(Value* use, Value* list) { |
| 119 intptr_t count = 0; | 119 intptr_t count = 0; |
| 120 while (list != NULL) { | 120 while (list != NULL) { |
| 121 if (list == use) ++count; | 121 if (list == use) ++count; |
| 122 list = list->next_use(); | 122 list = list->next_use(); |
| 123 } | 123 } |
| 124 return count; | 124 return count; |
| 125 } | 125 } |
| 126 | 126 |
| 127 | 127 |
| 128 static void ResetUseListsInInstruction(Instruction* instr) { |
| 129 Definition* defn = instr->AsDefinition(); |
| 130 if (defn != NULL) { |
| 131 defn->set_input_use_list(NULL); |
| 132 defn->set_env_use_list(NULL); |
| 133 } |
| 134 for (intptr_t i = 0; i < instr->InputCount(); ++i) { |
| 135 Value* use = instr->InputAt(i); |
| 136 use->set_instruction(NULL); |
| 137 use->set_use_index(-1); |
| 138 use->set_previous_use(NULL); |
| 139 use->set_next_use(NULL); |
| 140 } |
| 141 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
| 142 Value* use = it.CurrentValue(); |
| 143 use->set_instruction(NULL); |
| 144 use->set_use_index(-1); |
| 145 use->set_previous_use(NULL); |
| 146 use->set_next_use(NULL); |
| 147 } |
| 148 } |
| 149 |
| 150 |
| 151 bool FlowGraph::ResetUseLists() { |
| 152 // Reset initial definitions. |
| 153 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) { |
| 154 ResetUseListsInInstruction((*graph_entry_->initial_definitions())[i]); |
| 155 } |
| 156 |
| 157 // Reset phis in join entries and the instructions in each block. |
| 158 for (intptr_t i = 0; i < preorder_.length(); ++i) { |
| 159 BlockEntryInstr* entry = preorder_[i]; |
| 160 JoinEntryInstr* join = entry->AsJoinEntry(); |
| 161 if (join != NULL && join->phis() != NULL) { |
| 162 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| 163 PhiInstr* phi = (*join->phis())[i]; |
| 164 if (phi != NULL) ResetUseListsInInstruction(phi); |
| 165 } |
| 166 } |
| 167 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 168 ResetUseListsInInstruction(it.Current()); |
| 169 } |
| 170 } |
| 171 return true; // Return true so we can ASSERT the reset code. |
| 172 } |
| 173 |
| 174 |
| 128 static void VerifyUseListsInInstruction(Instruction* instr) { | 175 static void VerifyUseListsInInstruction(Instruction* instr) { |
| 129 ASSERT(instr != NULL); | 176 ASSERT(instr != NULL); |
| 130 ASSERT(!instr->IsJoinEntry()); | 177 ASSERT(!instr->IsJoinEntry()); |
| 131 for (intptr_t i = 0; i < instr->InputCount(); ++i) { | 178 for (intptr_t i = 0; i < instr->InputCount(); ++i) { |
| 132 Value* use = instr->InputAt(i); | 179 Value* use = instr->InputAt(i); |
| 133 ASSERT(use->definition() != NULL); | 180 ASSERT(use->definition() != NULL); |
| 134 ASSERT(use->definition() != instr); | 181 ASSERT(use->definition() != instr); |
| 135 ASSERT(use->instruction() == instr); | 182 ASSERT(use->instruction() == instr); |
| 136 ASSERT(use->use_index() == i); | 183 ASSERT(use->use_index() == i); |
| 137 ASSERT(!FLAG_verify_compiler || | 184 ASSERT(!FLAG_verify_compiler || |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 } | 251 } |
| 205 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 252 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 206 VerifyUseListsInInstruction(it.Current()); | 253 VerifyUseListsInInstruction(it.Current()); |
| 207 } | 254 } |
| 208 } | 255 } |
| 209 return true; // Return true so we can ASSERT validation. | 256 return true; // Return true so we can ASSERT validation. |
| 210 } | 257 } |
| 211 #endif // DEBUG | 258 #endif // DEBUG |
| 212 | 259 |
| 213 | 260 |
| 261 static void ClearUseLists(Definition* defn) { |
| 262 ASSERT(defn != NULL); |
| 263 ASSERT(!defn->HasUses()); |
| 264 defn->set_input_use_list(NULL); |
| 265 defn->set_env_use_list(NULL); |
| 266 } |
| 267 |
| 268 |
| 269 static void RecordInputUses(Instruction* instr) { |
| 270 ASSERT(instr != NULL); |
| 271 for (intptr_t i = 0; i < instr->InputCount(); ++i) { |
| 272 Value* use = instr->InputAt(i); |
| 273 ASSERT(use->instruction() == NULL); |
| 274 ASSERT(use->use_index() == -1); |
| 275 ASSERT(use->previous_use() == NULL); |
| 276 ASSERT(use->next_use() == NULL); |
| 277 DEBUG_ASSERT(!FLAG_verify_compiler || |
| 278 (0 == MembershipCount(use, use->definition()->input_use_list()))); |
| 279 use->set_instruction(instr); |
| 280 use->set_use_index(i); |
| 281 use->definition()->AddInputUse(use); |
| 282 } |
| 283 } |
| 284 |
| 285 |
| 286 static void RecordEnvUses(Instruction* instr) { |
| 287 ASSERT(instr != NULL); |
| 288 if (instr->env() == NULL) return; |
| 289 intptr_t use_index = 0; |
| 290 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
| 291 Value* use = it.CurrentValue(); |
| 292 ASSERT(use->instruction() == NULL); |
| 293 ASSERT(use->use_index() == -1); |
| 294 ASSERT(use->previous_use() == NULL); |
| 295 ASSERT(use->next_use() == NULL); |
| 296 DEBUG_ASSERT(!FLAG_verify_compiler || |
| 297 (0 == MembershipCount(use, use->definition()->env_use_list()))); |
| 298 use->set_instruction(instr); |
| 299 use->set_use_index(use_index++); |
| 300 use->definition()->AddEnvUse(use); |
| 301 } |
| 302 } |
| 303 |
| 304 |
| 305 static void ComputeUseListsRecursive(BlockEntryInstr* block) { |
| 306 // Clear phi definitions. |
| 307 JoinEntryInstr* join = block->AsJoinEntry(); |
| 308 if (join != NULL && join->phis() != NULL) { |
| 309 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| 310 PhiInstr* phi = (*join->phis())[i]; |
| 311 if (phi != NULL) ClearUseLists(phi); |
| 312 } |
| 313 } |
| 314 // Compute uses on normal instructions. |
| 315 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 316 Instruction* instr = it.Current(); |
| 317 if (instr->IsDefinition()) ClearUseLists(instr->AsDefinition()); |
| 318 RecordInputUses(instr); |
| 319 RecordEnvUses(instr); |
| 320 } |
| 321 // Compute recursively on dominated blocks. |
| 322 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { |
| 323 ComputeUseListsRecursive(block->dominated_blocks()[i]); |
| 324 } |
| 325 // Add phi uses on successor edges. |
| 326 if (block->last_instruction()->SuccessorCount() == 1 && |
| 327 block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { |
| 328 JoinEntryInstr* join = |
| 329 block->last_instruction()->SuccessorAt(0)->AsJoinEntry(); |
| 330 intptr_t pred_index = join->IndexOfPredecessor(block); |
| 331 ASSERT(pred_index >= 0); |
| 332 if (join->phis() != NULL) { |
| 333 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| 334 PhiInstr* phi = (*join->phis())[i]; |
| 335 if (phi == NULL) continue; |
| 336 Value* use = phi->InputAt(pred_index); |
| 337 ASSERT(use->instruction() == NULL); |
| 338 ASSERT(use->use_index() == -1); |
| 339 ASSERT(use->previous_use() == NULL); |
| 340 ASSERT(use->next_use() == NULL); |
| 341 DEBUG_ASSERT(!FLAG_verify_compiler || |
| 342 (0 == MembershipCount(use, use->definition()->input_use_list()))); |
| 343 use->set_instruction(phi); |
| 344 use->set_use_index(pred_index); |
| 345 use->definition()->AddInputUse(use); |
| 346 } |
| 347 } |
| 348 } |
| 349 } |
| 350 |
| 351 |
| 352 void FlowGraph::ComputeUseLists() { |
| 353 DEBUG_ASSERT(ResetUseLists()); |
| 354 // Clear initial definitions. |
| 355 for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) { |
| 356 ClearUseLists((*graph_entry_->initial_definitions())[i]); |
| 357 } |
| 358 ComputeUseListsRecursive(graph_entry_); |
| 359 DEBUG_ASSERT(!FLAG_verify_compiler || VerifyUseLists()); |
| 360 } |
| 361 |
| 362 |
| 214 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number, | 363 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number, |
| 215 GrowableArray<Definition*>* inlining_parameters) { | 364 GrowableArray<Definition*>* inlining_parameters) { |
| 216 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); | 365 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); |
| 217 current_ssa_temp_index_ = next_virtual_register_number; | 366 current_ssa_temp_index_ = next_virtual_register_number; |
| 218 GrowableArray<BitVector*> dominance_frontier; | 367 GrowableArray<BitVector*> dominance_frontier; |
| 219 ComputeDominators(&dominance_frontier); | 368 ComputeDominators(&dominance_frontier); |
| 220 InsertPhis(preorder_, assigned_vars_, dominance_frontier); | 369 InsertPhis(preorder_, assigned_vars_, dominance_frontier); |
| 221 GrowableArray<PhiInstr*> live_phis; | 370 GrowableArray<PhiInstr*> live_phis; |
| 222 // Rename uses to reference inserted phis where appropriate. | 371 // Rename uses to reference inserted phis where appropriate. |
| 223 // Collect phis that reach a non-environment use. | 372 // Collect phis that reach a non-environment use. |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 } | 612 } |
| 464 } | 613 } |
| 465 | 614 |
| 466 // 2. Process normal instructions. | 615 // 2. Process normal instructions. |
| 467 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { | 616 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { |
| 468 Instruction* current = it.Current(); | 617 Instruction* current = it.Current(); |
| 469 // Attach current environment to the instructions that can deoptimize and | 618 // Attach current environment to the instructions that can deoptimize and |
| 470 // at goto instructions. Optimizations like LICM expect an environment at | 619 // at goto instructions. Optimizations like LICM expect an environment at |
| 471 // gotos. | 620 // gotos. |
| 472 if (current->CanDeoptimize() || current->IsGoto()) { | 621 if (current->CanDeoptimize() || current->IsGoto()) { |
| 473 Environment* deopt_env = | 622 current->set_env(Environment::From(*env, |
| 474 Environment::From(*env, | 623 num_non_copied_params_, |
| 475 num_non_copied_params_, | 624 parsed_function_.function())); |
| 476 parsed_function_.function()); | |
| 477 current->set_env(deopt_env); | |
| 478 intptr_t use_index = 0; | |
| 479 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { | |
| 480 Value* use = it.CurrentValue(); | |
| 481 use->set_instruction(current); | |
| 482 use->set_use_index(use_index++); | |
| 483 use->definition()->AddEnvUse(use); | |
| 484 } | |
| 485 } | 625 } |
| 486 if (current->CanDeoptimize()) { | 626 if (current->CanDeoptimize()) { |
| 487 current->env()->set_deopt_id(current->deopt_id()); | 627 current->env()->set_deopt_id(current->deopt_id()); |
| 488 } | 628 } |
| 489 | 629 |
| 490 // 2a. Handle uses: | 630 // 2a. Handle uses: |
| 491 // Update expression stack environment for each use. | 631 // Update expression stack environment for each use. |
| 492 // For each use of a LoadLocal or StoreLocal: Replace it with the value | 632 // For each use of a LoadLocal or StoreLocal: Replace it with the value |
| 493 // from the environment. | 633 // from the environment. |
| 494 for (intptr_t i = current->InputCount() - 1; i >= 0; --i) { | 634 for (intptr_t i = current->InputCount() - 1; i >= 0; --i) { |
| 495 Value* v = current->InputAt(i); | 635 Value* v = current->InputAt(i); |
| 496 // Update expression stack. | 636 // Update expression stack. |
| 497 ASSERT(env->length() > variable_count()); | 637 ASSERT(env->length() > variable_count()); |
| 498 | 638 |
| 499 Definition* reaching_defn = env->RemoveLast(); | 639 Definition* reaching_defn = env->RemoveLast(); |
| 500 | 640 |
| 501 Definition* input_defn = v->definition(); | 641 Definition* input_defn = v->definition(); |
| 502 if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) { | 642 if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) { |
| 503 // Remove the load/store from the graph. | 643 // Remove the load/store from the graph. |
| 504 input_defn->UnuseAllInputs(); | |
| 505 input_defn->RemoveFromGraph(); | 644 input_defn->RemoveFromGraph(); |
| 506 // Assert we are not referencing nulls in the initial environment. | 645 // Assert we are not referencing nulls in the initial environment. |
| 507 ASSERT(reaching_defn->ssa_temp_index() != -1); | 646 ASSERT(reaching_defn->ssa_temp_index() != -1); |
| 508 v->set_definition(reaching_defn); | 647 current->SetInputAt(i, new Value(reaching_defn)); |
| 509 input_defn = reaching_defn; | |
| 510 } | 648 } |
| 511 v->set_instruction(current); | |
| 512 v->set_use_index(i); | |
| 513 input_defn->AddInputUse(v); | |
| 514 } | 649 } |
| 515 | 650 |
| 516 // Drop pushed arguments for calls. | 651 // Drop pushed arguments for calls. |
| 517 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { | 652 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { |
| 518 env->RemoveLast(); | 653 env->RemoveLast(); |
| 519 } | 654 } |
| 520 | 655 |
| 521 // 2b. Handle LoadLocal and StoreLocal. | 656 // 2b. Handle LoadLocal and StoreLocal. |
| 522 // For each LoadLocal: Remove it from the graph. | 657 // For each LoadLocal: Remove it from the graph. |
| 523 // For each StoreLocal: Remove it from the graph and update the environment. | 658 // For each StoreLocal: Remove it from the graph and update the environment. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 541 if ((phi != NULL) && !phi->is_alive()) { | 676 if ((phi != NULL) && !phi->is_alive()) { |
| 542 phi->mark_alive(); | 677 phi->mark_alive(); |
| 543 live_phis->Add(phi); | 678 live_phis->Add(phi); |
| 544 } | 679 } |
| 545 } | 680 } |
| 546 // Update expression stack or remove from graph. | 681 // Update expression stack or remove from graph. |
| 547 if (definition->is_used()) { | 682 if (definition->is_used()) { |
| 548 env->Add((*env)[index]); | 683 env->Add((*env)[index]); |
| 549 // We remove load/store instructions when we find their use in 2a. | 684 // We remove load/store instructions when we find their use in 2a. |
| 550 } else { | 685 } else { |
| 551 definition->UnuseAllInputs(); | |
| 552 it.RemoveCurrentFromGraph(); | 686 it.RemoveCurrentFromGraph(); |
| 553 } | 687 } |
| 554 } else { | 688 } else { |
| 555 // Not a load or store. | 689 // Not a load or store. |
| 556 if (definition->is_used()) { | 690 if (definition->is_used()) { |
| 557 // Assign fresh SSA temporary and update expression stack. | 691 // Assign fresh SSA temporary and update expression stack. |
| 558 definition->set_ssa_temp_index(alloc_ssa_temp_index()); | 692 definition->set_ssa_temp_index(alloc_ssa_temp_index()); |
| 559 env->Add(definition); | 693 env->Add(definition); |
| 560 } | 694 } |
| 561 } | 695 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 582 block_entry->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { | 716 block_entry->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { |
| 583 JoinEntryInstr* successor = | 717 JoinEntryInstr* successor = |
| 584 block_entry->last_instruction()->SuccessorAt(0)->AsJoinEntry(); | 718 block_entry->last_instruction()->SuccessorAt(0)->AsJoinEntry(); |
| 585 intptr_t pred_index = successor->IndexOfPredecessor(block_entry); | 719 intptr_t pred_index = successor->IndexOfPredecessor(block_entry); |
| 586 ASSERT(pred_index >= 0); | 720 ASSERT(pred_index >= 0); |
| 587 if (successor->phis() != NULL) { | 721 if (successor->phis() != NULL) { |
| 588 for (intptr_t i = 0; i < successor->phis()->length(); ++i) { | 722 for (intptr_t i = 0; i < successor->phis()->length(); ++i) { |
| 589 PhiInstr* phi = (*successor->phis())[i]; | 723 PhiInstr* phi = (*successor->phis())[i]; |
| 590 if (phi != NULL) { | 724 if (phi != NULL) { |
| 591 // Rename input operand. | 725 // Rename input operand. |
| 592 Value* use = new Value((*env)[i]); | 726 phi->SetInputAt(pred_index, new Value((*env)[i])); |
| 593 phi->SetInputAt(pred_index, use); | |
| 594 use->set_instruction(phi); | |
| 595 use->set_use_index(pred_index); | |
| 596 use->definition()->AddInputUse(use); | |
| 597 } | 727 } |
| 598 } | 728 } |
| 599 } | 729 } |
| 600 } | 730 } |
| 601 } | 731 } |
| 602 | 732 |
| 603 | 733 |
| 604 void FlowGraph::MarkLivePhis(GrowableArray<PhiInstr*>* live_phis) { | 734 void FlowGraph::MarkLivePhis(GrowableArray<PhiInstr*>* live_phis) { |
| 605 while (!live_phis->is_empty()) { | 735 while (!live_phis->is_empty()) { |
| 606 PhiInstr* phi = live_phis->RemoveLast(); | 736 PhiInstr* phi = live_phis->RemoveLast(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 !it.Done(); | 830 !it.Done(); |
| 701 it.Advance()) { | 831 it.Advance()) { |
| 702 ++size; | 832 ++size; |
| 703 } | 833 } |
| 704 } | 834 } |
| 705 return size; | 835 return size; |
| 706 } | 836 } |
| 707 | 837 |
| 708 | 838 |
| 709 } // namespace dart | 839 } // namespace dart |
| OLD | NEW |