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 |