| 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 | |
| 175 static void VerifyUseListsInInstruction(Instruction* instr) { | 128 static void VerifyUseListsInInstruction(Instruction* instr) { |
| 176 ASSERT(instr != NULL); | 129 ASSERT(instr != NULL); |
| 177 ASSERT(!instr->IsJoinEntry()); | 130 ASSERT(!instr->IsJoinEntry()); |
| 178 for (intptr_t i = 0; i < instr->InputCount(); ++i) { | 131 for (intptr_t i = 0; i < instr->InputCount(); ++i) { |
| 179 Value* use = instr->InputAt(i); | 132 Value* use = instr->InputAt(i); |
| 180 ASSERT(use->definition() != NULL); | 133 ASSERT(use->definition() != NULL); |
| 181 ASSERT(use->definition() != instr); | 134 ASSERT(use->definition() != instr); |
| 182 ASSERT(use->instruction() == instr); | 135 ASSERT(use->instruction() == instr); |
| 183 ASSERT(use->use_index() == i); | 136 ASSERT(use->use_index() == i); |
| 184 ASSERT(!FLAG_verify_compiler || | 137 ASSERT(!FLAG_verify_compiler || |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 } | 204 } |
| 252 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 205 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 253 VerifyUseListsInInstruction(it.Current()); | 206 VerifyUseListsInInstruction(it.Current()); |
| 254 } | 207 } |
| 255 } | 208 } |
| 256 return true; // Return true so we can ASSERT validation. | 209 return true; // Return true so we can ASSERT validation. |
| 257 } | 210 } |
| 258 #endif // DEBUG | 211 #endif // DEBUG |
| 259 | 212 |
| 260 | 213 |
| 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 | |
| 363 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number, | 214 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number, |
| 364 GrowableArray<Definition*>* inlining_parameters) { | 215 GrowableArray<Definition*>* inlining_parameters) { |
| 365 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); | 216 ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL)); |
| 366 current_ssa_temp_index_ = next_virtual_register_number; | 217 current_ssa_temp_index_ = next_virtual_register_number; |
| 367 GrowableArray<BitVector*> dominance_frontier; | 218 GrowableArray<BitVector*> dominance_frontier; |
| 368 ComputeDominators(&dominance_frontier); | 219 ComputeDominators(&dominance_frontier); |
| 369 InsertPhis(preorder_, assigned_vars_, dominance_frontier); | 220 InsertPhis(preorder_, assigned_vars_, dominance_frontier); |
| 370 GrowableArray<PhiInstr*> live_phis; | 221 GrowableArray<PhiInstr*> live_phis; |
| 371 // Rename uses to reference inserted phis where appropriate. | 222 // Rename uses to reference inserted phis where appropriate. |
| 372 // Collect phis that reach a non-environment use. | 223 // Collect phis that reach a non-environment use. |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 } | 463 } |
| 613 } | 464 } |
| 614 | 465 |
| 615 // 2. Process normal instructions. | 466 // 2. Process normal instructions. |
| 616 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { | 467 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { |
| 617 Instruction* current = it.Current(); | 468 Instruction* current = it.Current(); |
| 618 // Attach current environment to the instructions that can deoptimize and | 469 // Attach current environment to the instructions that can deoptimize and |
| 619 // at goto instructions. Optimizations like LICM expect an environment at | 470 // at goto instructions. Optimizations like LICM expect an environment at |
| 620 // gotos. | 471 // gotos. |
| 621 if (current->CanDeoptimize() || current->IsGoto()) { | 472 if (current->CanDeoptimize() || current->IsGoto()) { |
| 622 current->set_env(Environment::From(*env, | 473 Environment* deopt_env = |
| 623 num_non_copied_params_, | 474 Environment::From(*env, |
| 624 parsed_function_.function())); | 475 num_non_copied_params_, |
| 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 } |
| 625 } | 485 } |
| 626 if (current->CanDeoptimize()) { | 486 if (current->CanDeoptimize()) { |
| 627 current->env()->set_deopt_id(current->deopt_id()); | 487 current->env()->set_deopt_id(current->deopt_id()); |
| 628 } | 488 } |
| 629 | 489 |
| 630 // 2a. Handle uses: | 490 // 2a. Handle uses: |
| 631 // Update expression stack environment for each use. | 491 // Update expression stack environment for each use. |
| 632 // For each use of a LoadLocal or StoreLocal: Replace it with the value | 492 // For each use of a LoadLocal or StoreLocal: Replace it with the value |
| 633 // from the environment. | 493 // from the environment. |
| 634 for (intptr_t i = current->InputCount() - 1; i >= 0; --i) { | 494 for (intptr_t i = current->InputCount() - 1; i >= 0; --i) { |
| 635 Value* v = current->InputAt(i); | 495 Value* v = current->InputAt(i); |
| 636 // Update expression stack. | 496 // Update expression stack. |
| 637 ASSERT(env->length() > variable_count()); | 497 ASSERT(env->length() > variable_count()); |
| 638 | 498 |
| 639 Definition* reaching_defn = env->RemoveLast(); | 499 Definition* reaching_defn = env->RemoveLast(); |
| 640 | 500 |
| 641 Definition* input_defn = v->definition(); | 501 Definition* input_defn = v->definition(); |
| 642 if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) { | 502 if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) { |
| 643 // Remove the load/store from the graph. | 503 // Remove the load/store from the graph. |
| 504 input_defn->UnuseAllInputs(); |
| 644 input_defn->RemoveFromGraph(); | 505 input_defn->RemoveFromGraph(); |
| 645 // Assert we are not referencing nulls in the initial environment. | 506 // Assert we are not referencing nulls in the initial environment. |
| 646 ASSERT(reaching_defn->ssa_temp_index() != -1); | 507 ASSERT(reaching_defn->ssa_temp_index() != -1); |
| 647 current->SetInputAt(i, new Value(reaching_defn)); | 508 v->set_definition(reaching_defn); |
| 509 input_defn = reaching_defn; |
| 648 } | 510 } |
| 511 v->set_instruction(current); |
| 512 v->set_use_index(i); |
| 513 input_defn->AddInputUse(v); |
| 649 } | 514 } |
| 650 | 515 |
| 651 // Drop pushed arguments for calls. | 516 // Drop pushed arguments for calls. |
| 652 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { | 517 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { |
| 653 env->RemoveLast(); | 518 env->RemoveLast(); |
| 654 } | 519 } |
| 655 | 520 |
| 656 // 2b. Handle LoadLocal and StoreLocal. | 521 // 2b. Handle LoadLocal and StoreLocal. |
| 657 // For each LoadLocal: Remove it from the graph. | 522 // For each LoadLocal: Remove it from the graph. |
| 658 // For each StoreLocal: Remove it from the graph and update the environment. | 523 // For each StoreLocal: Remove it from the graph and update the environment. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 676 if ((phi != NULL) && !phi->is_alive()) { | 541 if ((phi != NULL) && !phi->is_alive()) { |
| 677 phi->mark_alive(); | 542 phi->mark_alive(); |
| 678 live_phis->Add(phi); | 543 live_phis->Add(phi); |
| 679 } | 544 } |
| 680 } | 545 } |
| 681 // Update expression stack or remove from graph. | 546 // Update expression stack or remove from graph. |
| 682 if (definition->is_used()) { | 547 if (definition->is_used()) { |
| 683 env->Add((*env)[index]); | 548 env->Add((*env)[index]); |
| 684 // We remove load/store instructions when we find their use in 2a. | 549 // We remove load/store instructions when we find their use in 2a. |
| 685 } else { | 550 } else { |
| 551 definition->UnuseAllInputs(); |
| 686 it.RemoveCurrentFromGraph(); | 552 it.RemoveCurrentFromGraph(); |
| 687 } | 553 } |
| 688 } else { | 554 } else { |
| 689 // Not a load or store. | 555 // Not a load or store. |
| 690 if (definition->is_used()) { | 556 if (definition->is_used()) { |
| 691 // Assign fresh SSA temporary and update expression stack. | 557 // Assign fresh SSA temporary and update expression stack. |
| 692 definition->set_ssa_temp_index(alloc_ssa_temp_index()); | 558 definition->set_ssa_temp_index(alloc_ssa_temp_index()); |
| 693 env->Add(definition); | 559 env->Add(definition); |
| 694 } | 560 } |
| 695 } | 561 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 716 block_entry->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { | 582 block_entry->last_instruction()->SuccessorAt(0)->IsJoinEntry()) { |
| 717 JoinEntryInstr* successor = | 583 JoinEntryInstr* successor = |
| 718 block_entry->last_instruction()->SuccessorAt(0)->AsJoinEntry(); | 584 block_entry->last_instruction()->SuccessorAt(0)->AsJoinEntry(); |
| 719 intptr_t pred_index = successor->IndexOfPredecessor(block_entry); | 585 intptr_t pred_index = successor->IndexOfPredecessor(block_entry); |
| 720 ASSERT(pred_index >= 0); | 586 ASSERT(pred_index >= 0); |
| 721 if (successor->phis() != NULL) { | 587 if (successor->phis() != NULL) { |
| 722 for (intptr_t i = 0; i < successor->phis()->length(); ++i) { | 588 for (intptr_t i = 0; i < successor->phis()->length(); ++i) { |
| 723 PhiInstr* phi = (*successor->phis())[i]; | 589 PhiInstr* phi = (*successor->phis())[i]; |
| 724 if (phi != NULL) { | 590 if (phi != NULL) { |
| 725 // Rename input operand. | 591 // Rename input operand. |
| 726 phi->SetInputAt(pred_index, new Value((*env)[i])); | 592 Value* use = 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); |
| 727 } | 597 } |
| 728 } | 598 } |
| 729 } | 599 } |
| 730 } | 600 } |
| 731 } | 601 } |
| 732 | 602 |
| 733 | 603 |
| 734 void FlowGraph::MarkLivePhis(GrowableArray<PhiInstr*>* live_phis) { | 604 void FlowGraph::MarkLivePhis(GrowableArray<PhiInstr*>* live_phis) { |
| 735 while (!live_phis->is_empty()) { | 605 while (!live_phis->is_empty()) { |
| 736 PhiInstr* phi = live_phis->RemoveLast(); | 606 PhiInstr* phi = live_phis->RemoveLast(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 !it.Done(); | 700 !it.Done(); |
| 831 it.Advance()) { | 701 it.Advance()) { |
| 832 ++size; | 702 ++size; |
| 833 } | 703 } |
| 834 } | 704 } |
| 835 return size; | 705 return size; |
| 836 } | 706 } |
| 837 | 707 |
| 838 | 708 |
| 839 } // namespace dart | 709 } // namespace dart |
| OLD | NEW |