| 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_allocator.h" | 5 #include "vm/flow_graph_allocator.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 blocked_cpu_registers_[FPREG] = true; | 83 blocked_cpu_registers_[FPREG] = true; |
| 84 | 84 |
| 85 // XMM0 is used as scratch by optimized code and parallel move resolver. | 85 // XMM0 is used as scratch by optimized code and parallel move resolver. |
| 86 blocked_xmm_registers_[XMM0] = true; | 86 blocked_xmm_registers_[XMM0] = true; |
| 87 } | 87 } |
| 88 | 88 |
| 89 | 89 |
| 90 // Remove environments from the instructions which can't deoptimize. | 90 // Remove environments from the instructions which can't deoptimize. |
| 91 // Replace dead phis uses with null values in environments. | 91 // Replace dead phis uses with null values in environments. |
| 92 void FlowGraphAllocator::EliminateEnvironmentUses() { | 92 void FlowGraphAllocator::EliminateEnvironmentUses() { |
| 93 ConstantVal* null_value = new ConstantVal(Object::ZoneHandle()); | 93 Definition* constant_null = |
| 94 | 94 postorder_.Last()->AsGraphEntry()->constant_null(); |
| 95 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 95 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 96 BlockEntryInstr* block = block_order_[i]; | 96 BlockEntryInstr* block = block_order_[i]; |
| 97 | |
| 98 if (block->IsJoinEntry()) block->AsJoinEntry()->RemoveDeadPhis(); | 97 if (block->IsJoinEntry()) block->AsJoinEntry()->RemoveDeadPhis(); |
| 99 | |
| 100 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 98 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 101 Instruction* current = it.Current(); | 99 Instruction* current = it.Current(); |
| 102 if (current->CanDeoptimize()) { | 100 if (current->CanDeoptimize()) { |
| 103 ASSERT(current->env() != NULL); | 101 ASSERT(current->env() != NULL); |
| 104 GrowableArray<Value*>* values = current->env()->values_ptr(); | 102 GrowableArray<Value*>* values = current->env()->values_ptr(); |
| 105 | |
| 106 for (intptr_t i = 0; i < values->length(); i++) { | 103 for (intptr_t i = 0; i < values->length(); i++) { |
| 107 UseVal* use = (*values)[i]->AsUse(); | 104 UseVal* use = (*values)[i]->AsUse(); |
| 108 if (use == NULL) continue; | 105 if (use == NULL) continue; |
| 109 | 106 |
| 110 Definition* def = use->definition(); | 107 Definition* def = use->definition(); |
| 111 | |
| 112 PushArgumentInstr* push_argument = def->AsPushArgument(); | 108 PushArgumentInstr* push_argument = def->AsPushArgument(); |
| 113 if ((push_argument != NULL) && push_argument->WasEliminated()) { | 109 if ((push_argument != NULL) && push_argument->WasEliminated()) { |
| 114 (*values)[i] = push_argument->value()->CopyValue(); | 110 (*values)[i] = push_argument->value()->CopyValue(); |
| 115 continue; | 111 continue; |
| 116 } | 112 } |
| 117 | 113 |
| 118 PhiInstr* phi = def->AsPhi(); | 114 PhiInstr* phi = def->AsPhi(); |
| 119 if ((phi != NULL) && !phi->is_alive()) { | 115 if ((phi != NULL) && !phi->is_alive()) { |
| 120 (*values)[i] = null_value; | 116 (*values)[i] = new UseVal(constant_null); |
| 121 continue; | 117 continue; |
| 122 } | 118 } |
| 123 } | 119 } |
| 124 } else { | 120 } else { |
| 125 current->set_env(NULL); | 121 current->set_env(NULL); |
| 126 } | 122 } |
| 127 } | 123 } |
| 128 } | 124 } |
| 129 } | 125 } |
| 130 | 126 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 live_in_[pred->postorder_number()]->Add(use); | 187 live_in_[pred->postorder_number()]->Add(use); |
| 192 } | 188 } |
| 193 } | 189 } |
| 194 } | 190 } |
| 195 } | 191 } |
| 196 } | 192 } |
| 197 } | 193 } |
| 198 } | 194 } |
| 199 | 195 |
| 200 // Process incoming parameters. | 196 // Process incoming parameters. |
| 201 GraphEntryInstr* graph_entry = postorder_[block_count - 1]->AsGraphEntry(); | 197 GraphEntryInstr* graph_entry = postorder_.Last()->AsGraphEntry(); |
| 202 for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { | 198 for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { |
| 203 Value* val = graph_entry->start_env()->values()[i]; | 199 Value* val = graph_entry->start_env()->values()[i]; |
| 204 if (val->IsUse()) { | 200 if (val->IsUse()) { |
| 205 const intptr_t vreg = val->AsUse()->definition()->ssa_temp_index(); | 201 intptr_t vreg = val->AsUse()->definition()->ssa_temp_index(); |
| 206 kill_[graph_entry->postorder_number()]->Add(vreg); | 202 kill_[graph_entry->postorder_number()]->Add(vreg); |
| 207 live_in_[graph_entry->postorder_number()]->Remove(vreg); | 203 live_in_[graph_entry->postorder_number()]->Remove(vreg); |
| 208 } | 204 } |
| 209 } | 205 } |
| 210 | 206 |
| 207 // Process global constants. |
| 208 intptr_t vreg = graph_entry->constant_null()->ssa_temp_index(); |
| 209 kill_[graph_entry->postorder_number()]->Add(vreg); |
| 210 live_in_[graph_entry->postorder_number()]->Remove(vreg); |
| 211 |
| 211 // Update initial live_in sets to match live_out sets. Has to be | 212 // Update initial live_in sets to match live_out sets. Has to be |
| 212 // done in a separate path because of backwards branches. | 213 // done in a separate path because of backwards branches. |
| 213 for (intptr_t i = 0; i < block_count; i++) { | 214 for (intptr_t i = 0; i < block_count; i++) { |
| 214 UpdateLiveIn(*postorder_[i]); | 215 UpdateLiveIn(*postorder_[i]); |
| 215 } | 216 } |
| 216 } | 217 } |
| 217 | 218 |
| 218 | 219 |
| 219 bool FlowGraphAllocator::UpdateLiveOut(const BlockEntryInstr& instr) { | 220 bool FlowGraphAllocator::UpdateLiveOut(const BlockEntryInstr& instr) { |
| 220 BitVector* live_out = live_out_[instr.postorder_number()]; | 221 BitVector* live_out = live_out_[instr.postorder_number()]; |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 for (intptr_t i = 0; i < live_ranges_.length(); i++) { | 493 for (intptr_t i = 0; i < live_ranges_.length(); i++) { |
| 493 if (live_ranges_[i] != NULL) { | 494 if (live_ranges_[i] != NULL) { |
| 494 live_ranges_[i]->Print(); | 495 live_ranges_[i]->Print(); |
| 495 } | 496 } |
| 496 } | 497 } |
| 497 } | 498 } |
| 498 | 499 |
| 499 | 500 |
| 500 void FlowGraphAllocator::BuildLiveRanges() { | 501 void FlowGraphAllocator::BuildLiveRanges() { |
| 501 const intptr_t block_count = postorder_.length(); | 502 const intptr_t block_count = postorder_.length(); |
| 502 ASSERT(postorder_[block_count - 1]->IsGraphEntry()); | 503 ASSERT(postorder_.Last()->IsGraphEntry()); |
| 503 for (intptr_t i = 0; i < (block_count - 1); i++) { | 504 for (intptr_t i = 0; i < (block_count - 1); i++) { |
| 504 BlockEntryInstr* block = postorder_[i]; | 505 BlockEntryInstr* block = postorder_[i]; |
| 505 | 506 |
| 506 // For every SSA value that is live out of this block, create an interval | 507 // For every SSA value that is live out of this block, create an interval |
| 507 // that covers the whole block. It will be shortened if we encounter a | 508 // that covers the whole block. It will be shortened if we encounter a |
| 508 // definition of this value in this block. | 509 // definition of this value in this block. |
| 509 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 510 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { |
| 510 LiveRange* range = GetLiveRange(it.Current()); | 511 LiveRange* range = GetLiveRange(it.Current()); |
| 511 range->AddUseInterval(block->start_pos(), block->end_pos()); | 512 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 512 } | 513 } |
| 513 | 514 |
| 514 // Connect outgoing phi-moves that were created in NumberInstructions | 515 // Connect outgoing phi-moves that were created in NumberInstructions |
| 515 // and find last instruction that contributes to liveness. | 516 // and find last instruction that contributes to liveness. |
| 516 Instruction* current = ConnectOutgoingPhiMoves(block); | 517 Instruction* current = ConnectOutgoingPhiMoves(block); |
| 517 | 518 |
| 518 // Now process all instructions in reverse order. | 519 // Now process all instructions in reverse order. |
| 519 while (current != block) { | 520 while (current != block) { |
| 520 // Skip parallel moves that we insert while processing instructions. | 521 // Skip parallel moves that we insert while processing instructions. |
| 521 if (!current->IsParallelMove()) { | 522 if (!current->IsParallelMove()) { |
| 522 ProcessOneInstruction(block, current); | 523 ProcessOneInstruction(block, current); |
| 523 } | 524 } |
| 524 current = current->previous(); | 525 current = current->previous(); |
| 525 } | 526 } |
| 526 | 527 |
| 527 ConnectIncomingPhiMoves(block); | 528 ConnectIncomingPhiMoves(block); |
| 528 } | 529 } |
| 529 | 530 |
| 530 // Process incoming parameters. Do this after all other instructions so | 531 // Process incoming parameters. Do this after all other instructions so |
| 531 // that safepoints for all calls have already been found. | 532 // that safepoints for all calls have already been found. |
| 532 GraphEntryInstr* graph_entry = postorder_[block_count - 1]->AsGraphEntry(); | 533 GraphEntryInstr* graph_entry = postorder_.Last()->AsGraphEntry(); |
| 533 for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { | 534 for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) { |
| 534 Value* val = graph_entry->start_env()->values()[i]; | 535 Value* val = graph_entry->start_env()->values()[i]; |
| 535 if (val->IsUse()) { | 536 ASSERT(val->IsUse()); |
| 536 ParameterInstr* param = val->AsUse()->definition()->AsParameter(); | 537 ParameterInstr* param = val->AsUse()->definition()->AsParameter(); |
| 538 if (param == NULL) continue; |
| 537 | 539 |
| 538 LiveRange* range = GetLiveRange(param->ssa_temp_index()); | 540 // Handle the parameters specially. They are spilled on entry. |
| 539 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); | 541 LiveRange* range = GetLiveRange(param->ssa_temp_index()); |
| 540 range->DefineAt(graph_entry->start_pos()); | 542 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); |
| 543 range->DefineAt(graph_entry->start_pos()); |
| 541 | 544 |
| 542 // Assert that copied and non-copied parameters are mutually exclusive. | 545 // Assert that copied and non-copied parameters are mutually exclusive. |
| 543 // This might change in the future and, if so, the index will be wrong. | 546 // This might change in the future and, if so, the index will be wrong. |
| 544 ASSERT(flow_graph_.copied_parameter_count() == 0 || | 547 ASSERT(flow_graph_.copied_parameter_count() == 0 || |
| 545 flow_graph_.non_copied_parameter_count() == 0); | 548 flow_graph_.non_copied_parameter_count() == 0); |
| 546 // Slot index for the leftmost copied parameter is 0. | 549 // Slot index for the leftmost copied parameter is 0. |
| 547 intptr_t slot_index = param->index(); | 550 intptr_t slot_index = param->index(); |
| 548 // Slot index for the rightmost fixed parameter is -1. | 551 // Slot index for the rightmost fixed parameter is -1. |
| 549 slot_index -= flow_graph_.non_copied_parameter_count(); | 552 slot_index -= flow_graph_.non_copied_parameter_count(); |
| 550 | 553 |
| 551 range->set_assigned_location(Location::StackSlot(slot_index)); | 554 range->set_assigned_location(Location::StackSlot(slot_index)); |
| 552 range->set_spill_slot(Location::StackSlot(slot_index)); | 555 range->set_spill_slot(Location::StackSlot(slot_index)); |
| 553 if (flow_graph_.copied_parameter_count() > 0) { | 556 if (flow_graph_.copied_parameter_count() > 0) { |
| 554 ASSERT(spill_slots_.length() == slot_index); | 557 ASSERT(spill_slots_.length() == slot_index); |
| 555 spill_slots_.Add(range->End()); | 558 spill_slots_.Add(range->End()); |
| 556 } | 559 } |
| 557 | 560 |
| 558 AssignSafepoints(range); | 561 AssignSafepoints(range); |
| 559 | 562 |
| 560 range->finger()->Initialize(range); | 563 range->finger()->Initialize(range); |
| 561 UsePosition* use = range->finger()->FirstRegisterBeneficialUse( | 564 UsePosition* use = |
| 562 graph_entry->start_pos()); | 565 range->finger()->FirstRegisterBeneficialUse(graph_entry->start_pos()); |
| 563 if (use != NULL) { | 566 if (use != NULL) { |
| 564 LiveRange* tail = SplitBetween(range, | 567 LiveRange* tail = |
| 565 graph_entry->start_pos(), | 568 SplitBetween(range, graph_entry->start_pos(), use->pos()); |
| 566 use->pos()); | 569 // All incoming parameters are tagged. |
| 567 | 570 CompleteRange(tail, Location::kRegister); |
| 568 // All incomming parameters are tagged. | 571 } |
| 569 CompleteRange(tail, Location::kRegister); | 572 ConvertAllUses(range); |
| 570 } | 573 if (flow_graph_.copied_parameter_count() > 0) { |
| 571 ConvertAllUses(range); | 574 MarkAsObjectAtSafepoints(range); |
| 572 if (flow_graph_.copied_parameter_count() > 0) { | |
| 573 MarkAsObjectAtSafepoints(range); | |
| 574 } | |
| 575 } | 575 } |
| 576 } | 576 } |
| 577 |
| 578 // Process global constants. |
| 579 BindInstr* null_defn = graph_entry->constant_null()->AsBind(); |
| 580 LiveRange* range = GetLiveRange(null_defn->ssa_temp_index()); |
| 581 range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos()); |
| 582 range->DefineAt(graph_entry->start_pos()); |
| 583 range->set_assigned_location( |
| 584 Location::Constant(null_defn->computation()->AsConstant()->value())); |
| 585 range->finger()->Initialize(range); |
| 586 UsePosition* use = |
| 587 range->finger()->FirstRegisterBeneficialUse(graph_entry->start_pos()); |
| 588 if (use != NULL) { |
| 589 LiveRange* tail = SplitBetween(range, graph_entry->start_pos(), use->pos()); |
| 590 CompleteRange(tail, Location::kRegister); |
| 591 } |
| 592 ConvertAllUses(range); |
| 577 } | 593 } |
| 578 | 594 |
| 595 |
| 579 // | 596 // |
| 580 // When describing shape of live ranges in comments below we are going to use | 597 // When describing shape of live ranges in comments below we are going to use |
| 581 // the following notation: | 598 // the following notation: |
| 582 // | 599 // |
| 583 // B block entry | 600 // B block entry |
| 584 // g g' start and end of goto instruction | 601 // g g' start and end of goto instruction |
| 585 // i i' start and end of any other instruction | 602 // i i' start and end of any other instruction |
| 586 // j j' start and end of any other instruction | 603 // j j' start and end of any other instruction |
| 587 | 604 |
| 588 // - body of a use interval | 605 // - body of a use interval |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 | 643 |
| 627 // Record the corresponding phi input use for each phi. | 644 // Record the corresponding phi input use for each phi. |
| 628 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 645 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 629 intptr_t move_idx = 0; | 646 intptr_t move_idx = 0; |
| 630 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { | 647 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { |
| 631 PhiInstr* phi = (*phis)[phi_idx]; | 648 PhiInstr* phi = (*phis)[phi_idx]; |
| 632 if (phi == NULL) continue; | 649 if (phi == NULL) continue; |
| 633 | 650 |
| 634 Value* val = phi->InputAt(pred_idx); | 651 Value* val = phi->InputAt(pred_idx); |
| 635 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); | 652 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); |
| 636 if (val->IsUse()) { | 653 ASSERT(val->IsUse()); |
| 637 // Expected shape of live ranges: | 654 // Expected shape of live ranges: |
| 638 // | 655 // |
| 639 // g g' | 656 // g g' |
| 640 // value --* | 657 // value --* |
| 641 // | 658 // |
| 642 | 659 |
| 643 LiveRange* range = GetLiveRange( | 660 LiveRange* range = |
| 644 val->AsUse()->definition()->ssa_temp_index()); | 661 GetLiveRange(val->AsUse()->definition()->ssa_temp_index()); |
| 645 | 662 |
| 646 range->AddUseInterval(block->start_pos(), pos); | 663 range->AddUseInterval(block->start_pos(), pos); |
| 647 range->AddHintedUse(pos, move->src_slot(), move->dest_slot()); | 664 range->AddHintedUse(pos, move->src_slot(), move->dest_slot()); |
| 648 | 665 |
| 649 move->set_src(Location::PrefersRegister()); | 666 move->set_src(Location::PrefersRegister()); |
| 650 } else { | |
| 651 ASSERT(val->IsConstant()); | |
| 652 move->set_src(Location::Constant(val->AsConstant()->value())); | |
| 653 } | |
| 654 move_idx++; | 667 move_idx++; |
| 655 } | 668 } |
| 656 | 669 |
| 657 // Begin backward iteration with the instruction before the parallel | 670 // Begin backward iteration with the instruction before the parallel |
| 658 // move. | 671 // move. |
| 659 return goto_instr->previous(); | 672 return goto_instr->previous(); |
| 660 } | 673 } |
| 661 | 674 |
| 662 | 675 |
| 663 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { | 676 void FlowGraphAllocator::ConnectIncomingPhiMoves(BlockEntryInstr* block) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 if (values.length() == 0) return; | 742 if (values.length() == 0) return; |
| 730 | 743 |
| 731 const intptr_t block_start_pos = block->start_pos(); | 744 const intptr_t block_start_pos = block->start_pos(); |
| 732 const intptr_t use_pos = current->lifetime_position() + 1; | 745 const intptr_t use_pos = current->lifetime_position() + 1; |
| 733 | 746 |
| 734 Location* locations = | 747 Location* locations = |
| 735 Isolate::Current()->current_zone()->Alloc<Location>(values.length()); | 748 Isolate::Current()->current_zone()->Alloc<Location>(values.length()); |
| 736 | 749 |
| 737 for (intptr_t i = 0; i < values.length(); ++i) { | 750 for (intptr_t i = 0; i < values.length(); ++i) { |
| 738 Value* value = values[i]; | 751 Value* value = values[i]; |
| 739 if (value->IsUse()) { | 752 ASSERT(value->IsUse()); |
| 740 locations[i] = Location::Any(); | 753 locations[i] = Location::Any(); |
| 741 Definition* def = value->AsUse()->definition(); | 754 Definition* def = value->AsUse()->definition(); |
| 742 | 755 |
| 743 if (def->IsPushArgument()) { | 756 if (def->IsPushArgument()) { |
| 744 // Frame size is unknown until after allocation. | 757 // Frame size is unknown until after allocation. |
| 745 locations[i] = Location::NoLocation(); | 758 locations[i] = Location::NoLocation(); |
| 746 continue; | 759 continue; |
| 747 } | 760 } |
| 748 | 761 |
| 749 const intptr_t vreg = def->ssa_temp_index(); | 762 const intptr_t vreg = def->ssa_temp_index(); |
| 750 LiveRange* range = GetLiveRange(vreg); | 763 LiveRange* range = GetLiveRange(vreg); |
| 751 range->AddUseInterval(block_start_pos, use_pos); | 764 range->AddUseInterval(block_start_pos, use_pos); |
| 752 range->AddUse(use_pos, &locations[i]); | 765 range->AddUse(use_pos, &locations[i]); |
| 753 } else { | |
| 754 ASSERT(value->IsConstant()); | |
| 755 locations[i] = Location::NoLocation(); | |
| 756 } | |
| 757 } | 766 } |
| 758 | 767 |
| 759 env->set_locations(locations); | 768 env->set_locations(locations); |
| 760 } | 769 } |
| 761 | 770 |
| 762 | 771 |
| 763 static Location::Kind RegisterKindFromPolicy(Location loc) { | 772 static Location::Kind RegisterKindFromPolicy(Location loc) { |
| 764 if (loc.policy() == Location::kRequiresXmmRegister) { | 773 if (loc.policy() == Location::kRequiresXmmRegister) { |
| 765 return Location::kXmmRegister; | 774 return Location::kXmmRegister; |
| 766 } else { | 775 } else { |
| (...skipping 1380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2147 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", | 2156 OS::Print("-- [after ssa allocator] ir [%s] -------------\n", |
| 2148 function.ToFullyQualifiedCString()); | 2157 function.ToFullyQualifiedCString()); |
| 2149 FlowGraphPrinter printer(flow_graph_, true); | 2158 FlowGraphPrinter printer(flow_graph_, true); |
| 2150 printer.PrintBlocks(); | 2159 printer.PrintBlocks(); |
| 2151 OS::Print("----------------------------------------------\n"); | 2160 OS::Print("----------------------------------------------\n"); |
| 2152 } | 2161 } |
| 2153 } | 2162 } |
| 2154 | 2163 |
| 2155 | 2164 |
| 2156 } // namespace dart | 2165 } // namespace dart |
| OLD | NEW |