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/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/compiler/linkage.h" | 6 #include "src/compiler/linkage.h" |
7 #include "src/compiler/register-allocator.h" | 7 #include "src/compiler/register-allocator.h" |
8 #include "src/string-stream.h" | 8 #include "src/string-stream.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == | 58 code->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == |
59 pos.ToInstructionIndex(); | 59 pos.ToInstructionIndex(); |
60 } | 60 } |
61 | 61 |
62 | 62 |
63 Instruction* GetLastInstruction(InstructionSequence* code, | 63 Instruction* GetLastInstruction(InstructionSequence* code, |
64 const InstructionBlock* block) { | 64 const InstructionBlock* block) { |
65 return code->InstructionAt(block->last_instruction_index()); | 65 return code->InstructionAt(block->last_instruction_index()); |
66 } | 66 } |
67 | 67 |
| 68 |
| 69 bool IsOutputRegisterOf(Instruction* instr, int index) { |
| 70 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 71 auto output = instr->OutputAt(i); |
| 72 if (output->IsRegister() && |
| 73 RegisterOperand::cast(output)->index() == index) { |
| 74 return true; |
| 75 } |
| 76 } |
| 77 return false; |
| 78 } |
| 79 |
| 80 |
| 81 bool IsOutputDoubleRegisterOf(Instruction* instr, int index) { |
| 82 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 83 auto output = instr->OutputAt(i); |
| 84 if (output->IsDoubleRegister() && |
| 85 DoubleRegisterOperand::cast(output)->index() == index) { |
| 86 return true; |
| 87 } |
| 88 } |
| 89 return false; |
| 90 } |
| 91 |
68 } // namespace | 92 } // namespace |
69 | 93 |
70 | 94 |
71 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, | 95 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
72 InstructionOperand* hint) | 96 void* hint, UsePositionHintType hint_type) |
73 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { | 97 : operand_(operand), hint_(hint), next_(nullptr), pos_(pos), flags_(0) { |
| 98 DCHECK_IMPLIES(hint == nullptr, hint_type == UsePositionHintType::kNone); |
74 bool register_beneficial = true; | 99 bool register_beneficial = true; |
75 UsePositionType type = UsePositionType::kAny; | 100 UsePositionType type = UsePositionType::kAny; |
76 if (operand_ != nullptr && operand_->IsUnallocated()) { | 101 if (operand_ != nullptr && operand_->IsUnallocated()) { |
77 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); | 102 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); |
78 if (unalloc->HasRegisterPolicy()) { | 103 if (unalloc->HasRegisterPolicy()) { |
79 type = UsePositionType::kRequiresRegister; | 104 type = UsePositionType::kRequiresRegister; |
80 } else if (unalloc->HasSlotPolicy()) { | 105 } else if (unalloc->HasSlotPolicy()) { |
81 type = UsePositionType::kRequiresSlot; | 106 type = UsePositionType::kRequiresSlot; |
82 register_beneficial = false; | 107 register_beneficial = false; |
83 } else { | 108 } else { |
84 register_beneficial = !unalloc->HasAnyPolicy(); | 109 register_beneficial = !unalloc->HasAnyPolicy(); |
85 } | 110 } |
86 } | 111 } |
87 flags_ = TypeField::encode(type) | | 112 flags_ = TypeField::encode(type) | HintTypeField::encode(hint_type) | |
88 RegisterBeneficialField::encode(register_beneficial); | 113 RegisterBeneficialField::encode(register_beneficial) | |
| 114 AssignedRegisterField::encode(kUnassignedRegister); |
89 DCHECK(pos_.IsValid()); | 115 DCHECK(pos_.IsValid()); |
90 } | 116 } |
91 | 117 |
92 | 118 |
93 bool UsePosition::HasHint() const { | 119 bool UsePosition::HasHint() const { |
94 return hint_ != nullptr && !hint_->IsUnallocated(); | 120 int hint_register; |
| 121 return HintRegister(&hint_register); |
95 } | 122 } |
96 | 123 |
97 | 124 |
| 125 bool UsePosition::HintRegister(int* register_index) const { |
| 126 if (hint_ == nullptr) return false; |
| 127 switch (HintTypeField::decode(flags_)) { |
| 128 case UsePositionHintType::kNone: |
| 129 case UsePositionHintType::kUnresolved: |
| 130 return false; |
| 131 case UsePositionHintType::kUsePos: { |
| 132 auto use_pos = reinterpret_cast<UsePosition*>(hint_); |
| 133 int assigned_register = AssignedRegisterField::decode(use_pos->flags_); |
| 134 if (assigned_register == kUnassignedRegister) return false; |
| 135 *register_index = assigned_register; |
| 136 return true; |
| 137 } |
| 138 case UsePositionHintType::kOperand: { |
| 139 auto operand = reinterpret_cast<InstructionOperand*>(hint_); |
| 140 int assigned_register = AllocatedOperand::cast(operand)->index(); |
| 141 *register_index = assigned_register; |
| 142 return true; |
| 143 } |
| 144 case UsePositionHintType::kPhi: { |
| 145 auto phi = reinterpret_cast<RegisterAllocationData::PhiMapValue*>(hint_); |
| 146 int assigned_register = phi->assigned_register(); |
| 147 if (assigned_register == kUnassignedRegister) return false; |
| 148 *register_index = assigned_register; |
| 149 return true; |
| 150 } |
| 151 } |
| 152 UNREACHABLE(); |
| 153 return false; |
| 154 } |
| 155 |
| 156 |
| 157 UsePositionHintType UsePosition::HintTypeForOperand( |
| 158 const InstructionOperand& op) { |
| 159 switch (op.kind()) { |
| 160 case InstructionOperand::CONSTANT: |
| 161 case InstructionOperand::IMMEDIATE: |
| 162 return UsePositionHintType::kNone; |
| 163 case InstructionOperand::UNALLOCATED: |
| 164 return UsePositionHintType::kUnresolved; |
| 165 case InstructionOperand::ALLOCATED: |
| 166 switch (AllocatedOperand::cast(op).allocated_kind()) { |
| 167 case AllocatedOperand::REGISTER: |
| 168 case AllocatedOperand::DOUBLE_REGISTER: |
| 169 return UsePositionHintType::kOperand; |
| 170 case AllocatedOperand::STACK_SLOT: |
| 171 case AllocatedOperand::DOUBLE_STACK_SLOT: |
| 172 return UsePositionHintType::kNone; |
| 173 } |
| 174 case InstructionOperand::INVALID: |
| 175 break; |
| 176 } |
| 177 UNREACHABLE(); |
| 178 return UsePositionHintType::kNone; |
| 179 } |
| 180 |
| 181 |
| 182 void UsePosition::ResolveHint(UsePosition* use_pos) { |
| 183 DCHECK_NOT_NULL(use_pos); |
| 184 if (HintTypeField::decode(flags_) != UsePositionHintType::kUnresolved) return; |
| 185 hint_ = use_pos; |
| 186 flags_ = HintTypeField::update(flags_, UsePositionHintType::kUsePos); |
| 187 } |
| 188 |
| 189 |
98 void UsePosition::set_type(UsePositionType type, bool register_beneficial) { | 190 void UsePosition::set_type(UsePositionType type, bool register_beneficial) { |
99 DCHECK_IMPLIES(type == UsePositionType::kRequiresSlot, !register_beneficial); | 191 DCHECK_IMPLIES(type == UsePositionType::kRequiresSlot, !register_beneficial); |
100 flags_ = TypeField::encode(type) | | 192 flags_ = TypeField::encode(type) | |
101 RegisterBeneficialField::encode(register_beneficial); | 193 RegisterBeneficialField::encode(register_beneficial); |
102 } | 194 } |
103 | 195 |
104 | 196 |
105 UseInterval* UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { | 197 UseInterval* UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { |
106 DCHECK(Contains(pos) && pos != start()); | 198 DCHECK(Contains(pos) && pos != start()); |
107 auto after = new (zone) UseInterval(pos, end_); | 199 auto after = new (zone) UseInterval(pos, end_); |
(...skipping 14 matching lines...) Expand all Loading... |
122 }; | 214 }; |
123 | 215 |
124 | 216 |
125 LiveRange::LiveRange(int id) | 217 LiveRange::LiveRange(int id) |
126 : id_(id), | 218 : id_(id), |
127 spilled_(false), | 219 spilled_(false), |
128 has_slot_use_(false), | 220 has_slot_use_(false), |
129 is_phi_(false), | 221 is_phi_(false), |
130 is_non_loop_phi_(false), | 222 is_non_loop_phi_(false), |
131 kind_(UNALLOCATED_REGISTERS), | 223 kind_(UNALLOCATED_REGISTERS), |
132 assigned_register_(kInvalidAssignment), | 224 assigned_register_(kUnassignedRegister), |
133 last_interval_(nullptr), | 225 last_interval_(nullptr), |
134 first_interval_(nullptr), | 226 first_interval_(nullptr), |
135 first_pos_(nullptr), | 227 first_pos_(nullptr), |
136 parent_(nullptr), | 228 parent_(nullptr), |
137 next_(nullptr), | 229 next_(nullptr), |
138 current_interval_(nullptr), | 230 current_interval_(nullptr), |
139 last_processed_use_(nullptr), | 231 last_processed_use_(nullptr), |
140 current_hint_operand_(nullptr), | 232 current_hint_position_(nullptr), |
141 spill_start_index_(kMaxInt), | 233 spill_start_index_(kMaxInt), |
142 spill_type_(SpillType::kNoSpillType), | 234 spill_type_(SpillType::kNoSpillType), |
143 spill_operand_(nullptr), | 235 spill_operand_(nullptr), |
144 spills_at_definition_(nullptr) {} | 236 spills_at_definition_(nullptr) {} |
145 | 237 |
146 | 238 |
147 void LiveRange::Verify() const { | 239 void LiveRange::Verify() const { |
148 // Walk the positions, verifying that each is in an interval. | 240 // Walk the positions, verifying that each is in an interval. |
149 auto interval = first_interval_; | 241 auto interval = first_interval_; |
150 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { | 242 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { |
151 CHECK(Start() <= pos->pos()); | 243 CHECK(Start() <= pos->pos()); |
152 CHECK(pos->pos() <= End()); | 244 CHECK(pos->pos() <= End()); |
153 CHECK(interval != nullptr); | 245 CHECK(interval != nullptr); |
154 while (!interval->Contains(pos->pos()) && interval->end() != pos->pos()) { | 246 while (!interval->Contains(pos->pos()) && interval->end() != pos->pos()) { |
155 interval = interval->next(); | 247 interval = interval->next(); |
156 CHECK(interval != nullptr); | 248 CHECK(interval != nullptr); |
157 } | 249 } |
158 } | 250 } |
159 } | 251 } |
160 | 252 |
161 | 253 |
162 void LiveRange::set_assigned_register(int reg) { | 254 void LiveRange::set_assigned_register(int reg) { |
163 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 255 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
164 assigned_register_ = reg; | 256 assigned_register_ = reg; |
165 } | 257 } |
166 | 258 |
167 | 259 |
| 260 void LiveRange::UnsetAssignedRegister() { |
| 261 DCHECK(HasRegisterAssigned() && !IsSpilled()); |
| 262 assigned_register_ = kUnassignedRegister; |
| 263 } |
| 264 |
| 265 |
168 void LiveRange::MakeSpilled() { | 266 void LiveRange::MakeSpilled() { |
169 DCHECK(!IsSpilled()); | 267 DCHECK(!IsSpilled()); |
170 DCHECK(!TopLevel()->HasNoSpillType()); | 268 DCHECK(!TopLevel()->HasNoSpillType()); |
171 spilled_ = true; | 269 spilled_ = true; |
172 assigned_register_ = kInvalidAssignment; | 270 assigned_register_ = kUnassignedRegister; |
173 } | 271 } |
174 | 272 |
175 | 273 |
176 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, | 274 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, |
177 InstructionOperand* operand) { | 275 InstructionOperand* operand) { |
178 DCHECK(HasNoSpillType()); | 276 DCHECK(HasNoSpillType()); |
179 spills_at_definition_ = new (zone) | 277 spills_at_definition_ = new (zone) |
180 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); | 278 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); |
181 } | 279 } |
182 | 280 |
(...skipping 20 matching lines...) Expand all Loading... |
203 break; | 301 break; |
204 } | 302 } |
205 } | 303 } |
206 if (found) continue; | 304 if (found) continue; |
207 } | 305 } |
208 move->AddMove(*to_spill->operand, *op); | 306 move->AddMove(*to_spill->operand, *op); |
209 } | 307 } |
210 } | 308 } |
211 | 309 |
212 | 310 |
| 311 UsePosition* LiveRange::FirstHintPosition(int* register_index) const { |
| 312 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { |
| 313 if (pos->HintRegister(register_index)) return pos; |
| 314 } |
| 315 return nullptr; |
| 316 } |
| 317 |
| 318 |
213 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 319 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
214 DCHECK(HasNoSpillType()); | 320 DCHECK(HasNoSpillType()); |
215 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); | 321 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); |
216 spill_type_ = SpillType::kSpillOperand; | 322 spill_type_ = SpillType::kSpillOperand; |
217 spill_operand_ = operand; | 323 spill_operand_ = operand; |
218 } | 324 } |
219 | 325 |
220 | 326 |
221 void LiveRange::SetSpillRange(SpillRange* spill_range) { | 327 void LiveRange::SetSpillRange(SpillRange* spill_range) { |
222 DCHECK(HasNoSpillType() || HasSpillRange()); | 328 DCHECK(HasNoSpillType() || HasSpillRange()); |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 // that each new use interval either precedes or intersects with | 593 // that each new use interval either precedes or intersects with |
488 // last added interval. | 594 // last added interval. |
489 DCHECK(start < first_interval_->end()); | 595 DCHECK(start < first_interval_->end()); |
490 first_interval_->set_start(Min(start, first_interval_->start())); | 596 first_interval_->set_start(Min(start, first_interval_->start())); |
491 first_interval_->set_end(Max(end, first_interval_->end())); | 597 first_interval_->set_end(Max(end, first_interval_->end())); |
492 } | 598 } |
493 } | 599 } |
494 } | 600 } |
495 | 601 |
496 | 602 |
497 void LiveRange::AddUsePosition(LifetimePosition pos, | 603 void LiveRange::AddUsePosition(UsePosition* use_pos) { |
498 InstructionOperand* operand, | 604 auto pos = use_pos->pos(); |
499 InstructionOperand* hint, Zone* zone) { | |
500 TRACE("Add to live range %d use position %d\n", id_, pos.value()); | 605 TRACE("Add to live range %d use position %d\n", id_, pos.value()); |
501 auto use_pos = new (zone) UsePosition(pos, operand, hint); | |
502 UsePosition* prev_hint = nullptr; | 606 UsePosition* prev_hint = nullptr; |
503 UsePosition* prev = nullptr; | 607 UsePosition* prev = nullptr; |
504 auto current = first_pos_; | 608 auto current = first_pos_; |
505 while (current != nullptr && current->pos() < pos) { | 609 while (current != nullptr && current->pos() < pos) { |
506 prev_hint = current->HasHint() ? current : prev_hint; | 610 prev_hint = current->HasHint() ? current : prev_hint; |
507 prev = current; | 611 prev = current; |
508 current = current->next(); | 612 current = current->next(); |
509 } | 613 } |
510 | 614 |
511 if (prev == nullptr) { | 615 if (prev == nullptr) { |
512 use_pos->set_next(first_pos_); | 616 use_pos->set_next(first_pos_); |
513 first_pos_ = use_pos; | 617 first_pos_ = use_pos; |
514 } else { | 618 } else { |
515 use_pos->set_next(prev->next()); | 619 use_pos->set_next(prev->next()); |
516 prev->set_next(use_pos); | 620 prev->set_next(use_pos); |
517 } | 621 } |
518 | 622 |
519 if (prev_hint == nullptr && use_pos->HasHint()) { | 623 if (prev_hint == nullptr && use_pos->HasHint()) { |
520 current_hint_operand_ = hint; | 624 current_hint_position_ = use_pos; |
521 } | 625 } |
522 } | 626 } |
523 | 627 |
524 | 628 |
525 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, | 629 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, |
526 InstructionOperand* spill_op) { | 630 InstructionOperand* spill_op) { |
527 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { | 631 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
528 DCHECK(Start() <= pos->pos() && pos->pos() <= End()); | 632 DCHECK(Start() <= pos->pos() && pos->pos() <= End()); |
529 if (!pos->HasOperand()) { | 633 if (!pos->HasOperand()) continue; |
530 continue; | |
531 } | |
532 switch (pos->type()) { | 634 switch (pos->type()) { |
533 case UsePositionType::kRequiresSlot: | 635 case UsePositionType::kRequiresSlot: |
534 if (spill_op != nullptr) { | 636 if (spill_op != nullptr) { |
535 InstructionOperand::ReplaceWith(pos->operand(), spill_op); | 637 InstructionOperand::ReplaceWith(pos->operand(), spill_op); |
536 } | 638 } |
537 break; | 639 break; |
538 case UsePositionType::kRequiresRegister: | 640 case UsePositionType::kRequiresRegister: |
539 DCHECK(op.IsRegister() || op.IsDoubleRegister()); | 641 DCHECK(op.IsRegister() || op.IsDoubleRegister()); |
540 // Fall through. | 642 // Fall through. |
541 case UsePositionType::kAny: | 643 case UsePositionType::kAny: |
542 InstructionOperand::ReplaceWith(pos->operand(), &op); | 644 InstructionOperand::ReplaceWith(pos->operand(), &op); |
543 break; | 645 break; |
544 } | 646 } |
545 } | 647 } |
546 } | 648 } |
547 | 649 |
548 | 650 |
| 651 void LiveRange::SetUseHints(int register_index) { |
| 652 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
| 653 if (!pos->HasOperand()) continue; |
| 654 switch (pos->type()) { |
| 655 case UsePositionType::kRequiresSlot: |
| 656 break; |
| 657 case UsePositionType::kRequiresRegister: |
| 658 case UsePositionType::kAny: |
| 659 pos->set_assigned_register(register_index); |
| 660 break; |
| 661 } |
| 662 } |
| 663 } |
| 664 |
| 665 |
549 bool LiveRange::CanCover(LifetimePosition position) const { | 666 bool LiveRange::CanCover(LifetimePosition position) const { |
550 if (IsEmpty()) return false; | 667 if (IsEmpty()) return false; |
551 return Start() <= position && position < End(); | 668 return Start() <= position && position < End(); |
552 } | 669 } |
553 | 670 |
554 | 671 |
555 bool LiveRange::Covers(LifetimePosition position) const { | 672 bool LiveRange::Covers(LifetimePosition position) const { |
556 if (!CanCover(position)) return false; | 673 if (!CanCover(position)) return false; |
557 auto start_search = FirstSearchIntervalForPosition(position); | 674 auto start_search = FirstSearchIntervalForPosition(position); |
558 for (auto interval = start_search; interval != nullptr; | 675 for (auto interval = start_search; interval != nullptr; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 } else { | 812 } else { |
696 tail->set_next(current); | 813 tail->set_next(current); |
697 } | 814 } |
698 tail = current; | 815 tail = current; |
699 current = current->next(); | 816 current = current->next(); |
700 } | 817 } |
701 // Other list is empty => we are done | 818 // Other list is empty => we are done |
702 } | 819 } |
703 | 820 |
704 | 821 |
| 822 RegisterAllocationData::PhiMapValue::PhiMapValue(PhiInstruction* phi, |
| 823 const InstructionBlock* block, |
| 824 Zone* zone) |
| 825 : phi_(phi), |
| 826 block_(block), |
| 827 incoming_operands_(zone), |
| 828 assigned_register_(kUnassignedRegister) { |
| 829 incoming_operands_.reserve(phi->operands().size()); |
| 830 } |
| 831 |
| 832 |
| 833 void RegisterAllocationData::PhiMapValue::AddOperand( |
| 834 InstructionOperand* operand) { |
| 835 incoming_operands_.push_back(operand); |
| 836 } |
| 837 |
| 838 |
| 839 void RegisterAllocationData::PhiMapValue::CommitAssignment( |
| 840 const InstructionOperand& assigned) { |
| 841 for (auto operand : incoming_operands_) { |
| 842 InstructionOperand::ReplaceWith(operand, &assigned); |
| 843 } |
| 844 } |
| 845 |
| 846 |
705 RegisterAllocationData::RegisterAllocationData( | 847 RegisterAllocationData::RegisterAllocationData( |
706 const RegisterConfiguration* config, Zone* zone, Frame* frame, | 848 const RegisterConfiguration* config, Zone* zone, Frame* frame, |
707 InstructionSequence* code, const char* debug_name) | 849 InstructionSequence* code, const char* debug_name) |
708 : allocation_zone_(zone), | 850 : allocation_zone_(zone), |
709 frame_(frame), | 851 frame_(frame), |
710 code_(code), | 852 code_(code), |
711 debug_name_(debug_name), | 853 debug_name_(debug_name), |
712 config_(config), | 854 config_(config), |
713 phi_map_(allocation_zone()), | 855 phi_map_(allocation_zone()), |
714 live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), | 856 live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 | 892 |
751 MoveOperands* RegisterAllocationData::AddGapMove( | 893 MoveOperands* RegisterAllocationData::AddGapMove( |
752 int index, Instruction::GapPosition position, | 894 int index, Instruction::GapPosition position, |
753 const InstructionOperand& from, const InstructionOperand& to) { | 895 const InstructionOperand& from, const InstructionOperand& to) { |
754 auto instr = code()->InstructionAt(index); | 896 auto instr = code()->InstructionAt(index); |
755 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); | 897 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); |
756 return moves->AddMove(from, to); | 898 return moves->AddMove(from, to); |
757 } | 899 } |
758 | 900 |
759 | 901 |
760 void RegisterAllocationData::AssignPhiInput( | |
761 LiveRange* range, const InstructionOperand& assignment) { | |
762 DCHECK(range->is_phi()); | |
763 auto it = phi_map().find(range->id()); | |
764 DCHECK(it != phi_map().end()); | |
765 for (auto move : it->second->incoming_moves) { | |
766 move->set_destination(assignment); | |
767 } | |
768 } | |
769 | |
770 | |
771 LiveRange* RegisterAllocationData::NewLiveRange(int index) { | 902 LiveRange* RegisterAllocationData::NewLiveRange(int index) { |
772 return new (allocation_zone()) LiveRange(index); | 903 return new (allocation_zone()) LiveRange(index); |
773 } | 904 } |
774 | 905 |
775 | 906 |
| 907 RegisterAllocationData::PhiMapValue* RegisterAllocationData::InitializePhiMap( |
| 908 const InstructionBlock* block, PhiInstruction* phi) { |
| 909 auto map_value = new (allocation_zone()) |
| 910 RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); |
| 911 auto res = |
| 912 phi_map_.insert(std::make_pair(phi->virtual_register(), map_value)); |
| 913 DCHECK(res.second); |
| 914 USE(res); |
| 915 return map_value; |
| 916 } |
| 917 |
| 918 |
| 919 RegisterAllocationData::PhiMapValue* RegisterAllocationData::GetPhiMapValueFor( |
| 920 int virtual_register) { |
| 921 auto it = phi_map_.find(virtual_register); |
| 922 DCHECK(it != phi_map_.end()); |
| 923 return it->second; |
| 924 } |
| 925 |
| 926 |
776 bool RegisterAllocationData::ExistsUseWithoutDefinition() { | 927 bool RegisterAllocationData::ExistsUseWithoutDefinition() { |
777 bool found = false; | 928 bool found = false; |
778 BitVector::Iterator iterator(live_in_sets()[0]); | 929 BitVector::Iterator iterator(live_in_sets()[0]); |
779 while (!iterator.Done()) { | 930 while (!iterator.Done()) { |
780 found = true; | 931 found = true; |
781 int operand_index = iterator.Current(); | 932 int operand_index = iterator.Current(); |
782 PrintF("Register allocator error: live v%d reached first block.\n", | 933 PrintF("Register allocator error: live v%d reached first block.\n", |
783 operand_index); | 934 operand_index); |
784 LiveRange* range = LiveRangeFor(operand_index); | 935 LiveRange* range = LiveRangeFor(operand_index); |
785 PrintF(" (first use is at %d)\n", range->first_pos()->pos().value()); | 936 PrintF(" (first use is at %d)\n", range->first_pos()->pos().value()); |
(...skipping 10 matching lines...) Expand all Loading... |
796 | 947 |
797 SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange( | 948 SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange( |
798 LiveRange* range) { | 949 LiveRange* range) { |
799 auto spill_range = | 950 auto spill_range = |
800 new (allocation_zone()) SpillRange(range, allocation_zone()); | 951 new (allocation_zone()) SpillRange(range, allocation_zone()); |
801 spill_ranges().push_back(spill_range); | 952 spill_ranges().push_back(spill_range); |
802 return spill_range; | 953 return spill_range; |
803 } | 954 } |
804 | 955 |
805 | 956 |
806 void RegisterAllocationData::SetLiveRangeAssignedRegister(LiveRange* range, | 957 void RegisterAllocationData::MarkAllocated(RegisterKind kind, int index) { |
807 int reg) { | 958 if (kind == DOUBLE_REGISTERS) { |
808 if (range->Kind() == DOUBLE_REGISTERS) { | 959 assigned_double_registers_->Add(index); |
809 assigned_double_registers_->Add(reg); | |
810 } else { | 960 } else { |
811 DCHECK(range->Kind() == GENERAL_REGISTERS); | 961 DCHECK(kind == GENERAL_REGISTERS); |
812 assigned_registers_->Add(reg); | 962 assigned_registers_->Add(index); |
813 } | 963 } |
814 range->set_assigned_register(reg); | |
815 auto assignment = range->GetAssignedOperand(); | |
816 // TODO(dcarney): stop aliasing hint operands. | |
817 range->ConvertUsesToOperand(assignment, nullptr); | |
818 if (range->is_phi()) AssignPhiInput(range, assignment); | |
819 } | 964 } |
820 | 965 |
821 | 966 |
822 ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) | 967 ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) |
823 : data_(data) {} | 968 : data_(data) {} |
824 | 969 |
825 | 970 |
826 InstructionOperand* ConstraintBuilder::AllocateFixed( | 971 InstructionOperand* ConstraintBuilder::AllocateFixed( |
827 UnallocatedOperand* operand, int pos, bool is_tagged) { | 972 UnallocatedOperand* operand, int pos, bool is_tagged) { |
828 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); | 973 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1015 // Process the blocks in reverse order. | 1160 // Process the blocks in reverse order. |
1016 for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) { | 1161 for (InstructionBlock* block : base::Reversed(code()->instruction_blocks())) { |
1017 ResolvePhis(block); | 1162 ResolvePhis(block); |
1018 } | 1163 } |
1019 } | 1164 } |
1020 | 1165 |
1021 | 1166 |
1022 void ConstraintBuilder::ResolvePhis(const InstructionBlock* block) { | 1167 void ConstraintBuilder::ResolvePhis(const InstructionBlock* block) { |
1023 for (auto phi : block->phis()) { | 1168 for (auto phi : block->phis()) { |
1024 int phi_vreg = phi->virtual_register(); | 1169 int phi_vreg = phi->virtual_register(); |
1025 auto map_value = new (allocation_zone()) | 1170 auto map_value = data()->InitializePhiMap(block, phi); |
1026 RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); | |
1027 auto res = data()->phi_map().insert(std::make_pair(phi_vreg, map_value)); | |
1028 DCHECK(res.second); | |
1029 USE(res); | |
1030 auto& output = phi->output(); | 1171 auto& output = phi->output(); |
| 1172 // Map the destination operands, so the commitment phase can find them. |
1031 for (size_t i = 0; i < phi->operands().size(); ++i) { | 1173 for (size_t i = 0; i < phi->operands().size(); ++i) { |
1032 InstructionBlock* cur_block = | 1174 InstructionBlock* cur_block = |
1033 code()->InstructionBlockAt(block->predecessors()[i]); | 1175 code()->InstructionBlockAt(block->predecessors()[i]); |
1034 UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); | 1176 UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); |
1035 auto move = data()->AddGapMove(cur_block->last_instruction_index(), | 1177 auto move = data()->AddGapMove(cur_block->last_instruction_index(), |
1036 Instruction::END, input, output); | 1178 Instruction::END, input, output); |
1037 map_value->incoming_moves.push_back(move); | 1179 map_value->AddOperand(&move->destination()); |
1038 DCHECK(!InstructionAt(cur_block->last_instruction_index()) | 1180 DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
1039 ->HasReferenceMap()); | 1181 ->HasReferenceMap()); |
1040 } | 1182 } |
1041 auto live_range = LiveRangeFor(phi_vreg); | 1183 auto live_range = LiveRangeFor(phi_vreg); |
1042 int gap_index = block->first_instruction_index(); | 1184 int gap_index = block->first_instruction_index(); |
1043 live_range->SpillAtDefinition(allocation_zone(), gap_index, &output); | 1185 live_range->SpillAtDefinition(allocation_zone(), gap_index, &output); |
1044 live_range->SetSpillStartIndex(gap_index); | 1186 live_range->SetSpillStartIndex(gap_index); |
1045 // We use the phi-ness of some nodes in some later heuristics. | 1187 // We use the phi-ness of some nodes in some later heuristics. |
1046 live_range->set_is_phi(true); | 1188 live_range->set_is_phi(true); |
1047 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); | 1189 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
1048 } | 1190 } |
1049 } | 1191 } |
1050 | 1192 |
1051 | 1193 |
1052 LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data) | 1194 LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data, |
1053 : data_(data) {} | 1195 Zone* local_zone) |
| 1196 : data_(data), phi_hints_(local_zone) {} |
1054 | 1197 |
1055 | 1198 |
1056 BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) { | 1199 BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) { |
1057 // Compute live out for the given block, except not including backward | 1200 // Compute live out for the given block, except not including backward |
1058 // successor edges. | 1201 // successor edges. |
1059 auto live_out = new (allocation_zone()) | 1202 auto live_out = new (allocation_zone()) |
1060 BitVector(code()->VirtualRegisterCount(), allocation_zone()); | 1203 BitVector(code()->VirtualRegisterCount(), allocation_zone()); |
1061 | 1204 |
1062 // Process all successor blocks. | 1205 // Process all successor blocks. |
1063 for (auto succ : block->successors()) { | 1206 for (auto succ : block->successors()) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 } | 1245 } |
1103 | 1246 |
1104 | 1247 |
1105 LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { | 1248 LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { |
1106 DCHECK(index < config()->num_general_registers()); | 1249 DCHECK(index < config()->num_general_registers()); |
1107 auto result = data()->fixed_live_ranges()[index]; | 1250 auto result = data()->fixed_live_ranges()[index]; |
1108 if (result == nullptr) { | 1251 if (result == nullptr) { |
1109 result = data()->NewLiveRange(FixedLiveRangeID(index)); | 1252 result = data()->NewLiveRange(FixedLiveRangeID(index)); |
1110 DCHECK(result->IsFixed()); | 1253 DCHECK(result->IsFixed()); |
1111 result->set_kind(GENERAL_REGISTERS); | 1254 result->set_kind(GENERAL_REGISTERS); |
1112 data()->SetLiveRangeAssignedRegister(result, index); | 1255 result->set_assigned_register(index); |
| 1256 data()->MarkAllocated(GENERAL_REGISTERS, index); |
1113 data()->fixed_live_ranges()[index] = result; | 1257 data()->fixed_live_ranges()[index] = result; |
1114 } | 1258 } |
1115 return result; | 1259 return result; |
1116 } | 1260 } |
1117 | 1261 |
1118 | 1262 |
1119 LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { | 1263 LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { |
1120 DCHECK(index < config()->num_aliased_double_registers()); | 1264 DCHECK(index < config()->num_aliased_double_registers()); |
1121 auto result = data()->fixed_double_live_ranges()[index]; | 1265 auto result = data()->fixed_double_live_ranges()[index]; |
1122 if (result == nullptr) { | 1266 if (result == nullptr) { |
1123 result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); | 1267 result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); |
1124 DCHECK(result->IsFixed()); | 1268 DCHECK(result->IsFixed()); |
1125 result->set_kind(DOUBLE_REGISTERS); | 1269 result->set_kind(DOUBLE_REGISTERS); |
1126 data()->SetLiveRangeAssignedRegister(result, index); | 1270 result->set_assigned_register(index); |
| 1271 data()->MarkAllocated(DOUBLE_REGISTERS, index); |
1127 data()->fixed_double_live_ranges()[index] = result; | 1272 data()->fixed_double_live_ranges()[index] = result; |
1128 } | 1273 } |
1129 return result; | 1274 return result; |
1130 } | 1275 } |
1131 | 1276 |
1132 | 1277 |
1133 LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { | 1278 LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { |
1134 if (operand->IsUnallocated()) { | 1279 if (operand->IsUnallocated()) { |
1135 return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); | 1280 return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); |
1136 } else if (operand->IsConstant()) { | 1281 } else if (operand->IsConstant()) { |
1137 return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); | 1282 return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); |
1138 } else if (operand->IsRegister()) { | 1283 } else if (operand->IsRegister()) { |
1139 return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); | 1284 return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); |
1140 } else if (operand->IsDoubleRegister()) { | 1285 } else if (operand->IsDoubleRegister()) { |
1141 return FixedDoubleLiveRangeFor( | 1286 return FixedDoubleLiveRangeFor( |
1142 DoubleRegisterOperand::cast(operand)->index()); | 1287 DoubleRegisterOperand::cast(operand)->index()); |
1143 } else { | 1288 } else { |
1144 return nullptr; | 1289 return nullptr; |
1145 } | 1290 } |
1146 } | 1291 } |
1147 | 1292 |
1148 | 1293 |
1149 void LiveRangeBuilder::Define(LifetimePosition position, | 1294 UsePosition* LiveRangeBuilder::NewUsePosition(LifetimePosition pos, |
1150 InstructionOperand* operand, | 1295 InstructionOperand* operand, |
1151 InstructionOperand* hint) { | 1296 void* hint, |
| 1297 UsePositionHintType hint_type) { |
| 1298 return new (allocation_zone()) UsePosition(pos, operand, hint, hint_type); |
| 1299 } |
| 1300 |
| 1301 |
| 1302 UsePosition* LiveRangeBuilder::Define(LifetimePosition position, |
| 1303 InstructionOperand* operand, void* hint, |
| 1304 UsePositionHintType hint_type) { |
1152 auto range = LiveRangeFor(operand); | 1305 auto range = LiveRangeFor(operand); |
1153 if (range == nullptr) return; | 1306 if (range == nullptr) return nullptr; |
1154 | 1307 |
1155 if (range->IsEmpty() || range->Start() > position) { | 1308 if (range->IsEmpty() || range->Start() > position) { |
1156 // Can happen if there is a definition without use. | 1309 // Can happen if there is a definition without use. |
1157 range->AddUseInterval(position, position.NextStart(), allocation_zone()); | 1310 range->AddUseInterval(position, position.NextStart(), allocation_zone()); |
1158 range->AddUsePosition(position.NextStart(), nullptr, nullptr, | 1311 range->AddUsePosition(NewUsePosition(position.NextStart())); |
1159 allocation_zone()); | |
1160 } else { | 1312 } else { |
1161 range->ShortenTo(position); | 1313 range->ShortenTo(position); |
1162 } | 1314 } |
1163 | 1315 if (!operand->IsUnallocated()) return nullptr; |
1164 if (operand->IsUnallocated()) { | 1316 auto unalloc_operand = UnallocatedOperand::cast(operand); |
1165 auto unalloc_operand = UnallocatedOperand::cast(operand); | 1317 auto use_pos = NewUsePosition(position, unalloc_operand, hint, hint_type); |
1166 range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); | 1318 range->AddUsePosition(use_pos); |
1167 } | 1319 return use_pos; |
1168 } | 1320 } |
1169 | 1321 |
1170 | 1322 |
1171 void LiveRangeBuilder::Use(LifetimePosition block_start, | 1323 UsePosition* LiveRangeBuilder::Use(LifetimePosition block_start, |
1172 LifetimePosition position, | 1324 LifetimePosition position, |
1173 InstructionOperand* operand, | 1325 InstructionOperand* operand, void* hint, |
1174 InstructionOperand* hint) { | 1326 UsePositionHintType hint_type) { |
1175 auto range = LiveRangeFor(operand); | 1327 auto range = LiveRangeFor(operand); |
1176 if (range == nullptr) return; | 1328 if (range == nullptr) return nullptr; |
| 1329 UsePosition* use_pos = nullptr; |
1177 if (operand->IsUnallocated()) { | 1330 if (operand->IsUnallocated()) { |
1178 UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); | 1331 UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
1179 range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); | 1332 use_pos = NewUsePosition(position, unalloc_operand, hint, hint_type); |
| 1333 range->AddUsePosition(use_pos); |
1180 } | 1334 } |
1181 range->AddUseInterval(block_start, position, allocation_zone()); | 1335 range->AddUseInterval(block_start, position, allocation_zone()); |
| 1336 return use_pos; |
1182 } | 1337 } |
1183 | 1338 |
1184 | 1339 |
1185 bool LiveRangeBuilder::IsOutputRegisterOf(Instruction* instr, int index) { | |
1186 for (size_t i = 0; i < instr->OutputCount(); i++) { | |
1187 auto output = instr->OutputAt(i); | |
1188 if (output->IsRegister() && RegisterOperand::cast(output)->index() == index) | |
1189 return true; | |
1190 } | |
1191 return false; | |
1192 } | |
1193 | |
1194 | |
1195 bool LiveRangeBuilder::IsOutputDoubleRegisterOf(Instruction* instr, int index) { | |
1196 for (size_t i = 0; i < instr->OutputCount(); i++) { | |
1197 auto output = instr->OutputAt(i); | |
1198 if (output->IsDoubleRegister() && | |
1199 DoubleRegisterOperand::cast(output)->index() == index) | |
1200 return true; | |
1201 } | |
1202 return false; | |
1203 } | |
1204 | |
1205 | |
1206 void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, | 1340 void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
1207 BitVector* live) { | 1341 BitVector* live) { |
1208 int block_start = block->first_instruction_index(); | 1342 int block_start = block->first_instruction_index(); |
1209 auto block_start_position = | 1343 auto block_start_position = |
1210 LifetimePosition::GapFromInstructionIndex(block_start); | 1344 LifetimePosition::GapFromInstructionIndex(block_start); |
1211 | 1345 |
1212 for (int index = block->last_instruction_index(); index >= block_start; | 1346 for (int index = block->last_instruction_index(); index >= block_start; |
1213 index--) { | 1347 index--) { |
1214 auto curr_position = | 1348 auto curr_position = |
1215 LifetimePosition::InstructionFromInstructionIndex(index); | 1349 LifetimePosition::InstructionFromInstructionIndex(index); |
1216 auto instr = code()->InstructionAt(index); | 1350 auto instr = code()->InstructionAt(index); |
1217 DCHECK(instr != nullptr); | 1351 DCHECK(instr != nullptr); |
1218 DCHECK(curr_position.IsInstructionPosition()); | 1352 DCHECK(curr_position.IsInstructionPosition()); |
1219 // Process output, inputs, and temps of this instruction. | 1353 // Process output, inputs, and temps of this instruction. |
1220 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1354 for (size_t i = 0; i < instr->OutputCount(); i++) { |
1221 auto output = instr->OutputAt(i); | 1355 auto output = instr->OutputAt(i); |
1222 if (output->IsUnallocated()) { | 1356 if (output->IsUnallocated()) { |
1223 // Unsupported. | 1357 // Unsupported. |
1224 DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); | 1358 DCHECK(!UnallocatedOperand::cast(output)->HasSlotPolicy()); |
1225 int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); | 1359 int out_vreg = UnallocatedOperand::cast(output)->virtual_register(); |
1226 live->Remove(out_vreg); | 1360 live->Remove(out_vreg); |
1227 } else if (output->IsConstant()) { | 1361 } else if (output->IsConstant()) { |
1228 int out_vreg = ConstantOperand::cast(output)->virtual_register(); | 1362 int out_vreg = ConstantOperand::cast(output)->virtual_register(); |
1229 live->Remove(out_vreg); | 1363 live->Remove(out_vreg); |
1230 } | 1364 } |
1231 Define(curr_position, output, nullptr); | 1365 Define(curr_position, output); |
1232 } | 1366 } |
1233 | 1367 |
1234 if (instr->ClobbersRegisters()) { | 1368 if (instr->ClobbersRegisters()) { |
1235 for (int i = 0; i < config()->num_general_registers(); ++i) { | 1369 for (int i = 0; i < config()->num_general_registers(); ++i) { |
1236 if (!IsOutputRegisterOf(instr, i)) { | 1370 if (!IsOutputRegisterOf(instr, i)) { |
1237 auto range = FixedLiveRangeFor(i); | 1371 auto range = FixedLiveRangeFor(i); |
1238 range->AddUseInterval(curr_position, curr_position.End(), | 1372 range->AddUseInterval(curr_position, curr_position.End(), |
1239 allocation_zone()); | 1373 allocation_zone()); |
1240 } | 1374 } |
1241 } | 1375 } |
(...skipping 21 matching lines...) Expand all Loading... |
1263 } | 1397 } |
1264 | 1398 |
1265 if (input->IsUnallocated()) { | 1399 if (input->IsUnallocated()) { |
1266 UnallocatedOperand* unalloc = UnallocatedOperand::cast(input); | 1400 UnallocatedOperand* unalloc = UnallocatedOperand::cast(input); |
1267 int vreg = unalloc->virtual_register(); | 1401 int vreg = unalloc->virtual_register(); |
1268 live->Add(vreg); | 1402 live->Add(vreg); |
1269 if (unalloc->HasSlotPolicy()) { | 1403 if (unalloc->HasSlotPolicy()) { |
1270 LiveRangeFor(vreg)->set_has_slot_use(true); | 1404 LiveRangeFor(vreg)->set_has_slot_use(true); |
1271 } | 1405 } |
1272 } | 1406 } |
1273 Use(block_start_position, use_pos, input, nullptr); | 1407 Use(block_start_position, use_pos, input); |
1274 } | 1408 } |
1275 | 1409 |
1276 for (size_t i = 0; i < instr->TempCount(); i++) { | 1410 for (size_t i = 0; i < instr->TempCount(); i++) { |
1277 auto temp = instr->TempAt(i); | 1411 auto temp = instr->TempAt(i); |
1278 // Unsupported. | 1412 // Unsupported. |
1279 DCHECK_IMPLIES(temp->IsUnallocated(), | 1413 DCHECK_IMPLIES(temp->IsUnallocated(), |
1280 !UnallocatedOperand::cast(temp)->HasSlotPolicy()); | 1414 !UnallocatedOperand::cast(temp)->HasSlotPolicy()); |
1281 if (instr->ClobbersTemps()) { | 1415 if (instr->ClobbersTemps()) { |
1282 if (temp->IsRegister()) continue; | 1416 if (temp->IsRegister()) continue; |
1283 if (temp->IsUnallocated()) { | 1417 if (temp->IsUnallocated()) { |
1284 UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); | 1418 UnallocatedOperand* temp_unalloc = UnallocatedOperand::cast(temp); |
1285 if (temp_unalloc->HasFixedPolicy()) { | 1419 if (temp_unalloc->HasFixedPolicy()) { |
1286 continue; | 1420 continue; |
1287 } | 1421 } |
1288 } | 1422 } |
1289 } | 1423 } |
1290 Use(block_start_position, curr_position.End(), temp, nullptr); | 1424 Use(block_start_position, curr_position.End(), temp); |
1291 Define(curr_position, temp, nullptr); | 1425 Define(curr_position, temp); |
1292 } | 1426 } |
1293 | 1427 |
1294 // Process the moves of the instruction's gaps, making their sources live. | 1428 // Process the moves of the instruction's gaps, making their sources live. |
1295 const Instruction::GapPosition kPositions[] = {Instruction::END, | 1429 const Instruction::GapPosition kPositions[] = {Instruction::END, |
1296 Instruction::START}; | 1430 Instruction::START}; |
1297 curr_position = curr_position.PrevStart(); | 1431 curr_position = curr_position.PrevStart(); |
1298 DCHECK(curr_position.IsGapPosition()); | 1432 DCHECK(curr_position.IsGapPosition()); |
1299 for (auto position : kPositions) { | 1433 for (auto position : kPositions) { |
1300 auto move = instr->GetParallelMove(position); | 1434 auto move = instr->GetParallelMove(position); |
1301 if (move == nullptr) continue; | 1435 if (move == nullptr) continue; |
1302 if (position == Instruction::END) { | 1436 if (position == Instruction::END) { |
1303 curr_position = curr_position.End(); | 1437 curr_position = curr_position.End(); |
1304 } else { | 1438 } else { |
1305 curr_position = curr_position.Start(); | 1439 curr_position = curr_position.Start(); |
1306 } | 1440 } |
1307 for (auto cur : *move) { | 1441 for (auto cur : *move) { |
1308 auto& from = cur->source(); | 1442 auto& from = cur->source(); |
1309 auto& to = cur->destination(); | 1443 auto& to = cur->destination(); |
1310 auto hint = &to; | 1444 void* hint = &to; |
| 1445 UsePositionHintType hint_type = UsePosition::HintTypeForOperand(to); |
| 1446 UsePosition* to_use = nullptr; |
| 1447 int phi_vreg = -1; |
1311 if (to.IsUnallocated()) { | 1448 if (to.IsUnallocated()) { |
1312 int to_vreg = UnallocatedOperand::cast(to).virtual_register(); | 1449 int to_vreg = UnallocatedOperand::cast(to).virtual_register(); |
1313 auto to_range = LiveRangeFor(to_vreg); | 1450 auto to_range = LiveRangeFor(to_vreg); |
1314 if (to_range->is_phi()) { | 1451 if (to_range->is_phi()) { |
| 1452 phi_vreg = to_vreg; |
1315 if (to_range->is_non_loop_phi()) { | 1453 if (to_range->is_non_loop_phi()) { |
1316 hint = to_range->current_hint_operand(); | 1454 hint = to_range->current_hint_position(); |
| 1455 hint_type = hint == nullptr ? UsePositionHintType::kNone |
| 1456 : UsePositionHintType::kUsePos; |
| 1457 } else { |
| 1458 hint_type = UsePositionHintType::kPhi; |
| 1459 hint = data()->GetPhiMapValueFor(to_vreg); |
1317 } | 1460 } |
1318 } else { | 1461 } else { |
1319 if (live->Contains(to_vreg)) { | 1462 if (live->Contains(to_vreg)) { |
1320 Define(curr_position, &to, &from); | 1463 to_use = Define(curr_position, &to, &from, |
| 1464 UsePosition::HintTypeForOperand(from)); |
1321 live->Remove(to_vreg); | 1465 live->Remove(to_vreg); |
1322 } else { | 1466 } else { |
1323 cur->Eliminate(); | 1467 cur->Eliminate(); |
1324 continue; | 1468 continue; |
1325 } | 1469 } |
1326 } | 1470 } |
1327 } else { | 1471 } else { |
1328 Define(curr_position, &to, &from); | 1472 Define(curr_position, &to); |
1329 } | 1473 } |
1330 Use(block_start_position, curr_position, &from, hint); | 1474 auto from_use = |
| 1475 Use(block_start_position, curr_position, &from, hint, hint_type); |
| 1476 // Mark range live. |
1331 if (from.IsUnallocated()) { | 1477 if (from.IsUnallocated()) { |
1332 live->Add(UnallocatedOperand::cast(from).virtual_register()); | 1478 live->Add(UnallocatedOperand::cast(from).virtual_register()); |
1333 } | 1479 } |
| 1480 // Resolve use position hints just created. |
| 1481 if (to_use != nullptr && from_use != nullptr) { |
| 1482 to_use->ResolveHint(from_use); |
| 1483 from_use->ResolveHint(to_use); |
| 1484 } |
| 1485 DCHECK_IMPLIES(to_use != nullptr, to_use->IsResolved()); |
| 1486 DCHECK_IMPLIES(from_use != nullptr, from_use->IsResolved()); |
| 1487 // Potentially resolve phi hint. |
| 1488 if (phi_vreg != -1) ResolvePhiHint(&from, from_use); |
1334 } | 1489 } |
1335 } | 1490 } |
1336 } | 1491 } |
1337 } | 1492 } |
1338 | 1493 |
1339 | 1494 |
| 1495 void LiveRangeBuilder::ProcessPhis(const InstructionBlock* block, |
| 1496 BitVector* live) { |
| 1497 for (auto phi : block->phis()) { |
| 1498 // The live range interval already ends at the first instruction of the |
| 1499 // block. |
| 1500 int phi_vreg = phi->virtual_register(); |
| 1501 live->Remove(phi_vreg); |
| 1502 InstructionOperand* hint = nullptr; |
| 1503 auto instr = GetLastInstruction( |
| 1504 code(), code()->InstructionBlockAt(block->predecessors()[0])); |
| 1505 for (auto move : *instr->GetParallelMove(Instruction::END)) { |
| 1506 auto& to = move->destination(); |
| 1507 if (to.IsUnallocated() && |
| 1508 UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { |
| 1509 hint = &move->source(); |
| 1510 break; |
| 1511 } |
| 1512 } |
| 1513 DCHECK(hint != nullptr); |
| 1514 auto block_start = LifetimePosition::GapFromInstructionIndex( |
| 1515 block->first_instruction_index()); |
| 1516 auto use_pos = Define(block_start, &phi->output(), hint, |
| 1517 UsePosition::HintTypeForOperand(*hint)); |
| 1518 MapPhiHint(hint, use_pos); |
| 1519 } |
| 1520 } |
| 1521 |
| 1522 |
| 1523 void LiveRangeBuilder::ProcessLoopHeader(const InstructionBlock* block, |
| 1524 BitVector* live) { |
| 1525 DCHECK(block->IsLoopHeader()); |
| 1526 // Add a live range stretching from the first loop instruction to the last |
| 1527 // for each value live on entry to the header. |
| 1528 BitVector::Iterator iterator(live); |
| 1529 auto start = LifetimePosition::GapFromInstructionIndex( |
| 1530 block->first_instruction_index()); |
| 1531 auto end = LifetimePosition::GapFromInstructionIndex( |
| 1532 code()->LastLoopInstructionIndex(block)).NextFullStart(); |
| 1533 while (!iterator.Done()) { |
| 1534 int operand_index = iterator.Current(); |
| 1535 auto range = LiveRangeFor(operand_index); |
| 1536 range->EnsureInterval(start, end, allocation_zone()); |
| 1537 iterator.Advance(); |
| 1538 } |
| 1539 // Insert all values into the live in sets of all blocks in the loop. |
| 1540 for (int i = block->rpo_number().ToInt() + 1; i < block->loop_end().ToInt(); |
| 1541 ++i) { |
| 1542 live_in_sets()[i]->Union(*live); |
| 1543 } |
| 1544 } |
| 1545 |
| 1546 |
1340 void LiveRangeBuilder::BuildLiveRanges() { | 1547 void LiveRangeBuilder::BuildLiveRanges() { |
1341 // Process the blocks in reverse order. | 1548 // Process the blocks in reverse order. |
1342 for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; | 1549 for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; |
1343 --block_id) { | 1550 --block_id) { |
1344 auto block = code()->InstructionBlockAt(RpoNumber::FromInt(block_id)); | 1551 auto block = code()->InstructionBlockAt(RpoNumber::FromInt(block_id)); |
1345 auto live = ComputeLiveOut(block); | 1552 auto live = ComputeLiveOut(block); |
1346 // Initially consider all live_out values live for the entire block. We | 1553 // Initially consider all live_out values live for the entire block. We |
1347 // will shorten these intervals if necessary. | 1554 // will shorten these intervals if necessary. |
1348 AddInitialIntervals(block, live); | 1555 AddInitialIntervals(block, live); |
1349 | |
1350 // Process the instructions in reverse order, generating and killing | 1556 // Process the instructions in reverse order, generating and killing |
1351 // live values. | 1557 // live values. |
1352 ProcessInstructions(block, live); | 1558 ProcessInstructions(block, live); |
1353 // All phi output operands are killed by this block. | 1559 // All phi output operands are killed by this block. |
1354 for (auto phi : block->phis()) { | 1560 ProcessPhis(block, live); |
1355 // The live range interval already ends at the first instruction of the | |
1356 // block. | |
1357 int phi_vreg = phi->virtual_register(); | |
1358 live->Remove(phi_vreg); | |
1359 InstructionOperand* hint = nullptr; | |
1360 auto instr = GetLastInstruction( | |
1361 code(), code()->InstructionBlockAt(block->predecessors()[0])); | |
1362 for (auto move : *instr->GetParallelMove(Instruction::END)) { | |
1363 auto& to = move->destination(); | |
1364 if (to.IsUnallocated() && | |
1365 UnallocatedOperand::cast(to).virtual_register() == phi_vreg) { | |
1366 hint = &move->source(); | |
1367 break; | |
1368 } | |
1369 } | |
1370 DCHECK(hint != nullptr); | |
1371 auto block_start = LifetimePosition::GapFromInstructionIndex( | |
1372 block->first_instruction_index()); | |
1373 Define(block_start, &phi->output(), hint); | |
1374 } | |
1375 | |
1376 // Now live is live_in for this block except not including values live | 1561 // Now live is live_in for this block except not including values live |
1377 // out on backward successor edges. | 1562 // out on backward successor edges. |
| 1563 if (block->IsLoopHeader()) ProcessLoopHeader(block, live); |
1378 live_in_sets()[block_id] = live; | 1564 live_in_sets()[block_id] = live; |
1379 | |
1380 if (block->IsLoopHeader()) { | |
1381 // Add a live range stretching from the first loop instruction to the last | |
1382 // for each value live on entry to the header. | |
1383 BitVector::Iterator iterator(live); | |
1384 auto start = LifetimePosition::GapFromInstructionIndex( | |
1385 block->first_instruction_index()); | |
1386 auto end = LifetimePosition::GapFromInstructionIndex( | |
1387 code()->LastLoopInstructionIndex(block)).NextFullStart(); | |
1388 while (!iterator.Done()) { | |
1389 int operand_index = iterator.Current(); | |
1390 auto range = LiveRangeFor(operand_index); | |
1391 range->EnsureInterval(start, end, allocation_zone()); | |
1392 iterator.Advance(); | |
1393 } | |
1394 // Insert all values into the live in sets of all blocks in the loop. | |
1395 for (int i = block->rpo_number().ToInt() + 1; | |
1396 i < block->loop_end().ToInt(); ++i) { | |
1397 live_in_sets()[i]->Union(*live); | |
1398 } | |
1399 } | |
1400 } | 1565 } |
1401 | 1566 // Postprocess the ranges. |
1402 for (auto range : data()->live_ranges()) { | 1567 for (auto range : data()->live_ranges()) { |
1403 if (range == nullptr) continue; | 1568 if (range == nullptr) continue; |
1404 range->set_kind(RequiredRegisterKind(range->id())); | 1569 range->set_kind(RequiredRegisterKind(range->id())); |
1405 // Give slots to all ranges with a non fixed slot use. | 1570 // Give slots to all ranges with a non fixed slot use. |
1406 if (range->has_slot_use() && range->HasNoSpillType()) { | 1571 if (range->has_slot_use() && range->HasNoSpillType()) { |
1407 data()->AssignSpillRangeToLiveRange(range); | 1572 data()->AssignSpillRangeToLiveRange(range); |
1408 } | 1573 } |
1409 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1574 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
1410 // live ranges, every use requires the constant to be in a register. | 1575 // live ranges, every use requires the constant to be in a register. |
1411 // Without this hack, all uses with "any" policy would get the constant | 1576 // Without this hack, all uses with "any" policy would get the constant |
1412 // operand assigned. | 1577 // operand assigned. |
1413 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { | 1578 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { |
1414 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) { | 1579 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) { |
1415 if (pos->type() == UsePositionType::kRequiresSlot) continue; | 1580 if (pos->type() == UsePositionType::kRequiresSlot) continue; |
1416 UsePositionType new_type = UsePositionType::kAny; | 1581 UsePositionType new_type = UsePositionType::kAny; |
1417 // Can't mark phis as needing a register. | 1582 // Can't mark phis as needing a register. |
1418 if (!pos->pos().IsGapPosition()) { | 1583 if (!pos->pos().IsGapPosition()) { |
1419 new_type = UsePositionType::kRequiresRegister; | 1584 new_type = UsePositionType::kRequiresRegister; |
1420 } | 1585 } |
1421 pos->set_type(new_type, true); | 1586 pos->set_type(new_type, true); |
1422 } | 1587 } |
1423 } | 1588 } |
1424 } | 1589 } |
1425 | |
1426 #ifdef DEBUG | 1590 #ifdef DEBUG |
1427 Verify(); | 1591 Verify(); |
1428 #endif | 1592 #endif |
1429 } | 1593 } |
1430 | 1594 |
1431 | 1595 |
| 1596 void LiveRangeBuilder::MapPhiHint(InstructionOperand* operand, |
| 1597 UsePosition* use_pos) { |
| 1598 DCHECK(!use_pos->IsResolved()); |
| 1599 auto res = phi_hints_.insert(std::make_pair(operand, use_pos)); |
| 1600 DCHECK(res.second); |
| 1601 USE(res); |
| 1602 } |
| 1603 |
| 1604 |
| 1605 void LiveRangeBuilder::ResolvePhiHint(InstructionOperand* operand, |
| 1606 UsePosition* use_pos) { |
| 1607 auto it = phi_hints_.find(operand); |
| 1608 if (it == phi_hints_.end()) return; |
| 1609 DCHECK(!it->second->IsResolved()); |
| 1610 it->second->ResolveHint(use_pos); |
| 1611 } |
| 1612 |
| 1613 |
1432 RegisterKind LiveRangeBuilder::RequiredRegisterKind( | 1614 RegisterKind LiveRangeBuilder::RequiredRegisterKind( |
1433 int virtual_register) const { | 1615 int virtual_register) const { |
1434 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS | 1616 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS |
1435 : GENERAL_REGISTERS; | 1617 : GENERAL_REGISTERS; |
1436 } | 1618 } |
1437 | 1619 |
1438 | 1620 |
1439 void LiveRangeBuilder::Verify() const { | 1621 void LiveRangeBuilder::Verify() const { |
| 1622 for (auto& hint : phi_hints_) { |
| 1623 CHECK(hint.second->IsResolved()); |
| 1624 } |
1440 for (auto current : data()->live_ranges()) { | 1625 for (auto current : data()->live_ranges()) { |
1441 if (current != nullptr) current->Verify(); | 1626 if (current != nullptr) current->Verify(); |
1442 } | 1627 } |
1443 } | 1628 } |
1444 | 1629 |
1445 | 1630 |
1446 RegisterAllocator::RegisterAllocator(RegisterAllocationData* data, | 1631 RegisterAllocator::RegisterAllocator(RegisterAllocationData* data, |
1447 RegisterKind kind) | 1632 RegisterKind kind) |
1448 : data_(data), | 1633 : data_(data), |
1449 mode_(kind), | 1634 mode_(kind), |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1670 | 1855 |
1671 const char* LinearScanAllocator::RegisterName(int allocation_index) const { | 1856 const char* LinearScanAllocator::RegisterName(int allocation_index) const { |
1672 if (mode() == GENERAL_REGISTERS) { | 1857 if (mode() == GENERAL_REGISTERS) { |
1673 return data()->config()->general_register_name(allocation_index); | 1858 return data()->config()->general_register_name(allocation_index); |
1674 } else { | 1859 } else { |
1675 return data()->config()->double_register_name(allocation_index); | 1860 return data()->config()->double_register_name(allocation_index); |
1676 } | 1861 } |
1677 } | 1862 } |
1678 | 1863 |
1679 | 1864 |
| 1865 void LinearScanAllocator::SetLiveRangeAssignedRegister(LiveRange* range, |
| 1866 int reg) { |
| 1867 data()->MarkAllocated(range->Kind(), reg); |
| 1868 range->set_assigned_register(reg); |
| 1869 range->SetUseHints(reg); |
| 1870 if (range->is_phi()) { |
| 1871 data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg); |
| 1872 } |
| 1873 } |
| 1874 |
| 1875 |
1680 void LinearScanAllocator::AddToActive(LiveRange* range) { | 1876 void LinearScanAllocator::AddToActive(LiveRange* range) { |
1681 TRACE("Add live range %d to active\n", range->id()); | 1877 TRACE("Add live range %d to active\n", range->id()); |
1682 active_live_ranges().push_back(range); | 1878 active_live_ranges().push_back(range); |
1683 } | 1879 } |
1684 | 1880 |
1685 | 1881 |
1686 void LinearScanAllocator::AddToInactive(LiveRange* range) { | 1882 void LinearScanAllocator::AddToInactive(LiveRange* range) { |
1687 TRACE("Add live range %d to inactive\n", range->id()); | 1883 TRACE("Add live range %d to inactive\n", range->id()); |
1688 inactive_live_ranges().push_back(range); | 1884 inactive_live_ranges().push_back(range); |
1689 } | 1885 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1785 } | 1981 } |
1786 | 1982 |
1787 for (auto cur_inactive : inactive_live_ranges()) { | 1983 for (auto cur_inactive : inactive_live_ranges()) { |
1788 DCHECK(cur_inactive->End() > current->Start()); | 1984 DCHECK(cur_inactive->End() > current->Start()); |
1789 auto next_intersection = cur_inactive->FirstIntersection(current); | 1985 auto next_intersection = cur_inactive->FirstIntersection(current); |
1790 if (!next_intersection.IsValid()) continue; | 1986 if (!next_intersection.IsValid()) continue; |
1791 int cur_reg = cur_inactive->assigned_register(); | 1987 int cur_reg = cur_inactive->assigned_register(); |
1792 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); | 1988 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); |
1793 } | 1989 } |
1794 | 1990 |
1795 auto hint = current->FirstHint(); | 1991 int hint_register; |
1796 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { | 1992 if (current->FirstHintPosition(&hint_register) != nullptr) { |
1797 int register_index = AllocatedOperand::cast(hint)->index(); | |
1798 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", | 1993 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", |
1799 RegisterName(register_index), free_until_pos[register_index].value(), | 1994 RegisterName(hint_register), free_until_pos[hint_register].value(), |
1800 current->id(), current->End().value()); | 1995 current->id(), current->End().value()); |
1801 | 1996 |
1802 // The desired register is free until the end of the current live range. | 1997 // The desired register is free until the end of the current live range. |
1803 if (free_until_pos[register_index] >= current->End()) { | 1998 if (free_until_pos[hint_register] >= current->End()) { |
1804 TRACE("Assigning preferred reg %s to live range %d\n", | 1999 TRACE("Assigning preferred reg %s to live range %d\n", |
1805 RegisterName(register_index), current->id()); | 2000 RegisterName(hint_register), current->id()); |
1806 data()->SetLiveRangeAssignedRegister(current, register_index); | 2001 SetLiveRangeAssignedRegister(current, hint_register); |
1807 return true; | 2002 return true; |
1808 } | 2003 } |
1809 } | 2004 } |
1810 | 2005 |
1811 // Find the register which stays free for the longest time. | 2006 // Find the register which stays free for the longest time. |
1812 int reg = 0; | 2007 int reg = 0; |
1813 for (int i = 1; i < num_registers(); ++i) { | 2008 for (int i = 1; i < num_registers(); ++i) { |
1814 if (free_until_pos[i] > free_until_pos[reg]) { | 2009 if (free_until_pos[i] > free_until_pos[reg]) { |
1815 reg = i; | 2010 reg = i; |
1816 } | 2011 } |
(...skipping 11 matching lines...) Expand all Loading... |
1828 // the range end. Split current at position where it becomes blocked. | 2023 // the range end. Split current at position where it becomes blocked. |
1829 auto tail = SplitRangeAt(current, pos); | 2024 auto tail = SplitRangeAt(current, pos); |
1830 AddToUnhandledSorted(tail); | 2025 AddToUnhandledSorted(tail); |
1831 } | 2026 } |
1832 | 2027 |
1833 // Register reg is available at the range start and is free until | 2028 // Register reg is available at the range start and is free until |
1834 // the range end. | 2029 // the range end. |
1835 DCHECK(pos >= current->End()); | 2030 DCHECK(pos >= current->End()); |
1836 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), | 2031 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), |
1837 current->id()); | 2032 current->id()); |
1838 data()->SetLiveRangeAssignedRegister(current, reg); | 2033 SetLiveRangeAssignedRegister(current, reg); |
1839 | 2034 |
1840 return true; | 2035 return true; |
1841 } | 2036 } |
1842 | 2037 |
1843 | 2038 |
1844 void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { | 2039 void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { |
1845 auto register_use = current->NextRegisterPosition(current->Start()); | 2040 auto register_use = current->NextRegisterPosition(current->Start()); |
1846 if (register_use == nullptr) { | 2041 if (register_use == nullptr) { |
1847 // There is no use in the current live range that requires a register. | 2042 // There is no use in the current live range that requires a register. |
1848 // We can just spill it. | 2043 // We can just spill it. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1907 // position. | 2102 // position. |
1908 LiveRange* tail = | 2103 LiveRange* tail = |
1909 SplitBetween(current, current->Start(), block_pos[reg].Start()); | 2104 SplitBetween(current, current->Start(), block_pos[reg].Start()); |
1910 AddToUnhandledSorted(tail); | 2105 AddToUnhandledSorted(tail); |
1911 } | 2106 } |
1912 | 2107 |
1913 // Register reg is not blocked for the whole range. | 2108 // Register reg is not blocked for the whole range. |
1914 DCHECK(block_pos[reg] >= current->End()); | 2109 DCHECK(block_pos[reg] >= current->End()); |
1915 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), | 2110 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), |
1916 current->id()); | 2111 current->id()); |
1917 data()->SetLiveRangeAssignedRegister(current, reg); | 2112 SetLiveRangeAssignedRegister(current, reg); |
1918 | 2113 |
1919 // This register was not free. Thus we need to find and spill | 2114 // This register was not free. Thus we need to find and spill |
1920 // parts of active and inactive live regions that use the same register | 2115 // parts of active and inactive live regions that use the same register |
1921 // at the same lifetime positions as current. | 2116 // at the same lifetime positions as current. |
1922 SplitAndSpillIntersecting(current); | 2117 SplitAndSpillIntersecting(current); |
1923 } | 2118 } |
1924 | 2119 |
1925 | 2120 |
1926 void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) { | 2121 void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) { |
1927 DCHECK(current->HasRegisterAssigned()); | 2122 DCHECK(current->HasRegisterAssigned()); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1967 --i; | 2162 --i; |
1968 } | 2163 } |
1969 } | 2164 } |
1970 } | 2165 } |
1971 } | 2166 } |
1972 | 2167 |
1973 | 2168 |
1974 bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) { | 2169 bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) { |
1975 if (range->IsChild() || !range->is_phi()) return false; | 2170 if (range->IsChild() || !range->is_phi()) return false; |
1976 DCHECK(!range->HasSpillOperand()); | 2171 DCHECK(!range->HasSpillOperand()); |
1977 | 2172 auto phi_map_value = data()->GetPhiMapValueFor(range->id()); |
1978 auto lookup = data()->phi_map().find(range->id()); | 2173 auto phi = phi_map_value->phi(); |
1979 DCHECK(lookup != data()->phi_map().end()); | 2174 auto block = phi_map_value->block(); |
1980 auto phi = lookup->second->phi; | |
1981 auto block = lookup->second->block; | |
1982 // Count the number of spilled operands. | 2175 // Count the number of spilled operands. |
1983 size_t spilled_count = 0; | 2176 size_t spilled_count = 0; |
1984 LiveRange* first_op = nullptr; | 2177 LiveRange* first_op = nullptr; |
1985 for (size_t i = 0; i < phi->operands().size(); i++) { | 2178 for (size_t i = 0; i < phi->operands().size(); i++) { |
1986 int op = phi->operands()[i]; | 2179 int op = phi->operands()[i]; |
1987 LiveRange* op_range = LiveRangeFor(op); | 2180 LiveRange* op_range = LiveRangeFor(op); |
1988 if (!op_range->HasSpillRange()) continue; | 2181 if (!op_range->HasSpillRange()) continue; |
1989 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); | 2182 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); |
1990 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( | 2183 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
1991 pred->last_instruction_index()); | 2184 pred->last_instruction_index()); |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2192 } | 2385 } |
2193 | 2386 |
2194 | 2387 |
2195 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { | 2388 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { |
2196 allocations_[reg_id]->Insert(range); | 2389 allocations_[reg_id]->Insert(range); |
2197 if (range->HasRegisterAssigned()) { | 2390 if (range->HasRegisterAssigned()) { |
2198 DCHECK_EQ(reg_id, range->assigned_register()); | 2391 DCHECK_EQ(reg_id, range->assigned_register()); |
2199 return; | 2392 return; |
2200 } | 2393 } |
2201 range->set_assigned_register(reg_id); | 2394 range->set_assigned_register(reg_id); |
| 2395 range->SetUseHints(reg_id); |
| 2396 if (range->is_phi()) { |
| 2397 data()->GetPhiMapValueFor(range->id())->set_assigned_register(reg_id); |
| 2398 } |
2202 } | 2399 } |
2203 | 2400 |
2204 | 2401 |
2205 float GreedyAllocator::CalculateSpillWeight(LiveRange* range) { | 2402 float GreedyAllocator::CalculateSpillWeight(LiveRange* range) { |
2206 if (range->IsFixed()) return std::numeric_limits<float>::max(); | 2403 if (range->IsFixed()) return std::numeric_limits<float>::max(); |
2207 | 2404 |
2208 if (range->FirstHint() != nullptr && range->FirstHint()->IsRegister()) { | 2405 int hint_register; |
| 2406 if (range->FirstHintPosition(&hint_register) != nullptr) { |
2209 return std::numeric_limits<float>::max(); | 2407 return std::numeric_limits<float>::max(); |
2210 } | 2408 } |
2211 | 2409 |
2212 unsigned use_count = 0; | 2410 unsigned use_count = 0; |
2213 auto* pos = range->first_pos(); | 2411 auto* pos = range->first_pos(); |
2214 while (pos != nullptr) { | 2412 while (pos != nullptr) { |
2215 use_count++; | 2413 use_count++; |
2216 pos = pos->next(); | 2414 pos = pos->next(); |
2217 } | 2415 } |
2218 | 2416 |
(...skipping 11 matching lines...) Expand all Loading... |
2230 for (auto* r : ranges) { | 2428 for (auto* r : ranges) { |
2231 max = std::max(max, CalculateSpillWeight(r)); | 2429 max = std::max(max, CalculateSpillWeight(r)); |
2232 } | 2430 } |
2233 return max; | 2431 return max; |
2234 } | 2432 } |
2235 | 2433 |
2236 | 2434 |
2237 void GreedyAllocator::Evict(LiveRange* range) { | 2435 void GreedyAllocator::Evict(LiveRange* range) { |
2238 bool removed = allocations_[range->assigned_register()]->Remove(range); | 2436 bool removed = allocations_[range->assigned_register()]->Remove(range); |
2239 CHECK(removed); | 2437 CHECK(removed); |
| 2438 range->UnsetUseHints(); |
| 2439 range->UnsetAssignedRegister(); |
| 2440 if (range->is_phi()) { |
| 2441 data()->GetPhiMapValueFor(range->id())->UnsetAssignedRegister(); |
| 2442 } |
2240 } | 2443 } |
2241 | 2444 |
2242 | 2445 |
2243 bool GreedyAllocator::TryAllocatePhysicalRegister( | 2446 bool GreedyAllocator::TryAllocatePhysicalRegister( |
2244 unsigned reg_id, LiveRange* range, ZoneSet<LiveRange*>* conflicting) { | 2447 unsigned reg_id, LiveRange* range, ZoneSet<LiveRange*>* conflicting) { |
2245 auto* segment = range->first_interval(); | 2448 auto* segment = range->first_interval(); |
2246 | 2449 |
2247 auto* alloc_info = allocations_[reg_id]; | 2450 auto* alloc_info = allocations_[reg_id]; |
2248 while (segment != nullptr) { | 2451 while (segment != nullptr) { |
2249 if (auto* existing = alloc_info->Find(segment)) { | 2452 if (auto* existing = alloc_info->Find(segment)) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2398 CHECK(allocated); | 2601 CHECK(allocated); |
2399 DCHECK(conflicting.empty()); | 2602 DCHECK(conflicting.empty()); |
2400 } else { | 2603 } else { |
2401 DCHECK(!current->IsFixed() || current->CanBeSpilled(current->Start())); | 2604 DCHECK(!current->IsFixed() || current->CanBeSpilled(current->Start())); |
2402 bool allocated = AllocateBlockedRange(current, conflicting); | 2605 bool allocated = AllocateBlockedRange(current, conflicting); |
2403 CHECK(allocated); | 2606 CHECK(allocated); |
2404 } | 2607 } |
2405 } | 2608 } |
2406 } | 2609 } |
2407 | 2610 |
2408 BitVector* assigned_registers = new (zone) BitVector(num_registers(), zone); | |
2409 for (size_t i = 0; i < allocations_.size(); ++i) { | 2611 for (size_t i = 0; i < allocations_.size(); ++i) { |
2410 if (!allocations_[i]->IsEmpty()) { | 2612 if (!allocations_[i]->IsEmpty()) { |
2411 assigned_registers->Add(static_cast<int>(i)); | 2613 data()->MarkAllocated(mode(), static_cast<int>(i)); |
2412 } | 2614 } |
2413 } | 2615 } |
2414 data()->frame()->SetAllocatedRegisters(assigned_registers); | |
2415 } | 2616 } |
2416 | 2617 |
2417 | 2618 |
2418 bool GreedyAllocator::AllocateBlockedRange( | 2619 bool GreedyAllocator::AllocateBlockedRange( |
2419 LiveRange* current, const ZoneSet<LiveRange*>& conflicts) { | 2620 LiveRange* current, const ZoneSet<LiveRange*>& conflicts) { |
2420 auto register_use = current->NextRegisterPosition(current->Start()); | 2621 auto register_use = current->NextRegisterPosition(current->Start()); |
2421 if (register_use == nullptr) { | 2622 if (register_use == nullptr) { |
2422 // There is no use in the current live range that requires a register. | 2623 // There is no use in the current live range that requires a register. |
2423 // We can just spill it. | 2624 // We can just spill it. |
2424 Spill(current); | 2625 Spill(current); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2465 | 2666 |
2466 void OperandAssigner::CommitAssignment() { | 2667 void OperandAssigner::CommitAssignment() { |
2467 for (auto range : data()->live_ranges()) { | 2668 for (auto range : data()->live_ranges()) { |
2468 if (range == nullptr || range->IsEmpty()) continue; | 2669 if (range == nullptr || range->IsEmpty()) continue; |
2469 InstructionOperand* spill_operand = nullptr; | 2670 InstructionOperand* spill_operand = nullptr; |
2470 if (!range->TopLevel()->HasNoSpillType()) { | 2671 if (!range->TopLevel()->HasNoSpillType()) { |
2471 spill_operand = range->TopLevel()->GetSpillOperand(); | 2672 spill_operand = range->TopLevel()->GetSpillOperand(); |
2472 } | 2673 } |
2473 auto assigned = range->GetAssignedOperand(); | 2674 auto assigned = range->GetAssignedOperand(); |
2474 range->ConvertUsesToOperand(assigned, spill_operand); | 2675 range->ConvertUsesToOperand(assigned, spill_operand); |
2475 if (range->is_phi()) data()->AssignPhiInput(range, assigned); | 2676 if (range->is_phi()) { |
| 2677 data()->GetPhiMapValueFor(range->id())->CommitAssignment(assigned); |
| 2678 } |
2476 if (!range->IsChild() && spill_operand != nullptr) { | 2679 if (!range->IsChild() && spill_operand != nullptr) { |
2477 range->CommitSpillsAtDefinition(data()->code(), spill_operand, | 2680 range->CommitSpillsAtDefinition(data()->code(), spill_operand, |
2478 range->has_slot_use()); | 2681 range->has_slot_use()); |
2479 } | 2682 } |
2480 } | 2683 } |
2481 } | 2684 } |
2482 | 2685 |
2483 | 2686 |
2484 ReferenceMapPopulator::ReferenceMapPopulator(RegisterAllocationData* data) | 2687 ReferenceMapPopulator::ReferenceMapPopulator(RegisterAllocationData* data) |
2485 : data_(data) {} | 2688 : data_(data) {} |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2841 auto eliminate = moves->PrepareInsertAfter(move); | 3044 auto eliminate = moves->PrepareInsertAfter(move); |
2842 to_insert.push_back(move); | 3045 to_insert.push_back(move); |
2843 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 3046 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
2844 } | 3047 } |
2845 } | 3048 } |
2846 | 3049 |
2847 | 3050 |
2848 } // namespace compiler | 3051 } // namespace compiler |
2849 } // namespace internal | 3052 } // namespace internal |
2850 } // namespace v8 | 3053 } // namespace v8 |
OLD | NEW |