| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/linkage.h" | 5 #include "src/compiler/linkage.h" |
| 6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
| 7 #include "src/string-stream.h" | 7 #include "src/string-stream.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 InstructionOperand* operand) { | 158 InstructionOperand* operand) { |
| 159 DCHECK(HasNoSpillType()); | 159 DCHECK(HasNoSpillType()); |
| 160 spills_at_definition_ = new (zone) | 160 spills_at_definition_ = new (zone) |
| 161 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); | 161 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); |
| 162 } | 162 } |
| 163 | 163 |
| 164 | 164 |
| 165 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, | 165 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
| 166 InstructionOperand* op, | 166 InstructionOperand* op, |
| 167 bool might_be_duplicated) { | 167 bool might_be_duplicated) { |
| 168 DCHECK_IMPLIES(op->IsConstant(), spills_at_definition_ == nullptr); |
| 168 DCHECK(!IsChild()); | 169 DCHECK(!IsChild()); |
| 169 auto zone = sequence->zone(); | 170 auto zone = sequence->zone(); |
| 170 for (auto to_spill = spills_at_definition_; to_spill != nullptr; | 171 for (auto to_spill = spills_at_definition_; to_spill != nullptr; |
| 171 to_spill = to_spill->next) { | 172 to_spill = to_spill->next) { |
| 172 auto instr = sequence->InstructionAt(to_spill->gap_index); | 173 auto instr = sequence->InstructionAt(to_spill->gap_index); |
| 173 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); | 174 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); |
| 174 // Skip insertion if it's possible that the move exists already as a | 175 // Skip insertion if it's possible that the move exists already as a |
| 175 // constraint move from a fixed output register to a slot. | 176 // constraint move from a fixed output register to a slot. |
| 176 if (might_be_duplicated) { | 177 if (might_be_duplicated) { |
| 177 bool found = false; | 178 bool found = false; |
| 178 auto move_ops = move->move_operands(); | 179 auto move_ops = move->move_operands(); |
| 179 for (auto move_op = move_ops->begin(); move_op != move_ops->end(); | 180 for (auto move_op = move_ops->begin(); move_op != move_ops->end(); |
| 180 ++move_op) { | 181 ++move_op) { |
| 181 if (move_op->IsEliminated()) continue; | 182 if (move_op->IsEliminated()) continue; |
| 182 if (move_op->source()->Equals(to_spill->operand) && | 183 if (move_op->source()->Equals(to_spill->operand) && |
| 183 move_op->destination()->Equals(op)) { | 184 move_op->destination()->Equals(op)) { |
| 184 found = true; | 185 found = true; |
| 185 break; | 186 break; |
| 186 } | 187 } |
| 187 } | 188 } |
| 188 if (found) continue; | 189 if (found) continue; |
| 189 } | 190 } |
| 190 move->AddMove(to_spill->operand, op, zone); | 191 move->AddMove(to_spill->operand, op, zone); |
| 191 } | 192 } |
| 192 } | 193 } |
| 193 | 194 |
| 194 | 195 |
| 195 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 196 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
| 196 DCHECK(HasNoSpillType()); | 197 DCHECK(HasNoSpillType()); |
| 197 DCHECK(!operand->IsUnallocated()); | 198 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); |
| 198 spill_type_ = SpillType::kSpillOperand; | 199 spill_type_ = SpillType::kSpillOperand; |
| 199 spill_operand_ = operand; | 200 spill_operand_ = operand; |
| 200 } | 201 } |
| 201 | 202 |
| 202 | 203 |
| 203 void LiveRange::SetSpillRange(SpillRange* spill_range) { | 204 void LiveRange::SetSpillRange(SpillRange* spill_range) { |
| 204 DCHECK(HasNoSpillType() || HasSpillRange()); | 205 DCHECK(HasNoSpillType() || HasSpillRange()); |
| 205 DCHECK(spill_range); | 206 DCHECK(spill_range); |
| 206 spill_type_ = SpillType::kSpillRange; | 207 spill_type_ = SpillType::kSpillRange; |
| 207 spill_range_ = spill_range; | 208 spill_range_ = spill_range; |
| 208 } | 209 } |
| 209 | 210 |
| 210 | 211 |
| 211 void LiveRange::CommitSpillOperand(InstructionOperand* operand) { | 212 void LiveRange::CommitSpillOperand(AllocatedOperand* operand) { |
| 212 DCHECK(HasSpillRange()); | 213 DCHECK(HasSpillRange()); |
| 213 DCHECK(!operand->IsUnallocated()); | |
| 214 DCHECK(!IsChild()); | 214 DCHECK(!IsChild()); |
| 215 spill_type_ = SpillType::kSpillOperand; | 215 spill_type_ = SpillType::kSpillOperand; |
| 216 spill_operand_ = operand; | 216 spill_operand_ = operand; |
| 217 } | 217 } |
| 218 | 218 |
| 219 | 219 |
| 220 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { | 220 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { |
| 221 UsePosition* use_pos = last_processed_use_; | 221 UsePosition* use_pos = last_processed_use_; |
| 222 if (use_pos == nullptr) use_pos = first_pos(); | 222 if (use_pos == nullptr) use_pos = first_pos(); |
| 223 while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) { | 223 while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 return use_pos->pos().Value() > pos.NextStart().End().Value(); | 267 return use_pos->pos().Value() > pos.NextStart().End().Value(); |
| 268 } | 268 } |
| 269 | 269 |
| 270 | 270 |
| 271 InstructionOperand* LiveRange::GetAssignedOperand( | 271 InstructionOperand* LiveRange::GetAssignedOperand( |
| 272 InstructionOperandCache* cache) const { | 272 InstructionOperandCache* cache) const { |
| 273 if (HasRegisterAssigned()) { | 273 if (HasRegisterAssigned()) { |
| 274 DCHECK(!IsSpilled()); | 274 DCHECK(!IsSpilled()); |
| 275 switch (Kind()) { | 275 switch (Kind()) { |
| 276 case GENERAL_REGISTERS: | 276 case GENERAL_REGISTERS: |
| 277 return cache->RegisterOperand(assigned_register()); | 277 return cache->GetRegisterOperand(assigned_register()); |
| 278 case DOUBLE_REGISTERS: | 278 case DOUBLE_REGISTERS: |
| 279 return cache->DoubleRegisterOperand(assigned_register()); | 279 return cache->GetDoubleRegisterOperand(assigned_register()); |
| 280 default: | 280 default: |
| 281 UNREACHABLE(); | 281 UNREACHABLE(); |
| 282 } | 282 } |
| 283 } | 283 } |
| 284 DCHECK(IsSpilled()); | 284 DCHECK(IsSpilled()); |
| 285 DCHECK(!HasRegisterAssigned()); | 285 DCHECK(!HasRegisterAssigned()); |
| 286 auto op = TopLevel()->GetSpillOperand(); | 286 auto op = TopLevel()->GetSpillOperand(); |
| 287 DCHECK(!op->IsUnallocated()); | 287 DCHECK(!op->IsUnallocated()); |
| 288 return op; | 288 return op; |
| 289 } | 289 } |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 InstructionOperand* spill_op) { | 530 InstructionOperand* spill_op) { |
| 531 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { | 531 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
| 532 DCHECK(Start().Value() <= pos->pos().Value() && | 532 DCHECK(Start().Value() <= pos->pos().Value() && |
| 533 pos->pos().Value() <= End().Value()); | 533 pos->pos().Value() <= End().Value()); |
| 534 if (!pos->HasOperand()) { | 534 if (!pos->HasOperand()) { |
| 535 continue; | 535 continue; |
| 536 } | 536 } |
| 537 switch (pos->type()) { | 537 switch (pos->type()) { |
| 538 case UsePositionType::kRequiresSlot: | 538 case UsePositionType::kRequiresSlot: |
| 539 if (spill_op != nullptr) { | 539 if (spill_op != nullptr) { |
| 540 pos->operand()->ConvertTo(spill_op->kind(), spill_op->index()); | 540 InstructionOperand::ReplaceWith(pos->operand(), spill_op); |
| 541 } | 541 } |
| 542 break; | 542 break; |
| 543 case UsePositionType::kRequiresRegister: | 543 case UsePositionType::kRequiresRegister: |
| 544 DCHECK(op->IsRegister() || op->IsDoubleRegister()); | 544 DCHECK(op->IsRegister() || op->IsDoubleRegister()); |
| 545 // Fall through. | 545 // Fall through. |
| 546 case UsePositionType::kAny: | 546 case UsePositionType::kAny: |
| 547 pos->operand()->ConvertTo(op->kind(), op->index()); | 547 InstructionOperand::ReplaceWith(pos->operand(), op); |
| 548 break; | 548 break; |
| 549 } | 549 } |
| 550 } | 550 } |
| 551 } | 551 } |
| 552 | 552 |
| 553 | 553 |
| 554 bool LiveRange::CanCover(LifetimePosition position) const { | 554 bool LiveRange::CanCover(LifetimePosition position) const { |
| 555 if (IsEmpty()) return false; | 555 if (IsEmpty()) return false; |
| 556 return Start().Value() <= position.Value() && | 556 return Start().Value() <= position.Value() && |
| 557 position.Value() < End().Value(); | 557 position.Value() < End().Value(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 } else { | 592 } else { |
| 593 b = b->next(); | 593 b = b->next(); |
| 594 } | 594 } |
| 595 } | 595 } |
| 596 return LifetimePosition::Invalid(); | 596 return LifetimePosition::Invalid(); |
| 597 } | 597 } |
| 598 | 598 |
| 599 | 599 |
| 600 InstructionOperandCache::InstructionOperandCache() { | 600 InstructionOperandCache::InstructionOperandCache() { |
| 601 for (size_t i = 0; i < arraysize(general_register_operands_); ++i) { | 601 for (size_t i = 0; i < arraysize(general_register_operands_); ++i) { |
| 602 general_register_operands_[i] = | 602 general_register_operands_[i] = RegisterOperand(static_cast<int>(i)); |
| 603 i::compiler::RegisterOperand(static_cast<int>(i)); | |
| 604 } | 603 } |
| 605 for (size_t i = 0; i < arraysize(double_register_operands_); ++i) { | 604 for (size_t i = 0; i < arraysize(double_register_operands_); ++i) { |
| 606 double_register_operands_[i] = | 605 double_register_operands_[i] = DoubleRegisterOperand(static_cast<int>(i)); |
| 607 i::compiler::DoubleRegisterOperand(static_cast<int>(i)); | |
| 608 } | 606 } |
| 609 } | 607 } |
| 610 | 608 |
| 611 | 609 |
| 612 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, | 610 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, |
| 613 Zone* zone, Frame* frame, | 611 Zone* zone, Frame* frame, |
| 614 InstructionSequence* code, | 612 InstructionSequence* code, |
| 615 const char* debug_name) | 613 const char* debug_name) |
| 616 : local_zone_(zone), | 614 : local_zone_(zone), |
| 617 frame_(frame), | 615 frame_(frame), |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 | 698 |
| 701 int RegisterAllocator::FixedDoubleLiveRangeID(int index) { | 699 int RegisterAllocator::FixedDoubleLiveRangeID(int index) { |
| 702 return -index - 1 - config()->num_general_registers(); | 700 return -index - 1 - config()->num_general_registers(); |
| 703 } | 701 } |
| 704 | 702 |
| 705 | 703 |
| 706 InstructionOperand* RegisterAllocator::AllocateFixed( | 704 InstructionOperand* RegisterAllocator::AllocateFixed( |
| 707 UnallocatedOperand* operand, int pos, bool is_tagged) { | 705 UnallocatedOperand* operand, int pos, bool is_tagged) { |
| 708 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); | 706 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); |
| 709 DCHECK(operand->HasFixedPolicy()); | 707 DCHECK(operand->HasFixedPolicy()); |
| 708 InstructionOperand allocated; |
| 710 if (operand->HasFixedSlotPolicy()) { | 709 if (operand->HasFixedSlotPolicy()) { |
| 711 operand->ConvertTo(InstructionOperand::STACK_SLOT, | 710 allocated = AllocatedOperand(InstructionOperand::STACK_SLOT, |
| 712 operand->fixed_slot_index()); | 711 operand->fixed_slot_index()); |
| 713 } else if (operand->HasFixedRegisterPolicy()) { | 712 } else if (operand->HasFixedRegisterPolicy()) { |
| 714 int reg_index = operand->fixed_register_index(); | 713 allocated = AllocatedOperand(InstructionOperand::REGISTER, |
| 715 operand->ConvertTo(InstructionOperand::REGISTER, reg_index); | 714 operand->fixed_register_index()); |
| 716 } else if (operand->HasFixedDoubleRegisterPolicy()) { | 715 } else if (operand->HasFixedDoubleRegisterPolicy()) { |
| 717 int reg_index = operand->fixed_register_index(); | 716 allocated = AllocatedOperand(InstructionOperand::DOUBLE_REGISTER, |
| 718 operand->ConvertTo(InstructionOperand::DOUBLE_REGISTER, reg_index); | 717 operand->fixed_register_index()); |
| 719 } else { | 718 } else { |
| 720 UNREACHABLE(); | 719 UNREACHABLE(); |
| 721 } | 720 } |
| 721 InstructionOperand::ReplaceWith(operand, &allocated); |
| 722 if (is_tagged) { | 722 if (is_tagged) { |
| 723 TRACE("Fixed reg is tagged at %d\n", pos); | 723 TRACE("Fixed reg is tagged at %d\n", pos); |
| 724 auto instr = InstructionAt(pos); | 724 auto instr = InstructionAt(pos); |
| 725 if (instr->HasPointerMap()) { | 725 if (instr->HasPointerMap()) { |
| 726 instr->pointer_map()->RecordPointer(operand, code_zone()); | 726 instr->pointer_map()->RecordPointer(operand, code_zone()); |
| 727 } | 727 } |
| 728 } | 728 } |
| 729 return operand; | 729 return operand; |
| 730 } | 730 } |
| 731 | 731 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 Instruction* RegisterAllocator::GetLastInstruction( | 782 Instruction* RegisterAllocator::GetLastInstruction( |
| 783 const InstructionBlock* block) { | 783 const InstructionBlock* block) { |
| 784 return code()->InstructionAt(block->last_instruction_index()); | 784 return code()->InstructionAt(block->last_instruction_index()); |
| 785 } | 785 } |
| 786 | 786 |
| 787 | 787 |
| 788 LiveRange* RegisterAllocator::LiveRangeFor(InstructionOperand* operand) { | 788 LiveRange* RegisterAllocator::LiveRangeFor(InstructionOperand* operand) { |
| 789 if (operand->IsUnallocated()) { | 789 if (operand->IsUnallocated()) { |
| 790 return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); | 790 return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); |
| 791 } else if (operand->IsConstant()) { | 791 } else if (operand->IsConstant()) { |
| 792 return LiveRangeFor(ConstantOperand::cast(operand)->index()); | 792 return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); |
| 793 } else if (operand->IsRegister()) { | 793 } else if (operand->IsRegister()) { |
| 794 return FixedLiveRangeFor(operand->index()); | 794 return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); |
| 795 } else if (operand->IsDoubleRegister()) { | 795 } else if (operand->IsDoubleRegister()) { |
| 796 return FixedDoubleLiveRangeFor(operand->index()); | 796 return FixedDoubleLiveRangeFor( |
| 797 DoubleRegisterOperand::cast(operand)->index()); |
| 797 } else { | 798 } else { |
| 798 return nullptr; | 799 return nullptr; |
| 799 } | 800 } |
| 800 } | 801 } |
| 801 | 802 |
| 802 | 803 |
| 803 void RegisterAllocator::Define(LifetimePosition position, | 804 void RegisterAllocator::Define(LifetimePosition position, |
| 804 InstructionOperand* operand, | 805 InstructionOperand* operand, |
| 805 InstructionOperand* hint) { | 806 InstructionOperand* hint) { |
| 806 auto range = LiveRangeFor(operand); | 807 auto range = LiveRangeFor(operand); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 915 } | 916 } |
| 916 | 917 |
| 917 live_ranges().insert(live_ranges().end(), other->live_ranges().begin(), | 918 live_ranges().insert(live_ranges().end(), other->live_ranges().begin(), |
| 918 other->live_ranges().end()); | 919 other->live_ranges().end()); |
| 919 other->live_ranges().clear(); | 920 other->live_ranges().clear(); |
| 920 | 921 |
| 921 return true; | 922 return true; |
| 922 } | 923 } |
| 923 | 924 |
| 924 | 925 |
| 925 void SpillRange::SetOperand(InstructionOperand* op) { | 926 void SpillRange::SetOperand(AllocatedOperand* op) { |
| 926 for (auto range : live_ranges()) { | 927 for (auto range : live_ranges()) { |
| 927 DCHECK(range->GetSpillRange() == this); | 928 DCHECK(range->GetSpillRange() == this); |
| 928 range->CommitSpillOperand(op); | 929 range->CommitSpillOperand(op); |
| 929 } | 930 } |
| 930 } | 931 } |
| 931 | 932 |
| 932 | 933 |
| 933 void SpillRange::MergeDisjointIntervals(UseInterval* other) { | 934 void SpillRange::MergeDisjointIntervals(UseInterval* other) { |
| 934 UseInterval* tail = nullptr; | 935 UseInterval* tail = nullptr; |
| 935 auto current = use_interval_; | 936 auto current = use_interval_; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 970 | 971 |
| 971 // Allocate slots for the merged spill ranges. | 972 // Allocate slots for the merged spill ranges. |
| 972 for (auto range : spill_ranges()) { | 973 for (auto range : spill_ranges()) { |
| 973 if (range->IsEmpty()) continue; | 974 if (range->IsEmpty()) continue; |
| 974 // Allocate a new operand referring to the spill slot. | 975 // Allocate a new operand referring to the spill slot. |
| 975 auto kind = range->Kind(); | 976 auto kind = range->Kind(); |
| 976 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 977 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
| 977 auto op_kind = kind == DOUBLE_REGISTERS | 978 auto op_kind = kind == DOUBLE_REGISTERS |
| 978 ? InstructionOperand::DOUBLE_STACK_SLOT | 979 ? InstructionOperand::DOUBLE_STACK_SLOT |
| 979 : InstructionOperand::STACK_SLOT; | 980 : InstructionOperand::STACK_SLOT; |
| 980 auto op = InstructionOperand::New(code_zone(), op_kind, index); | 981 auto op = AllocatedOperand::New(code_zone(), op_kind, index); |
| 981 range->SetOperand(op); | 982 range->SetOperand(op); |
| 982 } | 983 } |
| 983 } | 984 } |
| 984 | 985 |
| 985 | 986 |
| 986 void RegisterAllocator::CommitAssignment() { | 987 void RegisterAllocator::CommitAssignment() { |
| 987 for (auto range : live_ranges()) { | 988 for (auto range : live_ranges()) { |
| 988 if (range == nullptr || range->IsEmpty()) continue; | 989 if (range == nullptr || range->IsEmpty()) continue; |
| 989 auto assigned = range->GetAssignedOperand(operand_cache()); | 990 auto assigned = range->GetAssignedOperand(operand_cache()); |
| 990 InstructionOperand* spill_operand = nullptr; | 991 InstructionOperand* spill_operand = nullptr; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1110 auto output_operand = last_instruction->OutputAt(i); | 1111 auto output_operand = last_instruction->OutputAt(i); |
| 1111 DCHECK(!output_operand->IsConstant()); | 1112 DCHECK(!output_operand->IsConstant()); |
| 1112 auto output = UnallocatedOperand::cast(output_operand); | 1113 auto output = UnallocatedOperand::cast(output_operand); |
| 1113 int output_vreg = output->virtual_register(); | 1114 int output_vreg = output->virtual_register(); |
| 1114 auto range = LiveRangeFor(output_vreg); | 1115 auto range = LiveRangeFor(output_vreg); |
| 1115 bool assigned = false; | 1116 bool assigned = false; |
| 1116 if (output->HasFixedPolicy()) { | 1117 if (output->HasFixedPolicy()) { |
| 1117 AllocateFixed(output, -1, false); | 1118 AllocateFixed(output, -1, false); |
| 1118 // This value is produced on the stack, we never need to spill it. | 1119 // This value is produced on the stack, we never need to spill it. |
| 1119 if (output->IsStackSlot()) { | 1120 if (output->IsStackSlot()) { |
| 1120 DCHECK(output->index() < frame_->GetSpillSlotCount()); | 1121 DCHECK(StackSlotOperand::cast(output)->index() < |
| 1121 range->SetSpillOperand(output); | 1122 frame_->GetSpillSlotCount()); |
| 1123 range->SetSpillOperand(StackSlotOperand::cast(output)); |
| 1122 range->SetSpillStartIndex(end); | 1124 range->SetSpillStartIndex(end); |
| 1123 assigned = true; | 1125 assigned = true; |
| 1124 } | 1126 } |
| 1125 | 1127 |
| 1126 for (auto succ : block->successors()) { | 1128 for (auto succ : block->successors()) { |
| 1127 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1129 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
| 1128 DCHECK(successor->PredecessorCount() == 1); | 1130 DCHECK(successor->PredecessorCount() == 1); |
| 1129 int gap_index = successor->first_instruction_index(); | 1131 int gap_index = successor->first_instruction_index(); |
| 1130 // Create an unconstrained operand for the same virtual register | 1132 // Create an unconstrained operand for the same virtual register |
| 1131 // and insert a gap move from the fixed output to the operand. | 1133 // and insert a gap move from the fixed output to the operand. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1153 auto first = InstructionAt(instr_index); | 1155 auto first = InstructionAt(instr_index); |
| 1154 // Handle fixed temporaries. | 1156 // Handle fixed temporaries. |
| 1155 for (size_t i = 0; i < first->TempCount(); i++) { | 1157 for (size_t i = 0; i < first->TempCount(); i++) { |
| 1156 auto temp = UnallocatedOperand::cast(first->TempAt(i)); | 1158 auto temp = UnallocatedOperand::cast(first->TempAt(i)); |
| 1157 if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); | 1159 if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); |
| 1158 } | 1160 } |
| 1159 // Handle constant/fixed output operands. | 1161 // Handle constant/fixed output operands. |
| 1160 for (size_t i = 0; i < first->OutputCount(); i++) { | 1162 for (size_t i = 0; i < first->OutputCount(); i++) { |
| 1161 InstructionOperand* output = first->OutputAt(i); | 1163 InstructionOperand* output = first->OutputAt(i); |
| 1162 if (output->IsConstant()) { | 1164 if (output->IsConstant()) { |
| 1163 int output_vreg = output->index(); | 1165 int output_vreg = ConstantOperand::cast(output)->virtual_register(); |
| 1164 auto range = LiveRangeFor(output_vreg); | 1166 auto range = LiveRangeFor(output_vreg); |
| 1165 range->SetSpillStartIndex(instr_index + 1); | 1167 range->SetSpillStartIndex(instr_index + 1); |
| 1166 range->SetSpillOperand(output); | 1168 range->SetSpillOperand(output); |
| 1167 continue; | 1169 continue; |
| 1168 } | 1170 } |
| 1169 auto first_output = UnallocatedOperand::cast(output); | 1171 auto first_output = UnallocatedOperand::cast(output); |
| 1170 auto range = LiveRangeFor(first_output->virtual_register()); | 1172 auto range = LiveRangeFor(first_output->virtual_register()); |
| 1171 bool assigned = false; | 1173 bool assigned = false; |
| 1172 if (first_output->HasFixedPolicy()) { | 1174 if (first_output->HasFixedPolicy()) { |
| 1173 auto output_copy = first_output->CopyUnconstrained(code_zone()); | 1175 auto output_copy = first_output->CopyUnconstrained(code_zone()); |
| 1174 bool is_tagged = HasTaggedValue(first_output->virtual_register()); | 1176 bool is_tagged = HasTaggedValue(first_output->virtual_register()); |
| 1175 AllocateFixed(first_output, instr_index, is_tagged); | 1177 AllocateFixed(first_output, instr_index, is_tagged); |
| 1176 | 1178 |
| 1177 // This value is produced on the stack, we never need to spill it. | 1179 // This value is produced on the stack, we never need to spill it. |
| 1178 if (first_output->IsStackSlot()) { | 1180 if (first_output->IsStackSlot()) { |
| 1179 DCHECK(first_output->index() < frame_->GetSpillSlotCount()); | 1181 DCHECK(StackSlotOperand::cast(first_output)->index() < |
| 1180 range->SetSpillOperand(first_output); | 1182 frame_->GetSpillSlotCount()); |
| 1183 range->SetSpillOperand(StackSlotOperand::cast(first_output)); |
| 1181 range->SetSpillStartIndex(instr_index + 1); | 1184 range->SetSpillStartIndex(instr_index + 1); |
| 1182 assigned = true; | 1185 assigned = true; |
| 1183 } | 1186 } |
| 1184 AddGapMove(instr_index + 1, Instruction::START, first_output, | 1187 AddGapMove(instr_index + 1, Instruction::START, first_output, |
| 1185 output_copy); | 1188 output_copy); |
| 1186 } | 1189 } |
| 1187 // Make sure we add a gap move for spilling (if we have not done | 1190 // Make sure we add a gap move for spilling (if we have not done |
| 1188 // so already). | 1191 // so already). |
| 1189 if (!assigned) { | 1192 if (!assigned) { |
| 1190 range->SpillAtDefinition(local_zone(), instr_index + 1, first_output); | 1193 range->SpillAtDefinition(local_zone(), instr_index + 1, first_output); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1234 // this is not desired, then the pointer map at this instruction needs | 1237 // this is not desired, then the pointer map at this instruction needs |
| 1235 // to be adjusted manually. | 1238 // to be adjusted manually. |
| 1236 } | 1239 } |
| 1237 } | 1240 } |
| 1238 } | 1241 } |
| 1239 | 1242 |
| 1240 | 1243 |
| 1241 bool RegisterAllocator::IsOutputRegisterOf(Instruction* instr, int index) { | 1244 bool RegisterAllocator::IsOutputRegisterOf(Instruction* instr, int index) { |
| 1242 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1245 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 1243 auto output = instr->OutputAt(i); | 1246 auto output = instr->OutputAt(i); |
| 1244 if (output->IsRegister() && output->index() == index) return true; | 1247 if (output->IsRegister() && RegisterOperand::cast(output)->index() == index) |
| 1248 return true; |
| 1245 } | 1249 } |
| 1246 return false; | 1250 return false; |
| 1247 } | 1251 } |
| 1248 | 1252 |
| 1249 | 1253 |
| 1250 bool RegisterAllocator::IsOutputDoubleRegisterOf(Instruction* instr, | 1254 bool RegisterAllocator::IsOutputDoubleRegisterOf(Instruction* instr, |
| 1251 int index) { | 1255 int index) { |
| 1252 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1256 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 1253 auto output = instr->OutputAt(i); | 1257 auto output = instr->OutputAt(i); |
| 1254 if (output->IsDoubleRegister() && output->index() == index) return true; | 1258 if (output->IsDoubleRegister() && |
| 1259 DoubleRegisterOperand::cast(output)->index() == index) |
| 1260 return true; |
| 1255 } | 1261 } |
| 1256 return false; | 1262 return false; |
| 1257 } | 1263 } |
| 1258 | 1264 |
| 1259 | 1265 |
| 1260 void RegisterAllocator::ProcessInstructions(const InstructionBlock* block, | 1266 void RegisterAllocator::ProcessInstructions(const InstructionBlock* block, |
| 1261 BitVector* live) { | 1267 BitVector* live) { |
| 1262 int block_start = block->first_instruction_index(); | 1268 int block_start = block->first_instruction_index(); |
| 1263 auto block_start_position = | 1269 auto block_start_position = |
| 1264 LifetimePosition::GapFromInstructionIndex(block_start); | 1270 LifetimePosition::GapFromInstructionIndex(block_start); |
| 1265 | 1271 |
| 1266 for (int index = block->last_instruction_index(); index >= block_start; | 1272 for (int index = block->last_instruction_index(); index >= block_start; |
| 1267 index--) { | 1273 index--) { |
| 1268 auto curr_position = | 1274 auto curr_position = |
| 1269 LifetimePosition::InstructionFromInstructionIndex(index); | 1275 LifetimePosition::InstructionFromInstructionIndex(index); |
| 1270 auto instr = InstructionAt(index); | 1276 auto instr = InstructionAt(index); |
| 1271 DCHECK(instr != nullptr); | 1277 DCHECK(instr != nullptr); |
| 1272 DCHECK(curr_position.IsInstructionPosition()); | 1278 DCHECK(curr_position.IsInstructionPosition()); |
| 1273 // Process output, inputs, and temps of this instruction. | 1279 // Process output, inputs, and temps of this instruction. |
| 1274 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1280 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 1275 auto output = instr->OutputAt(i); | 1281 auto output = instr->OutputAt(i); |
| 1276 if (output->IsUnallocated()) { | 1282 if (output->IsUnallocated()) { |
| 1277 // Unsupported. | 1283 // Unsupported. |
| 1278 DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); | 1284 DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); |
| 1279 int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); | 1285 int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); |
| 1280 live->Remove(out_vreg); | 1286 live->Remove(out_vreg); |
| 1281 } else if (output->IsConstant()) { | 1287 } else if (output->IsConstant()) { |
| 1282 int out_vreg = output->index(); | 1288 int out_vreg = ConstantOperand::cast(output)->virtual_register(); |
| 1283 live->Remove(out_vreg); | 1289 live->Remove(out_vreg); |
| 1284 } | 1290 } |
| 1285 Define(curr_position, output, nullptr); | 1291 Define(curr_position, output, nullptr); |
| 1286 } | 1292 } |
| 1287 | 1293 |
| 1288 if (instr->ClobbersRegisters()) { | 1294 if (instr->ClobbersRegisters()) { |
| 1289 for (int i = 0; i < config()->num_general_registers(); ++i) { | 1295 for (int i = 0; i < config()->num_general_registers(); ++i) { |
| 1290 if (!IsOutputRegisterOf(instr, i)) { | 1296 if (!IsOutputRegisterOf(instr, i)) { |
| 1291 auto range = FixedLiveRangeFor(i); | 1297 auto range = FixedLiveRangeFor(i); |
| 1292 range->AddUseInterval(curr_position, curr_position.End(), | 1298 range->AddUseInterval(curr_position, curr_position.End(), |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 } | 1366 } |
| 1361 auto move_ops = move->move_operands(); | 1367 auto move_ops = move->move_operands(); |
| 1362 for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) { | 1368 for (auto cur = move_ops->begin(); cur != move_ops->end(); ++cur) { |
| 1363 auto from = cur->source(); | 1369 auto from = cur->source(); |
| 1364 auto to = cur->destination(); | 1370 auto to = cur->destination(); |
| 1365 auto hint = to; | 1371 auto hint = to; |
| 1366 if (to->IsUnallocated()) { | 1372 if (to->IsUnallocated()) { |
| 1367 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); | 1373 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); |
| 1368 auto to_range = LiveRangeFor(to_vreg); | 1374 auto to_range = LiveRangeFor(to_vreg); |
| 1369 if (to_range->is_phi()) { | 1375 if (to_range->is_phi()) { |
| 1370 DCHECK(!FLAG_turbo_delay_ssa_decon); | |
| 1371 if (to_range->is_non_loop_phi()) { | 1376 if (to_range->is_non_loop_phi()) { |
| 1372 hint = to_range->current_hint_operand(); | 1377 hint = to_range->current_hint_operand(); |
| 1373 } | 1378 } |
| 1374 } else { | 1379 } else { |
| 1375 if (live->Contains(to_vreg)) { | 1380 if (live->Contains(to_vreg)) { |
| 1376 Define(curr_position, to, from); | 1381 Define(curr_position, to, from); |
| 1377 live->Remove(to_vreg); | 1382 live->Remove(to_vreg); |
| 1378 } else { | 1383 } else { |
| 1379 cur->Eliminate(); | 1384 cur->Eliminate(); |
| 1380 continue; | 1385 continue; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1394 | 1399 |
| 1395 | 1400 |
| 1396 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { | 1401 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { |
| 1397 for (auto phi : block->phis()) { | 1402 for (auto phi : block->phis()) { |
| 1398 int phi_vreg = phi->virtual_register(); | 1403 int phi_vreg = phi->virtual_register(); |
| 1399 auto res = | 1404 auto res = |
| 1400 phi_map_.insert(std::make_pair(phi_vreg, PhiMapValue(phi, block))); | 1405 phi_map_.insert(std::make_pair(phi_vreg, PhiMapValue(phi, block))); |
| 1401 DCHECK(res.second); | 1406 DCHECK(res.second); |
| 1402 USE(res); | 1407 USE(res); |
| 1403 auto& output = phi->output(); | 1408 auto& output = phi->output(); |
| 1404 if (!FLAG_turbo_delay_ssa_decon) { | 1409 for (size_t i = 0; i < phi->operands().size(); ++i) { |
| 1405 for (size_t i = 0; i < phi->operands().size(); ++i) { | 1410 InstructionBlock* cur_block = |
| 1406 InstructionBlock* cur_block = | 1411 code()->InstructionBlockAt(block->predecessors()[i]); |
| 1407 code()->InstructionBlockAt(block->predecessors()[i]); | 1412 AddGapMove(cur_block->last_instruction_index(), Instruction::END, |
| 1408 AddGapMove(cur_block->last_instruction_index(), Instruction::END, | 1413 &phi->inputs()[i], &output); |
| 1409 &phi->inputs()[i], &output); | 1414 DCHECK( |
| 1410 DCHECK(!InstructionAt(cur_block->last_instruction_index()) | 1415 !InstructionAt(cur_block->last_instruction_index())->HasPointerMap()); |
| 1411 ->HasPointerMap()); | |
| 1412 } | |
| 1413 } | 1416 } |
| 1414 auto live_range = LiveRangeFor(phi_vreg); | 1417 auto live_range = LiveRangeFor(phi_vreg); |
| 1415 int gap_index = block->first_instruction_index(); | 1418 int gap_index = block->first_instruction_index(); |
| 1416 live_range->SpillAtDefinition(local_zone(), gap_index, &output); | 1419 live_range->SpillAtDefinition(local_zone(), gap_index, &output); |
| 1417 live_range->SetSpillStartIndex(gap_index); | 1420 live_range->SetSpillStartIndex(gap_index); |
| 1418 // We use the phi-ness of some nodes in some later heuristics. | 1421 // We use the phi-ness of some nodes in some later heuristics. |
| 1419 live_range->set_is_phi(true); | 1422 live_range->set_is_phi(true); |
| 1420 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); | 1423 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
| 1421 } | 1424 } |
| 1422 } | 1425 } |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1657 }; | 1660 }; |
| 1658 | 1661 |
| 1659 } // namespace | 1662 } // namespace |
| 1660 | 1663 |
| 1661 | 1664 |
| 1662 void RegisterAllocator::ResolveControlFlow() { | 1665 void RegisterAllocator::ResolveControlFlow() { |
| 1663 // Lazily linearize live ranges in memory for fast lookup. | 1666 // Lazily linearize live ranges in memory for fast lookup. |
| 1664 LiveRangeFinder finder(*this); | 1667 LiveRangeFinder finder(*this); |
| 1665 for (auto block : code()->instruction_blocks()) { | 1668 for (auto block : code()->instruction_blocks()) { |
| 1666 if (CanEagerlyResolveControlFlow(block)) continue; | 1669 if (CanEagerlyResolveControlFlow(block)) continue; |
| 1667 if (FLAG_turbo_delay_ssa_decon) { | |
| 1668 // resolve phis | |
| 1669 for (auto phi : block->phis()) { | |
| 1670 auto* block_bound = | |
| 1671 finder.ArrayFor(phi->virtual_register())->FindSucc(block); | |
| 1672 auto phi_output = | |
| 1673 block_bound->range_->GetAssignedOperand(operand_cache()); | |
| 1674 phi->output().ConvertTo(phi_output->kind(), phi_output->index()); | |
| 1675 size_t pred_index = 0; | |
| 1676 for (auto pred : block->predecessors()) { | |
| 1677 const InstructionBlock* pred_block = code()->InstructionBlockAt(pred); | |
| 1678 auto* pred_bound = finder.ArrayFor(phi->operands()[pred_index]) | |
| 1679 ->FindPred(pred_block); | |
| 1680 auto pred_op = | |
| 1681 pred_bound->range_->GetAssignedOperand(operand_cache()); | |
| 1682 phi->inputs()[pred_index] = *pred_op; | |
| 1683 ResolveControlFlow(block, phi_output, pred_block, pred_op); | |
| 1684 pred_index++; | |
| 1685 } | |
| 1686 } | |
| 1687 } | |
| 1688 auto live = live_in_sets_[block->rpo_number().ToInt()]; | 1670 auto live = live_in_sets_[block->rpo_number().ToInt()]; |
| 1689 BitVector::Iterator iterator(live); | 1671 BitVector::Iterator iterator(live); |
| 1690 while (!iterator.Done()) { | 1672 while (!iterator.Done()) { |
| 1691 auto* array = finder.ArrayFor(iterator.Current()); | 1673 auto* array = finder.ArrayFor(iterator.Current()); |
| 1692 for (auto pred : block->predecessors()) { | 1674 for (auto pred : block->predecessors()) { |
| 1693 FindResult result; | 1675 FindResult result; |
| 1694 const auto* pred_block = code()->InstructionBlockAt(pred); | 1676 const auto* pred_block = code()->InstructionBlockAt(pred); |
| 1695 array->Find(block, pred_block, &result); | 1677 array->Find(block, pred_block, &result); |
| 1696 if (result.cur_cover_ == result.pred_cover_ || | 1678 if (result.cur_cover_ == result.pred_cover_ || |
| 1697 result.cur_cover_->IsSpilled()) | 1679 result.cur_cover_->IsSpilled()) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1738 | 1720 |
| 1739 // Process the instructions in reverse order, generating and killing | 1721 // Process the instructions in reverse order, generating and killing |
| 1740 // live values. | 1722 // live values. |
| 1741 ProcessInstructions(block, live); | 1723 ProcessInstructions(block, live); |
| 1742 // All phi output operands are killed by this block. | 1724 // All phi output operands are killed by this block. |
| 1743 for (auto phi : block->phis()) { | 1725 for (auto phi : block->phis()) { |
| 1744 // The live range interval already ends at the first instruction of the | 1726 // The live range interval already ends at the first instruction of the |
| 1745 // block. | 1727 // block. |
| 1746 int phi_vreg = phi->virtual_register(); | 1728 int phi_vreg = phi->virtual_register(); |
| 1747 live->Remove(phi_vreg); | 1729 live->Remove(phi_vreg); |
| 1748 if (!FLAG_turbo_delay_ssa_decon) { | 1730 InstructionOperand* hint = nullptr; |
| 1749 InstructionOperand* hint = nullptr; | 1731 InstructionOperand* phi_operand = nullptr; |
| 1750 InstructionOperand* phi_operand = nullptr; | 1732 auto instr = GetLastInstruction( |
| 1751 auto instr = GetLastInstruction( | 1733 code()->InstructionBlockAt(block->predecessors()[0])); |
| 1752 code()->InstructionBlockAt(block->predecessors()[0])); | 1734 auto move = instr->GetParallelMove(Instruction::END); |
| 1753 auto move = instr->GetParallelMove(Instruction::END); | 1735 for (int j = 0; j < move->move_operands()->length(); ++j) { |
| 1754 for (int j = 0; j < move->move_operands()->length(); ++j) { | 1736 auto to = move->move_operands()->at(j).destination(); |
| 1755 auto to = move->move_operands()->at(j).destination(); | 1737 if (to->IsUnallocated() && |
| 1756 if (to->IsUnallocated() && | 1738 UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) { |
| 1757 UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) { | 1739 hint = move->move_operands()->at(j).source(); |
| 1758 hint = move->move_operands()->at(j).source(); | 1740 phi_operand = to; |
| 1759 phi_operand = to; | 1741 break; |
| 1760 break; | |
| 1761 } | |
| 1762 } | 1742 } |
| 1763 DCHECK(hint != nullptr); | |
| 1764 auto block_start = LifetimePosition::GapFromInstructionIndex( | |
| 1765 block->first_instruction_index()); | |
| 1766 Define(block_start, phi_operand, hint); | |
| 1767 } | 1743 } |
| 1744 DCHECK(hint != nullptr); |
| 1745 auto block_start = LifetimePosition::GapFromInstructionIndex( |
| 1746 block->first_instruction_index()); |
| 1747 Define(block_start, phi_operand, hint); |
| 1768 } | 1748 } |
| 1769 | 1749 |
| 1770 // Now live is live_in for this block except not including values live | 1750 // Now live is live_in for this block except not including values live |
| 1771 // out on backward successor edges. | 1751 // out on backward successor edges. |
| 1772 live_in_sets_[block_id] = live; | 1752 live_in_sets_[block_id] = live; |
| 1773 | 1753 |
| 1774 if (block->IsLoopHeader()) { | 1754 if (block->IsLoopHeader()) { |
| 1775 // Add a live range stretching from the first loop instruction to the last | 1755 // Add a live range stretching from the first loop instruction to the last |
| 1776 // for each value live on entry to the header. | 1756 // for each value live on entry to the header. |
| 1777 BitVector::Iterator iterator(live); | 1757 BitVector::Iterator iterator(live); |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2177 for (auto cur_inactive : inactive_live_ranges()) { | 2157 for (auto cur_inactive : inactive_live_ranges()) { |
| 2178 DCHECK(cur_inactive->End().Value() > current->Start().Value()); | 2158 DCHECK(cur_inactive->End().Value() > current->Start().Value()); |
| 2179 auto next_intersection = cur_inactive->FirstIntersection(current); | 2159 auto next_intersection = cur_inactive->FirstIntersection(current); |
| 2180 if (!next_intersection.IsValid()) continue; | 2160 if (!next_intersection.IsValid()) continue; |
| 2181 int cur_reg = cur_inactive->assigned_register(); | 2161 int cur_reg = cur_inactive->assigned_register(); |
| 2182 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); | 2162 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); |
| 2183 } | 2163 } |
| 2184 | 2164 |
| 2185 auto hint = current->FirstHint(); | 2165 auto hint = current->FirstHint(); |
| 2186 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { | 2166 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { |
| 2187 int register_index = hint->index(); | 2167 int register_index = AllocatedOperand::cast(hint)->index(); |
| 2188 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", | 2168 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", |
| 2189 RegisterName(register_index), free_until_pos[register_index].Value(), | 2169 RegisterName(register_index), free_until_pos[register_index].Value(), |
| 2190 current->id(), current->End().Value()); | 2170 current->id(), current->End().Value()); |
| 2191 | 2171 |
| 2192 // The desired register is free until the end of the current live range. | 2172 // The desired register is free until the end of the current live range. |
| 2193 if (free_until_pos[register_index].Value() >= current->End().Value()) { | 2173 if (free_until_pos[register_index].Value() >= current->End().Value()) { |
| 2194 TRACE("Assigning preferred reg %s to live range %d\n", | 2174 TRACE("Assigning preferred reg %s to live range %d\n", |
| 2195 RegisterName(register_index), current->id()); | 2175 RegisterName(register_index), current->id()); |
| 2196 SetLiveRangeAssignedRegister(current, register_index); | 2176 SetLiveRangeAssignedRegister(current, register_index); |
| 2197 return true; | 2177 return true; |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2553 } else { | 2533 } else { |
| 2554 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2534 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 2555 assigned_registers_->Add(reg); | 2535 assigned_registers_->Add(reg); |
| 2556 } | 2536 } |
| 2557 range->set_assigned_register(reg, operand_cache()); | 2537 range->set_assigned_register(reg, operand_cache()); |
| 2558 } | 2538 } |
| 2559 | 2539 |
| 2560 } // namespace compiler | 2540 } // namespace compiler |
| 2561 } // namespace internal | 2541 } // namespace internal |
| 2562 } // namespace v8 | 2542 } // namespace v8 |
| OLD | NEW |