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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 for (size_t i = 0; i < instr->OutputCount(); i++) { | 82 for (size_t i = 0; i < instr->OutputCount(); i++) { |
83 auto output = instr->OutputAt(i); | 83 auto output = instr->OutputAt(i); |
84 if (output->IsDoubleRegister() && | 84 if (output->IsDoubleRegister() && |
85 DoubleRegisterOperand::cast(output)->index() == index) { | 85 DoubleRegisterOperand::cast(output)->index() == index) { |
86 return true; | 86 return true; |
87 } | 87 } |
88 } | 88 } |
89 return false; | 89 return false; |
90 } | 90 } |
91 | 91 |
| 92 |
| 93 // TODO(dcarney): fix frame to allow frame accesses to half size location. |
| 94 int GetByteWidth(MachineType machine_type) { |
| 95 DCHECK_EQ(RepresentationOf(machine_type), machine_type); |
| 96 switch (machine_type) { |
| 97 case kRepBit: |
| 98 case kRepWord8: |
| 99 case kRepWord16: |
| 100 case kRepWord32: |
| 101 case kRepTagged: |
| 102 return kPointerSize; |
| 103 case kRepFloat32: |
| 104 case kRepWord64: |
| 105 case kRepFloat64: |
| 106 return 8; |
| 107 default: |
| 108 UNREACHABLE(); |
| 109 return 0; |
| 110 } |
| 111 } |
| 112 |
92 } // namespace | 113 } // namespace |
93 | 114 |
94 | 115 |
95 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, | 116 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
96 void* hint, UsePositionHintType hint_type) | 117 void* hint, UsePositionHintType hint_type) |
97 : operand_(operand), hint_(hint), next_(nullptr), pos_(pos), flags_(0) { | 118 : operand_(operand), hint_(hint), next_(nullptr), pos_(pos), flags_(0) { |
98 DCHECK_IMPLIES(hint == nullptr, hint_type == UsePositionHintType::kNone); | 119 DCHECK_IMPLIES(hint == nullptr, hint_type == UsePositionHintType::kNone); |
99 bool register_beneficial = true; | 120 bool register_beneficial = true; |
100 UsePositionType type = UsePositionType::kAny; | 121 UsePositionType type = UsePositionType::kAny; |
101 if (operand_ != nullptr && operand_->IsUnallocated()) { | 122 if (operand_ != nullptr && operand_->IsUnallocated()) { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 struct LiveRange::SpillAtDefinitionList : ZoneObject { | 228 struct LiveRange::SpillAtDefinitionList : ZoneObject { |
208 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, | 229 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, |
209 SpillAtDefinitionList* next) | 230 SpillAtDefinitionList* next) |
210 : gap_index(gap_index), operand(operand), next(next) {} | 231 : gap_index(gap_index), operand(operand), next(next) {} |
211 const int gap_index; | 232 const int gap_index; |
212 InstructionOperand* const operand; | 233 InstructionOperand* const operand; |
213 SpillAtDefinitionList* const next; | 234 SpillAtDefinitionList* const next; |
214 }; | 235 }; |
215 | 236 |
216 | 237 |
217 LiveRange::LiveRange(int id) | 238 LiveRange::LiveRange(int id, MachineType machine_type) |
218 : id_(id), | 239 : id_(id), |
219 spill_start_index_(kMaxInt), | 240 spill_start_index_(kMaxInt), |
220 bits_(0), | 241 bits_(0), |
221 last_interval_(nullptr), | 242 last_interval_(nullptr), |
222 first_interval_(nullptr), | 243 first_interval_(nullptr), |
223 first_pos_(nullptr), | 244 first_pos_(nullptr), |
224 parent_(nullptr), | 245 parent_(nullptr), |
225 next_(nullptr), | 246 next_(nullptr), |
226 spill_operand_(nullptr), | 247 spill_operand_(nullptr), |
227 spills_at_definition_(nullptr), | 248 spills_at_definition_(nullptr), |
228 current_interval_(nullptr), | 249 current_interval_(nullptr), |
229 last_processed_use_(nullptr), | 250 last_processed_use_(nullptr), |
230 current_hint_position_(nullptr) { | 251 current_hint_position_(nullptr) { |
| 252 DCHECK(AllocatedOperand::IsSupportedMachineType(machine_type)); |
231 bits_ = SpillTypeField::encode(SpillType::kNoSpillType) | | 253 bits_ = SpillTypeField::encode(SpillType::kNoSpillType) | |
232 AssignedRegisterField::encode(kUnassignedRegister); | 254 AssignedRegisterField::encode(kUnassignedRegister) | |
| 255 MachineTypeField::encode(machine_type); |
233 } | 256 } |
234 | 257 |
235 | 258 |
236 void LiveRange::Verify() const { | 259 void LiveRange::Verify() const { |
237 // Walk the positions, verifying that each is in an interval. | 260 // Walk the positions, verifying that each is in an interval. |
238 auto interval = first_interval_; | 261 auto interval = first_interval_; |
239 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { | 262 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { |
240 CHECK(Start() <= pos->pos()); | 263 CHECK(Start() <= pos->pos()); |
241 CHECK(pos->pos() <= End()); | 264 CHECK(pos->pos() <= End()); |
242 CHECK(interval != nullptr); | 265 CHECK(interval != nullptr); |
(...skipping 18 matching lines...) Expand all Loading... |
261 | 284 |
262 | 285 |
263 void LiveRange::Spill() { | 286 void LiveRange::Spill() { |
264 DCHECK(!spilled()); | 287 DCHECK(!spilled()); |
265 DCHECK(!TopLevel()->HasNoSpillType()); | 288 DCHECK(!TopLevel()->HasNoSpillType()); |
266 set_spilled(true); | 289 set_spilled(true); |
267 bits_ = AssignedRegisterField::update(bits_, kUnassignedRegister); | 290 bits_ = AssignedRegisterField::update(bits_, kUnassignedRegister); |
268 } | 291 } |
269 | 292 |
270 | 293 |
| 294 RegisterKind LiveRange::kind() const { |
| 295 switch (RepresentationOf(machine_type())) { |
| 296 case kRepFloat32: |
| 297 case kRepFloat64: |
| 298 return DOUBLE_REGISTERS; |
| 299 default: |
| 300 break; |
| 301 } |
| 302 return GENERAL_REGISTERS; |
| 303 } |
| 304 |
| 305 |
271 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, | 306 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, |
272 InstructionOperand* operand) { | 307 InstructionOperand* operand) { |
273 DCHECK(HasNoSpillType()); | 308 DCHECK(HasNoSpillType()); |
274 spills_at_definition_ = new (zone) | 309 spills_at_definition_ = new (zone) |
275 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); | 310 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); |
276 } | 311 } |
277 | 312 |
278 | 313 |
279 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, | 314 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
280 InstructionOperand* op, | 315 const InstructionOperand& op, |
281 bool might_be_duplicated) { | 316 bool might_be_duplicated) { |
282 DCHECK_IMPLIES(op->IsConstant(), spills_at_definition_ == nullptr); | 317 DCHECK_IMPLIES(op.IsConstant(), spills_at_definition_ == nullptr); |
283 DCHECK(!IsChild()); | 318 DCHECK(!IsChild()); |
284 auto zone = sequence->zone(); | 319 auto zone = sequence->zone(); |
285 for (auto to_spill = spills_at_definition_; to_spill != nullptr; | 320 for (auto to_spill = spills_at_definition_; to_spill != nullptr; |
286 to_spill = to_spill->next) { | 321 to_spill = to_spill->next) { |
287 auto instr = sequence->InstructionAt(to_spill->gap_index); | 322 auto instr = sequence->InstructionAt(to_spill->gap_index); |
288 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); | 323 auto move = instr->GetOrCreateParallelMove(Instruction::START, zone); |
289 // Skip insertion if it's possible that the move exists already as a | 324 // Skip insertion if it's possible that the move exists already as a |
290 // constraint move from a fixed output register to a slot. | 325 // constraint move from a fixed output register to a slot. |
291 if (might_be_duplicated) { | 326 if (might_be_duplicated) { |
292 bool found = false; | 327 bool found = false; |
293 for (auto move_op : *move) { | 328 for (auto move_op : *move) { |
294 if (move_op->IsEliminated()) continue; | 329 if (move_op->IsEliminated()) continue; |
295 if (move_op->source() == *to_spill->operand && | 330 if (move_op->source().Equals(*to_spill->operand) && |
296 move_op->destination() == *op) { | 331 move_op->destination().Equals(op)) { |
297 found = true; | 332 found = true; |
298 break; | 333 break; |
299 } | 334 } |
300 } | 335 } |
301 if (found) continue; | 336 if (found) continue; |
302 } | 337 } |
303 move->AddMove(*to_spill->operand, *op); | 338 move->AddMove(*to_spill->operand, op); |
304 } | 339 } |
305 } | 340 } |
306 | 341 |
307 | 342 |
308 UsePosition* LiveRange::FirstHintPosition(int* register_index) const { | 343 UsePosition* LiveRange::FirstHintPosition(int* register_index) const { |
309 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { | 344 for (auto pos = first_pos_; pos != nullptr; pos = pos->next()) { |
310 if (pos->HintRegister(register_index)) return pos; | 345 if (pos->HintRegister(register_index)) return pos; |
311 } | 346 } |
312 return nullptr; | 347 return nullptr; |
313 } | 348 } |
314 | 349 |
315 | 350 |
316 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 351 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
317 DCHECK(HasNoSpillType()); | 352 DCHECK(HasNoSpillType()); |
318 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); | 353 DCHECK(!operand->IsUnallocated() && !operand->IsImmediate()); |
319 set_spill_type(SpillType::kSpillOperand); | 354 set_spill_type(SpillType::kSpillOperand); |
320 spill_operand_ = operand; | 355 spill_operand_ = operand; |
321 } | 356 } |
322 | 357 |
323 | 358 |
324 void LiveRange::SetSpillRange(SpillRange* spill_range) { | 359 void LiveRange::SetSpillRange(SpillRange* spill_range) { |
325 DCHECK(HasNoSpillType() || HasSpillRange()); | 360 DCHECK(HasNoSpillType() || HasSpillRange()); |
326 DCHECK(spill_range); | 361 DCHECK(spill_range); |
327 set_spill_type(SpillType::kSpillRange); | 362 set_spill_type(SpillType::kSpillRange); |
328 spill_range_ = spill_range; | 363 spill_range_ = spill_range; |
329 } | 364 } |
330 | 365 |
331 | 366 |
332 void LiveRange::CommitSpillOperand(AllocatedOperand* operand) { | |
333 DCHECK(HasSpillRange()); | |
334 DCHECK(!IsChild()); | |
335 set_spill_type(SpillType::kSpillOperand); | |
336 spill_operand_ = operand; | |
337 } | |
338 | |
339 | |
340 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) const { | 367 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) const { |
341 UsePosition* use_pos = last_processed_use_; | 368 UsePosition* use_pos = last_processed_use_; |
342 if (use_pos == nullptr || use_pos->pos() > start) { | 369 if (use_pos == nullptr || use_pos->pos() > start) { |
343 use_pos = first_pos(); | 370 use_pos = first_pos(); |
344 } | 371 } |
345 while (use_pos != nullptr && use_pos->pos() < start) { | 372 while (use_pos != nullptr && use_pos->pos() < start) { |
346 use_pos = use_pos->next(); | 373 use_pos = use_pos->next(); |
347 } | 374 } |
348 last_processed_use_ = use_pos; | 375 last_processed_use_ = use_pos; |
349 return use_pos; | 376 return use_pos; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 if (use_pos == nullptr) return true; | 415 if (use_pos == nullptr) return true; |
389 return use_pos->pos() > pos.NextStart().End(); | 416 return use_pos->pos() > pos.NextStart().End(); |
390 } | 417 } |
391 | 418 |
392 | 419 |
393 InstructionOperand LiveRange::GetAssignedOperand() const { | 420 InstructionOperand LiveRange::GetAssignedOperand() const { |
394 if (HasRegisterAssigned()) { | 421 if (HasRegisterAssigned()) { |
395 DCHECK(!spilled()); | 422 DCHECK(!spilled()); |
396 switch (kind()) { | 423 switch (kind()) { |
397 case GENERAL_REGISTERS: | 424 case GENERAL_REGISTERS: |
398 return RegisterOperand(assigned_register()); | 425 return RegisterOperand(machine_type(), assigned_register()); |
399 case DOUBLE_REGISTERS: | 426 case DOUBLE_REGISTERS: |
400 return DoubleRegisterOperand(assigned_register()); | 427 return DoubleRegisterOperand(machine_type(), assigned_register()); |
401 default: | |
402 UNREACHABLE(); | |
403 } | 428 } |
404 } | 429 } |
405 DCHECK(spilled()); | 430 DCHECK(spilled()); |
406 DCHECK(!HasRegisterAssigned()); | 431 DCHECK(!HasRegisterAssigned()); |
407 auto op = TopLevel()->GetSpillOperand(); | 432 if (TopLevel()->HasSpillOperand()) { |
408 DCHECK(!op->IsUnallocated()); | 433 auto op = TopLevel()->GetSpillOperand(); |
409 return *op; | 434 DCHECK(!op->IsUnallocated()); |
| 435 return *op; |
| 436 } |
| 437 return TopLevel()->GetSpillRangeOperand(); |
410 } | 438 } |
411 | 439 |
412 | 440 |
| 441 AllocatedOperand LiveRange::GetSpillRangeOperand() const { |
| 442 auto spill_range = GetSpillRange(); |
| 443 int index = spill_range->assigned_slot(); |
| 444 switch (kind()) { |
| 445 case GENERAL_REGISTERS: |
| 446 return StackSlotOperand(machine_type(), index); |
| 447 case DOUBLE_REGISTERS: |
| 448 return DoubleStackSlotOperand(machine_type(), index); |
| 449 } |
| 450 UNREACHABLE(); |
| 451 return StackSlotOperand(kMachNone, 0); |
| 452 } |
| 453 |
| 454 |
413 UseInterval* LiveRange::FirstSearchIntervalForPosition( | 455 UseInterval* LiveRange::FirstSearchIntervalForPosition( |
414 LifetimePosition position) const { | 456 LifetimePosition position) const { |
415 if (current_interval_ == nullptr) return first_interval_; | 457 if (current_interval_ == nullptr) return first_interval_; |
416 if (current_interval_->start() > position) { | 458 if (current_interval_->start() > position) { |
417 current_interval_ = nullptr; | 459 current_interval_ = nullptr; |
418 return first_interval_; | 460 return first_interval_; |
419 } | 461 } |
420 return current_interval_; | 462 return current_interval_; |
421 } | 463 } |
422 | 464 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 result->first_pos_ = use_after; | 547 result->first_pos_ = use_after; |
506 | 548 |
507 // Discard cached iteration state. It might be pointing | 549 // Discard cached iteration state. It might be pointing |
508 // to the use that no longer belongs to this live range. | 550 // to the use that no longer belongs to this live range. |
509 last_processed_use_ = nullptr; | 551 last_processed_use_ = nullptr; |
510 current_interval_ = nullptr; | 552 current_interval_ = nullptr; |
511 | 553 |
512 // Link the new live range in the chain before any of the other | 554 // Link the new live range in the chain before any of the other |
513 // ranges linked from the range before the split. | 555 // ranges linked from the range before the split. |
514 result->parent_ = (parent_ == nullptr) ? this : parent_; | 556 result->parent_ = (parent_ == nullptr) ? this : parent_; |
515 result->set_kind(result->parent_->kind()); | |
516 result->next_ = next_; | 557 result->next_ = next_; |
517 next_ = result; | 558 next_ = result; |
518 | 559 |
519 #ifdef DEBUG | 560 #ifdef DEBUG |
520 Verify(); | 561 Verify(); |
521 result->Verify(); | 562 result->Verify(); |
522 #endif | 563 #endif |
523 } | 564 } |
524 | 565 |
525 | 566 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 prev->set_next(use_pos); | 660 prev->set_next(use_pos); |
620 } | 661 } |
621 | 662 |
622 if (prev_hint == nullptr && use_pos->HasHint()) { | 663 if (prev_hint == nullptr && use_pos->HasHint()) { |
623 current_hint_position_ = use_pos; | 664 current_hint_position_ = use_pos; |
624 } | 665 } |
625 } | 666 } |
626 | 667 |
627 | 668 |
628 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, | 669 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, |
629 InstructionOperand* spill_op) { | 670 const InstructionOperand& spill_op) { |
630 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { | 671 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
631 DCHECK(Start() <= pos->pos() && pos->pos() <= End()); | 672 DCHECK(Start() <= pos->pos() && pos->pos() <= End()); |
632 if (!pos->HasOperand()) continue; | 673 if (!pos->HasOperand()) continue; |
633 switch (pos->type()) { | 674 switch (pos->type()) { |
634 case UsePositionType::kRequiresSlot: | 675 case UsePositionType::kRequiresSlot: |
635 if (spill_op != nullptr) { | 676 DCHECK(spill_op.IsStackSlot() || spill_op.IsDoubleStackSlot()); |
636 InstructionOperand::ReplaceWith(pos->operand(), spill_op); | 677 InstructionOperand::ReplaceWith(pos->operand(), &spill_op); |
637 } | |
638 break; | 678 break; |
639 case UsePositionType::kRequiresRegister: | 679 case UsePositionType::kRequiresRegister: |
640 DCHECK(op.IsRegister() || op.IsDoubleRegister()); | 680 DCHECK(op.IsRegister() || op.IsDoubleRegister()); |
641 // Fall through. | 681 // Fall through. |
642 case UsePositionType::kAny: | 682 case UsePositionType::kAny: |
643 InstructionOperand::ReplaceWith(pos->operand(), &op); | 683 InstructionOperand::ReplaceWith(pos->operand(), &op); |
644 break; | 684 break; |
645 } | 685 } |
646 } | 686 } |
647 } | 687 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 if (interval2->end() > interval1->start()) { | 759 if (interval2->end() > interval1->start()) { |
720 return true; | 760 return true; |
721 } | 761 } |
722 interval2 = interval2->next(); | 762 interval2 = interval2->next(); |
723 } | 763 } |
724 } | 764 } |
725 return false; | 765 return false; |
726 } | 766 } |
727 | 767 |
728 | 768 |
729 SpillRange::SpillRange(LiveRange* parent, Zone* zone) : live_ranges_(zone) { | 769 SpillRange::SpillRange(LiveRange* parent, Zone* zone) |
| 770 : live_ranges_(zone), assigned_slot_(kUnassignedSlot) { |
730 DCHECK(!parent->IsChild()); | 771 DCHECK(!parent->IsChild()); |
731 UseInterval* result = nullptr; | 772 UseInterval* result = nullptr; |
732 UseInterval* node = nullptr; | 773 UseInterval* node = nullptr; |
733 // Copy the intervals for all ranges. | 774 // Copy the intervals for all ranges. |
734 for (auto range = parent; range != nullptr; range = range->next()) { | 775 for (auto range = parent; range != nullptr; range = range->next()) { |
735 auto src = range->first_interval(); | 776 auto src = range->first_interval(); |
736 while (src != nullptr) { | 777 while (src != nullptr) { |
737 auto new_node = new (zone) UseInterval(src->start(), src->end()); | 778 auto new_node = new (zone) UseInterval(src->start(), src->end()); |
738 if (result == nullptr) { | 779 if (result == nullptr) { |
739 result = new_node; | 780 result = new_node; |
740 } else { | 781 } else { |
741 node->set_next(new_node); | 782 node->set_next(new_node); |
742 } | 783 } |
743 node = new_node; | 784 node = new_node; |
744 src = src->next(); | 785 src = src->next(); |
745 } | 786 } |
746 } | 787 } |
747 use_interval_ = result; | 788 use_interval_ = result; |
748 live_ranges().push_back(parent); | 789 live_ranges().push_back(parent); |
749 end_position_ = node->end(); | 790 end_position_ = node->end(); |
750 DCHECK(!parent->HasSpillRange()); | 791 DCHECK(!parent->HasSpillRange()); |
751 parent->SetSpillRange(this); | 792 parent->SetSpillRange(this); |
752 } | 793 } |
753 | 794 |
754 | 795 |
| 796 int SpillRange::ByteWidth() const { |
| 797 return GetByteWidth(live_ranges_[0]->machine_type()); |
| 798 } |
| 799 |
| 800 |
755 bool SpillRange::IsIntersectingWith(SpillRange* other) const { | 801 bool SpillRange::IsIntersectingWith(SpillRange* other) const { |
756 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || | 802 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || |
757 this->End() <= other->use_interval_->start() || | 803 this->End() <= other->use_interval_->start() || |
758 other->End() <= this->use_interval_->start()) { | 804 other->End() <= this->use_interval_->start()) { |
759 return false; | 805 return false; |
760 } | 806 } |
761 return AreUseIntervalsIntersecting(use_interval_, other->use_interval_); | 807 return AreUseIntervalsIntersecting(use_interval_, other->use_interval_); |
762 } | 808 } |
763 | 809 |
764 | 810 |
765 bool SpillRange::TryMerge(SpillRange* other) { | 811 bool SpillRange::TryMerge(SpillRange* other) { |
766 if (kind() != other->kind() || IsIntersectingWith(other)) return false; | 812 // TODO(dcarney): byte widths should be compared here not kinds. |
| 813 if (live_ranges_[0]->kind() != other->live_ranges_[0]->kind() || |
| 814 IsIntersectingWith(other)) { |
| 815 return false; |
| 816 } |
767 | 817 |
768 auto max = LifetimePosition::MaxPosition(); | 818 auto max = LifetimePosition::MaxPosition(); |
769 if (End() < other->End() && other->End() != max) { | 819 if (End() < other->End() && other->End() != max) { |
770 end_position_ = other->End(); | 820 end_position_ = other->End(); |
771 } | 821 } |
772 other->end_position_ = max; | 822 other->end_position_ = max; |
773 | 823 |
774 MergeDisjointIntervals(other->use_interval_); | 824 MergeDisjointIntervals(other->use_interval_); |
775 other->use_interval_ = nullptr; | 825 other->use_interval_ = nullptr; |
776 | 826 |
777 for (auto range : other->live_ranges()) { | 827 for (auto range : other->live_ranges()) { |
778 DCHECK(range->GetSpillRange() == other); | 828 DCHECK(range->GetSpillRange() == other); |
779 range->SetSpillRange(this); | 829 range->SetSpillRange(this); |
780 } | 830 } |
781 | 831 |
782 live_ranges().insert(live_ranges().end(), other->live_ranges().begin(), | 832 live_ranges().insert(live_ranges().end(), other->live_ranges().begin(), |
783 other->live_ranges().end()); | 833 other->live_ranges().end()); |
784 other->live_ranges().clear(); | 834 other->live_ranges().clear(); |
785 | 835 |
786 return true; | 836 return true; |
787 } | 837 } |
788 | 838 |
789 | 839 |
790 void SpillRange::SetOperand(AllocatedOperand* op) { | |
791 for (auto range : live_ranges()) { | |
792 DCHECK(range->GetSpillRange() == this); | |
793 range->CommitSpillOperand(op); | |
794 } | |
795 } | |
796 | |
797 | |
798 void SpillRange::MergeDisjointIntervals(UseInterval* other) { | 840 void SpillRange::MergeDisjointIntervals(UseInterval* other) { |
799 UseInterval* tail = nullptr; | 841 UseInterval* tail = nullptr; |
800 auto current = use_interval_; | 842 auto current = use_interval_; |
801 while (other != nullptr) { | 843 while (other != nullptr) { |
802 // Make sure the 'current' list starts first | 844 // Make sure the 'current' list starts first |
803 if (current == nullptr || current->start() > other->start()) { | 845 if (current == nullptr || current->start() > other->start()) { |
804 std::swap(current, other); | 846 std::swap(current, other); |
805 } | 847 } |
806 // Check disjointness | 848 // Check disjointness |
807 DCHECK(other == nullptr || current->end() <= other->start()); | 849 DCHECK(other == nullptr || current->end() <= other->start()); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 phi_map_(allocation_zone()), | 896 phi_map_(allocation_zone()), |
855 live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), | 897 live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), |
856 live_ranges_(code->VirtualRegisterCount() * 2, nullptr, | 898 live_ranges_(code->VirtualRegisterCount() * 2, nullptr, |
857 allocation_zone()), | 899 allocation_zone()), |
858 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, | 900 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, |
859 allocation_zone()), | 901 allocation_zone()), |
860 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, | 902 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, |
861 allocation_zone()), | 903 allocation_zone()), |
862 spill_ranges_(allocation_zone()), | 904 spill_ranges_(allocation_zone()), |
863 assigned_registers_(nullptr), | 905 assigned_registers_(nullptr), |
864 assigned_double_registers_(nullptr) { | 906 assigned_double_registers_(nullptr), |
| 907 virtual_register_count_(code->VirtualRegisterCount()) { |
865 DCHECK(this->config()->num_general_registers() <= | 908 DCHECK(this->config()->num_general_registers() <= |
866 RegisterConfiguration::kMaxGeneralRegisters); | 909 RegisterConfiguration::kMaxGeneralRegisters); |
867 DCHECK(this->config()->num_double_registers() <= | 910 DCHECK(this->config()->num_double_registers() <= |
868 RegisterConfiguration::kMaxDoubleRegisters); | 911 RegisterConfiguration::kMaxDoubleRegisters); |
869 spill_ranges().reserve(8); | 912 spill_ranges().reserve(8); |
870 assigned_registers_ = new (code_zone()) | 913 assigned_registers_ = new (code_zone()) |
871 BitVector(this->config()->num_general_registers(), code_zone()); | 914 BitVector(this->config()->num_general_registers(), code_zone()); |
872 assigned_double_registers_ = new (code_zone()) | 915 assigned_double_registers_ = new (code_zone()) |
873 BitVector(this->config()->num_aliased_double_registers(), code_zone()); | 916 BitVector(this->config()->num_aliased_double_registers(), code_zone()); |
874 this->frame()->SetAllocatedRegisters(assigned_registers_); | 917 this->frame()->SetAllocatedRegisters(assigned_registers_); |
875 this->frame()->SetAllocatedDoubleRegisters(assigned_double_registers_); | 918 this->frame()->SetAllocatedDoubleRegisters(assigned_double_registers_); |
876 } | 919 } |
877 | 920 |
878 | 921 |
879 LiveRange* RegisterAllocationData::LiveRangeFor(int index) { | |
880 if (index >= static_cast<int>(live_ranges().size())) { | |
881 live_ranges().resize(index + 1, nullptr); | |
882 } | |
883 auto result = live_ranges()[index]; | |
884 if (result == nullptr) { | |
885 result = NewLiveRange(index); | |
886 live_ranges()[index] = result; | |
887 } | |
888 return result; | |
889 } | |
890 | |
891 | |
892 MoveOperands* RegisterAllocationData::AddGapMove( | 922 MoveOperands* RegisterAllocationData::AddGapMove( |
893 int index, Instruction::GapPosition position, | 923 int index, Instruction::GapPosition position, |
894 const InstructionOperand& from, const InstructionOperand& to) { | 924 const InstructionOperand& from, const InstructionOperand& to) { |
895 auto instr = code()->InstructionAt(index); | 925 auto instr = code()->InstructionAt(index); |
896 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); | 926 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); |
897 return moves->AddMove(from, to); | 927 return moves->AddMove(from, to); |
898 } | 928 } |
899 | 929 |
900 | 930 |
901 LiveRange* RegisterAllocationData::NewLiveRange(int index) { | 931 MachineType RegisterAllocationData::MachineTypeFor(int virtual_register) { |
902 return new (allocation_zone()) LiveRange(index); | 932 DCHECK_LT(virtual_register, code()->VirtualRegisterCount()); |
| 933 return code()->GetRepresentation(virtual_register); |
903 } | 934 } |
904 | 935 |
905 | 936 |
| 937 LiveRange* RegisterAllocationData::LiveRangeFor(int index) { |
| 938 if (index >= static_cast<int>(live_ranges().size())) { |
| 939 live_ranges().resize(index + 1, nullptr); |
| 940 } |
| 941 auto result = live_ranges()[index]; |
| 942 if (result == nullptr) { |
| 943 result = NewLiveRange(index, MachineTypeFor(index)); |
| 944 live_ranges()[index] = result; |
| 945 } |
| 946 return result; |
| 947 } |
| 948 |
| 949 |
| 950 LiveRange* RegisterAllocationData::NewLiveRange(int index, |
| 951 MachineType machine_type) { |
| 952 return new (allocation_zone()) LiveRange(index, machine_type); |
| 953 } |
| 954 |
| 955 |
| 956 LiveRange* RegisterAllocationData::NewChildRangeFor(LiveRange* range) { |
| 957 int vreg = virtual_register_count_++; |
| 958 if (vreg >= static_cast<int>(live_ranges().size())) { |
| 959 live_ranges().resize(vreg + 1, nullptr); |
| 960 } |
| 961 auto child = new (allocation_zone()) LiveRange(vreg, range->machine_type()); |
| 962 DCHECK_NULL(live_ranges()[vreg]); |
| 963 live_ranges()[vreg] = child; |
| 964 return child; |
| 965 } |
| 966 |
| 967 |
906 RegisterAllocationData::PhiMapValue* RegisterAllocationData::InitializePhiMap( | 968 RegisterAllocationData::PhiMapValue* RegisterAllocationData::InitializePhiMap( |
907 const InstructionBlock* block, PhiInstruction* phi) { | 969 const InstructionBlock* block, PhiInstruction* phi) { |
908 auto map_value = new (allocation_zone()) | 970 auto map_value = new (allocation_zone()) |
909 RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); | 971 RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); |
910 auto res = | 972 auto res = |
911 phi_map_.insert(std::make_pair(phi->virtual_register(), map_value)); | 973 phi_map_.insert(std::make_pair(phi->virtual_register(), map_value)); |
912 DCHECK(res.second); | 974 DCHECK(res.second); |
913 USE(res); | 975 USE(res); |
914 return map_value; | 976 return map_value; |
915 } | 977 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
965 | 1027 |
966 ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) | 1028 ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) |
967 : data_(data) {} | 1029 : data_(data) {} |
968 | 1030 |
969 | 1031 |
970 InstructionOperand* ConstraintBuilder::AllocateFixed( | 1032 InstructionOperand* ConstraintBuilder::AllocateFixed( |
971 UnallocatedOperand* operand, int pos, bool is_tagged) { | 1033 UnallocatedOperand* operand, int pos, bool is_tagged) { |
972 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); | 1034 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); |
973 DCHECK(operand->HasFixedPolicy()); | 1035 DCHECK(operand->HasFixedPolicy()); |
974 InstructionOperand allocated; | 1036 InstructionOperand allocated; |
| 1037 MachineType machine_type = InstructionSequence::DefaultRepresentation(); |
| 1038 int virtual_register = operand->virtual_register(); |
| 1039 if (virtual_register != InstructionOperand::kInvalidVirtualRegister) { |
| 1040 machine_type = data()->MachineTypeFor(virtual_register); |
| 1041 } |
975 if (operand->HasFixedSlotPolicy()) { | 1042 if (operand->HasFixedSlotPolicy()) { |
976 allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, | 1043 allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, machine_type, |
977 operand->fixed_slot_index()); | 1044 operand->fixed_slot_index()); |
978 } else if (operand->HasFixedRegisterPolicy()) { | 1045 } else if (operand->HasFixedRegisterPolicy()) { |
979 allocated = AllocatedOperand(AllocatedOperand::REGISTER, | 1046 allocated = AllocatedOperand(AllocatedOperand::REGISTER, machine_type, |
980 operand->fixed_register_index()); | 1047 operand->fixed_register_index()); |
981 } else if (operand->HasFixedDoubleRegisterPolicy()) { | 1048 } else if (operand->HasFixedDoubleRegisterPolicy()) { |
| 1049 DCHECK_NE(InstructionOperand::kInvalidVirtualRegister, virtual_register); |
982 allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER, | 1050 allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER, |
983 operand->fixed_register_index()); | 1051 machine_type, operand->fixed_register_index()); |
984 } else { | 1052 } else { |
985 UNREACHABLE(); | 1053 UNREACHABLE(); |
986 } | 1054 } |
987 InstructionOperand::ReplaceWith(operand, &allocated); | 1055 InstructionOperand::ReplaceWith(operand, &allocated); |
988 if (is_tagged) { | 1056 if (is_tagged) { |
989 TRACE("Fixed reg is tagged at %d\n", pos); | 1057 TRACE("Fixed reg is tagged at %d\n", pos); |
990 auto instr = InstructionAt(pos); | 1058 auto instr = InstructionAt(pos); |
991 if (instr->HasReferenceMap()) { | 1059 if (instr->HasReferenceMap()) { |
992 instr->reference_map()->RecordReference(*operand); | 1060 instr->reference_map()->RecordReference(*operand); |
993 } | 1061 } |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1241 | 1309 |
1242 int LiveRangeBuilder::FixedDoubleLiveRangeID(int index) { | 1310 int LiveRangeBuilder::FixedDoubleLiveRangeID(int index) { |
1243 return -index - 1 - config()->num_general_registers(); | 1311 return -index - 1 - config()->num_general_registers(); |
1244 } | 1312 } |
1245 | 1313 |
1246 | 1314 |
1247 LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { | 1315 LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { |
1248 DCHECK(index < config()->num_general_registers()); | 1316 DCHECK(index < config()->num_general_registers()); |
1249 auto result = data()->fixed_live_ranges()[index]; | 1317 auto result = data()->fixed_live_ranges()[index]; |
1250 if (result == nullptr) { | 1318 if (result == nullptr) { |
1251 result = data()->NewLiveRange(FixedLiveRangeID(index)); | 1319 result = data()->NewLiveRange(FixedLiveRangeID(index), |
| 1320 InstructionSequence::DefaultRepresentation()); |
1252 DCHECK(result->IsFixed()); | 1321 DCHECK(result->IsFixed()); |
1253 result->set_kind(GENERAL_REGISTERS); | |
1254 result->set_assigned_register(index); | 1322 result->set_assigned_register(index); |
1255 data()->MarkAllocated(GENERAL_REGISTERS, index); | 1323 data()->MarkAllocated(GENERAL_REGISTERS, index); |
1256 data()->fixed_live_ranges()[index] = result; | 1324 data()->fixed_live_ranges()[index] = result; |
1257 } | 1325 } |
1258 return result; | 1326 return result; |
1259 } | 1327 } |
1260 | 1328 |
1261 | 1329 |
1262 LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { | 1330 LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { |
1263 DCHECK(index < config()->num_aliased_double_registers()); | 1331 DCHECK(index < config()->num_aliased_double_registers()); |
1264 auto result = data()->fixed_double_live_ranges()[index]; | 1332 auto result = data()->fixed_double_live_ranges()[index]; |
1265 if (result == nullptr) { | 1333 if (result == nullptr) { |
1266 result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); | 1334 result = data()->NewLiveRange(FixedDoubleLiveRangeID(index), kRepFloat64); |
1267 DCHECK(result->IsFixed()); | 1335 DCHECK(result->IsFixed()); |
1268 result->set_kind(DOUBLE_REGISTERS); | |
1269 result->set_assigned_register(index); | 1336 result->set_assigned_register(index); |
1270 data()->MarkAllocated(DOUBLE_REGISTERS, index); | 1337 data()->MarkAllocated(DOUBLE_REGISTERS, index); |
1271 data()->fixed_double_live_ranges()[index] = result; | 1338 data()->fixed_double_live_ranges()[index] = result; |
1272 } | 1339 } |
1273 return result; | 1340 return result; |
1274 } | 1341 } |
1275 | 1342 |
1276 | 1343 |
1277 LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { | 1344 LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { |
1278 if (operand->IsUnallocated()) { | 1345 if (operand->IsUnallocated()) { |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1558 // All phi output operands are killed by this block. | 1625 // All phi output operands are killed by this block. |
1559 ProcessPhis(block, live); | 1626 ProcessPhis(block, live); |
1560 // Now live is live_in for this block except not including values live | 1627 // Now live is live_in for this block except not including values live |
1561 // out on backward successor edges. | 1628 // out on backward successor edges. |
1562 if (block->IsLoopHeader()) ProcessLoopHeader(block, live); | 1629 if (block->IsLoopHeader()) ProcessLoopHeader(block, live); |
1563 live_in_sets()[block_id] = live; | 1630 live_in_sets()[block_id] = live; |
1564 } | 1631 } |
1565 // Postprocess the ranges. | 1632 // Postprocess the ranges. |
1566 for (auto range : data()->live_ranges()) { | 1633 for (auto range : data()->live_ranges()) { |
1567 if (range == nullptr) continue; | 1634 if (range == nullptr) continue; |
1568 range->set_kind(RequiredRegisterKind(range->id())); | |
1569 // Give slots to all ranges with a non fixed slot use. | 1635 // Give slots to all ranges with a non fixed slot use. |
1570 if (range->has_slot_use() && range->HasNoSpillType()) { | 1636 if (range->has_slot_use() && range->HasNoSpillType()) { |
1571 data()->AssignSpillRangeToLiveRange(range); | 1637 data()->AssignSpillRangeToLiveRange(range); |
1572 } | 1638 } |
1573 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1639 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
1574 // live ranges, every use requires the constant to be in a register. | 1640 // live ranges, every use requires the constant to be in a register. |
1575 // Without this hack, all uses with "any" policy would get the constant | 1641 // Without this hack, all uses with "any" policy would get the constant |
1576 // operand assigned. | 1642 // operand assigned. |
1577 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { | 1643 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { |
1578 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) { | 1644 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next()) { |
(...skipping 24 matching lines...) Expand all Loading... |
1603 | 1669 |
1604 void LiveRangeBuilder::ResolvePhiHint(InstructionOperand* operand, | 1670 void LiveRangeBuilder::ResolvePhiHint(InstructionOperand* operand, |
1605 UsePosition* use_pos) { | 1671 UsePosition* use_pos) { |
1606 auto it = phi_hints_.find(operand); | 1672 auto it = phi_hints_.find(operand); |
1607 if (it == phi_hints_.end()) return; | 1673 if (it == phi_hints_.end()) return; |
1608 DCHECK(!it->second->IsResolved()); | 1674 DCHECK(!it->second->IsResolved()); |
1609 it->second->ResolveHint(use_pos); | 1675 it->second->ResolveHint(use_pos); |
1610 } | 1676 } |
1611 | 1677 |
1612 | 1678 |
1613 RegisterKind LiveRangeBuilder::RequiredRegisterKind( | |
1614 int virtual_register) const { | |
1615 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS | |
1616 : GENERAL_REGISTERS; | |
1617 } | |
1618 | |
1619 | |
1620 void LiveRangeBuilder::Verify() const { | 1679 void LiveRangeBuilder::Verify() const { |
1621 for (auto& hint : phi_hints_) { | 1680 for (auto& hint : phi_hints_) { |
1622 CHECK(hint.second->IsResolved()); | 1681 CHECK(hint.second->IsResolved()); |
1623 } | 1682 } |
1624 for (auto current : data()->live_ranges()) { | 1683 for (auto current : data()->live_ranges()) { |
1625 if (current != nullptr) current->Verify(); | 1684 if (current != nullptr) current->Verify(); |
1626 } | 1685 } |
1627 } | 1686 } |
1628 | 1687 |
1629 | 1688 |
(...skipping 10 matching lines...) Expand all Loading... |
1640 TRACE("Splitting live range %d at %d\n", range->id(), pos.value()); | 1699 TRACE("Splitting live range %d at %d\n", range->id(), pos.value()); |
1641 | 1700 |
1642 if (pos <= range->Start()) return range; | 1701 if (pos <= range->Start()) return range; |
1643 | 1702 |
1644 // We can't properly connect liveranges if splitting occurred at the end | 1703 // We can't properly connect liveranges if splitting occurred at the end |
1645 // a block. | 1704 // a block. |
1646 DCHECK(pos.IsStart() || pos.IsGapPosition() || | 1705 DCHECK(pos.IsStart() || pos.IsGapPosition() || |
1647 (GetInstructionBlock(code(), pos)->last_instruction_index() != | 1706 (GetInstructionBlock(code(), pos)->last_instruction_index() != |
1648 pos.ToInstructionIndex())); | 1707 pos.ToInstructionIndex())); |
1649 | 1708 |
1650 int vreg = code()->NextVirtualRegister(); | 1709 auto result = data()->NewChildRangeFor(range); |
1651 auto result = LiveRangeFor(vreg); | |
1652 range->SplitAt(pos, result, allocation_zone()); | 1710 range->SplitAt(pos, result, allocation_zone()); |
1653 return result; | 1711 return result; |
1654 } | 1712 } |
1655 | 1713 |
1656 | 1714 |
1657 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, | 1715 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, |
1658 LifetimePosition start, | 1716 LifetimePosition start, |
1659 LifetimePosition end) { | 1717 LifetimePosition end) { |
1660 DCHECK(!range->IsFixed()); | 1718 DCHECK(!range->IsFixed()); |
1661 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), | 1719 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), |
(...skipping 983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2645 auto other = spill_ranges[j]; | 2703 auto other = spill_ranges[j]; |
2646 if (!other->IsEmpty()) { | 2704 if (!other->IsEmpty()) { |
2647 range->TryMerge(other); | 2705 range->TryMerge(other); |
2648 } | 2706 } |
2649 } | 2707 } |
2650 } | 2708 } |
2651 // Allocate slots for the merged spill ranges. | 2709 // Allocate slots for the merged spill ranges. |
2652 for (auto range : spill_ranges) { | 2710 for (auto range : spill_ranges) { |
2653 if (range->IsEmpty()) continue; | 2711 if (range->IsEmpty()) continue; |
2654 // Allocate a new operand referring to the spill slot. | 2712 // Allocate a new operand referring to the spill slot. |
2655 auto kind = range->kind(); | 2713 int byte_width = range->ByteWidth(); |
2656 int index = data()->frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 2714 int index = data()->frame()->AllocateSpillSlot(byte_width); |
2657 auto op_kind = kind == DOUBLE_REGISTERS | 2715 range->set_assigned_slot(index); |
2658 ? AllocatedOperand::DOUBLE_STACK_SLOT | |
2659 : AllocatedOperand::STACK_SLOT; | |
2660 auto op = AllocatedOperand::New(data()->code_zone(), op_kind, index); | |
2661 range->SetOperand(op); | |
2662 } | 2716 } |
2663 } | 2717 } |
2664 | 2718 |
2665 | 2719 |
2666 void OperandAssigner::CommitAssignment() { | 2720 void OperandAssigner::CommitAssignment() { |
2667 for (auto range : data()->live_ranges()) { | 2721 for (auto range : data()->live_ranges()) { |
2668 if (range == nullptr || range->IsEmpty()) continue; | 2722 if (range == nullptr || range->IsEmpty()) continue; |
2669 InstructionOperand* spill_operand = nullptr; | 2723 InstructionOperand spill_operand; |
2670 if (!range->TopLevel()->HasNoSpillType()) { | 2724 if (range->TopLevel()->HasSpillOperand()) { |
2671 spill_operand = range->TopLevel()->GetSpillOperand(); | 2725 spill_operand = *range->TopLevel()->GetSpillOperand(); |
| 2726 } else if (range->TopLevel()->HasSpillRange()) { |
| 2727 spill_operand = range->TopLevel()->GetSpillRangeOperand(); |
2672 } | 2728 } |
2673 auto assigned = range->GetAssignedOperand(); | 2729 auto assigned = range->GetAssignedOperand(); |
2674 range->ConvertUsesToOperand(assigned, spill_operand); | 2730 range->ConvertUsesToOperand(assigned, spill_operand); |
2675 if (range->is_phi()) { | 2731 if (range->is_phi()) { |
2676 data()->GetPhiMapValueFor(range->id())->CommitAssignment(assigned); | 2732 data()->GetPhiMapValueFor(range->id())->CommitAssignment(assigned); |
2677 } | 2733 } |
2678 if (!range->IsChild() && spill_operand != nullptr) { | 2734 if (!range->IsChild() && !spill_operand.IsInvalid()) { |
2679 range->CommitSpillsAtDefinition(data()->code(), spill_operand, | 2735 range->CommitSpillsAtDefinition(data()->code(), spill_operand, |
2680 range->has_slot_use()); | 2736 range->has_slot_use()); |
2681 } | 2737 } |
2682 } | 2738 } |
2683 } | 2739 } |
2684 | 2740 |
2685 | 2741 |
2686 ReferenceMapPopulator::ReferenceMapPopulator(RegisterAllocationData* data) | 2742 ReferenceMapPopulator::ReferenceMapPopulator(RegisterAllocationData* data) |
2687 : data_(data) {} | 2743 : data_(data) {} |
2688 | 2744 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2749 auto safe_point_pos = | 2805 auto safe_point_pos = |
2750 LifetimePosition::InstructionFromInstructionIndex(safe_point); | 2806 LifetimePosition::InstructionFromInstructionIndex(safe_point); |
2751 auto cur = range; | 2807 auto cur = range; |
2752 while (cur != nullptr && !cur->Covers(safe_point_pos)) { | 2808 while (cur != nullptr && !cur->Covers(safe_point_pos)) { |
2753 cur = cur->next(); | 2809 cur = cur->next(); |
2754 } | 2810 } |
2755 if (cur == nullptr) continue; | 2811 if (cur == nullptr) continue; |
2756 | 2812 |
2757 // Check if the live range is spilled and the safe point is after | 2813 // Check if the live range is spilled and the safe point is after |
2758 // the spill position. | 2814 // the spill position. |
2759 if (range->HasSpillOperand() && | 2815 if (((range->HasSpillOperand() && |
2760 safe_point >= range->spill_start_index() && | 2816 !range->GetSpillOperand()->IsConstant()) || |
2761 !range->GetSpillOperand()->IsConstant()) { | 2817 range->HasSpillRange()) && |
| 2818 safe_point >= range->spill_start_index()) { |
2762 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", | 2819 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", |
2763 range->id(), range->spill_start_index(), safe_point); | 2820 range->id(), range->spill_start_index(), safe_point); |
2764 map->RecordReference(*range->GetSpillOperand()); | 2821 InstructionOperand operand; |
| 2822 if (range->HasSpillOperand()) { |
| 2823 operand = *range->GetSpillOperand(); |
| 2824 } else { |
| 2825 operand = range->GetSpillRangeOperand(); |
| 2826 } |
| 2827 DCHECK(operand.IsStackSlot()); |
| 2828 DCHECK_EQ(kRepTagged, AllocatedOperand::cast(operand).machine_type()); |
| 2829 map->RecordReference(operand); |
2765 } | 2830 } |
2766 | 2831 |
2767 if (!cur->spilled()) { | 2832 if (!cur->spilled()) { |
2768 TRACE( | 2833 TRACE( |
2769 "Pointer in register for range %d (start at %d) " | 2834 "Pointer in register for range %d (start at %d) " |
2770 "at safe point %d\n", | 2835 "at safe point %d\n", |
2771 cur->id(), cur->Start().value(), safe_point); | 2836 cur->id(), cur->Start().value(), safe_point); |
2772 auto operand = cur->GetAssignedOperand(); | 2837 auto operand = cur->GetAssignedOperand(); |
2773 DCHECK(!operand.IsStackSlot()); | 2838 DCHECK(!operand.IsStackSlot()); |
| 2839 DCHECK_EQ(kRepTagged, AllocatedOperand::cast(operand).machine_type()); |
2774 map->RecordReference(operand); | 2840 map->RecordReference(operand); |
2775 } | 2841 } |
2776 } | 2842 } |
2777 } | 2843 } |
2778 } | 2844 } |
2779 | 2845 |
2780 | 2846 |
2781 namespace { | 2847 namespace { |
2782 | 2848 |
2783 class LiveRangeBound { | 2849 class LiveRangeBound { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2902 | 2968 |
2903 private: | 2969 private: |
2904 const RegisterAllocationData* const data_; | 2970 const RegisterAllocationData* const data_; |
2905 const int bounds_length_; | 2971 const int bounds_length_; |
2906 LiveRangeBoundArray* const bounds_; | 2972 LiveRangeBoundArray* const bounds_; |
2907 Zone* const zone_; | 2973 Zone* const zone_; |
2908 | 2974 |
2909 DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); | 2975 DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); |
2910 }; | 2976 }; |
2911 | 2977 |
| 2978 |
| 2979 typedef std::pair<ParallelMove*, InstructionOperand> DelayedInsertionMapKey; |
| 2980 |
| 2981 |
| 2982 struct DelayedInsertionMapCompare { |
| 2983 bool operator()(const DelayedInsertionMapKey& a, |
| 2984 const DelayedInsertionMapKey& b) const { |
| 2985 if (a.first == b.first) { |
| 2986 return a.second.Compare(b.second); |
| 2987 } |
| 2988 return a.first < b.first; |
| 2989 } |
| 2990 }; |
| 2991 |
| 2992 |
| 2993 typedef ZoneMap<DelayedInsertionMapKey, InstructionOperand, |
| 2994 DelayedInsertionMapCompare> DelayedInsertionMap; |
| 2995 |
2912 } // namespace | 2996 } // namespace |
2913 | 2997 |
2914 | 2998 |
2915 LiveRangeConnector::LiveRangeConnector(RegisterAllocationData* data) | 2999 LiveRangeConnector::LiveRangeConnector(RegisterAllocationData* data) |
2916 : data_(data) {} | 3000 : data_(data) {} |
2917 | 3001 |
2918 | 3002 |
2919 bool LiveRangeConnector::CanEagerlyResolveControlFlow( | 3003 bool LiveRangeConnector::CanEagerlyResolveControlFlow( |
2920 const InstructionBlock* block) const { | 3004 const InstructionBlock* block) const { |
2921 if (block->PredecessorCount() != 1) return false; | 3005 if (block->PredecessorCount() != 1) return false; |
(...skipping 13 matching lines...) Expand all Loading... |
2935 auto* array = finder.ArrayFor(iterator.Current()); | 3019 auto* array = finder.ArrayFor(iterator.Current()); |
2936 for (auto pred : block->predecessors()) { | 3020 for (auto pred : block->predecessors()) { |
2937 FindResult result; | 3021 FindResult result; |
2938 const auto* pred_block = code()->InstructionBlockAt(pred); | 3022 const auto* pred_block = code()->InstructionBlockAt(pred); |
2939 array->Find(block, pred_block, &result); | 3023 array->Find(block, pred_block, &result); |
2940 if (result.cur_cover_ == result.pred_cover_ || | 3024 if (result.cur_cover_ == result.pred_cover_ || |
2941 result.cur_cover_->spilled()) | 3025 result.cur_cover_->spilled()) |
2942 continue; | 3026 continue; |
2943 auto pred_op = result.pred_cover_->GetAssignedOperand(); | 3027 auto pred_op = result.pred_cover_->GetAssignedOperand(); |
2944 auto cur_op = result.cur_cover_->GetAssignedOperand(); | 3028 auto cur_op = result.cur_cover_->GetAssignedOperand(); |
2945 if (pred_op == cur_op) continue; | 3029 if (pred_op.Equals(cur_op)) continue; |
2946 ResolveControlFlow(block, cur_op, pred_block, pred_op); | 3030 ResolveControlFlow(block, cur_op, pred_block, pred_op); |
2947 } | 3031 } |
2948 iterator.Advance(); | 3032 iterator.Advance(); |
2949 } | 3033 } |
2950 } | 3034 } |
2951 } | 3035 } |
2952 | 3036 |
2953 | 3037 |
2954 void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, | 3038 void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, |
2955 const InstructionOperand& cur_op, | 3039 const InstructionOperand& cur_op, |
2956 const InstructionBlock* pred, | 3040 const InstructionBlock* pred, |
2957 const InstructionOperand& pred_op) { | 3041 const InstructionOperand& pred_op) { |
2958 DCHECK(pred_op != cur_op); | 3042 DCHECK(!pred_op.Equals(cur_op)); |
2959 int gap_index; | 3043 int gap_index; |
2960 Instruction::GapPosition position; | 3044 Instruction::GapPosition position; |
2961 if (block->PredecessorCount() == 1) { | 3045 if (block->PredecessorCount() == 1) { |
2962 gap_index = block->first_instruction_index(); | 3046 gap_index = block->first_instruction_index(); |
2963 position = Instruction::START; | 3047 position = Instruction::START; |
2964 } else { | 3048 } else { |
2965 DCHECK(pred->SuccessorCount() == 1); | 3049 DCHECK(pred->SuccessorCount() == 1); |
2966 DCHECK(!code() | 3050 DCHECK(!code() |
2967 ->InstructionAt(pred->last_instruction_index()) | 3051 ->InstructionAt(pred->last_instruction_index()) |
2968 ->HasReferenceMap()); | 3052 ->HasReferenceMap()); |
2969 gap_index = pred->last_instruction_index(); | 3053 gap_index = pred->last_instruction_index(); |
2970 position = Instruction::END; | 3054 position = Instruction::END; |
2971 } | 3055 } |
2972 data()->AddGapMove(gap_index, position, pred_op, cur_op); | 3056 data()->AddGapMove(gap_index, position, pred_op, cur_op); |
2973 } | 3057 } |
2974 | 3058 |
2975 | 3059 |
2976 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { | 3060 void LiveRangeConnector::ConnectRanges(Zone* local_zone) { |
2977 ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand> | 3061 DelayedInsertionMap delayed_insertion_map(local_zone); |
2978 delayed_insertion_map(local_zone); | |
2979 for (auto first_range : data()->live_ranges()) { | 3062 for (auto first_range : data()->live_ranges()) { |
2980 if (first_range == nullptr || first_range->IsChild()) continue; | 3063 if (first_range == nullptr || first_range->IsChild()) continue; |
2981 for (auto second_range = first_range->next(); second_range != nullptr; | 3064 for (auto second_range = first_range->next(); second_range != nullptr; |
2982 first_range = second_range, second_range = second_range->next()) { | 3065 first_range = second_range, second_range = second_range->next()) { |
2983 auto pos = second_range->Start(); | 3066 auto pos = second_range->Start(); |
2984 // Add gap move if the two live ranges touch and there is no block | 3067 // Add gap move if the two live ranges touch and there is no block |
2985 // boundary. | 3068 // boundary. |
2986 if (second_range->spilled()) continue; | 3069 if (second_range->spilled()) continue; |
2987 if (first_range->End() != pos) continue; | 3070 if (first_range->End() != pos) continue; |
2988 if (IsBlockBoundary(code(), pos) && | 3071 if (IsBlockBoundary(code(), pos) && |
2989 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { | 3072 !CanEagerlyResolveControlFlow(GetInstructionBlock(code(), pos))) { |
2990 continue; | 3073 continue; |
2991 } | 3074 } |
2992 auto prev_operand = first_range->GetAssignedOperand(); | 3075 auto prev_operand = first_range->GetAssignedOperand(); |
2993 auto cur_operand = second_range->GetAssignedOperand(); | 3076 auto cur_operand = second_range->GetAssignedOperand(); |
2994 if (prev_operand == cur_operand) continue; | 3077 if (prev_operand.Equals(cur_operand)) continue; |
2995 bool delay_insertion = false; | 3078 bool delay_insertion = false; |
2996 Instruction::GapPosition gap_pos; | 3079 Instruction::GapPosition gap_pos; |
2997 int gap_index = pos.ToInstructionIndex(); | 3080 int gap_index = pos.ToInstructionIndex(); |
2998 if (pos.IsGapPosition()) { | 3081 if (pos.IsGapPosition()) { |
2999 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; | 3082 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; |
3000 } else { | 3083 } else { |
3001 if (pos.IsStart()) { | 3084 if (pos.IsStart()) { |
3002 delay_insertion = true; | 3085 delay_insertion = true; |
3003 } else { | 3086 } else { |
3004 gap_index++; | 3087 gap_index++; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3043 auto eliminate = moves->PrepareInsertAfter(move); | 3126 auto eliminate = moves->PrepareInsertAfter(move); |
3044 to_insert.push_back(move); | 3127 to_insert.push_back(move); |
3045 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 3128 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
3046 } | 3129 } |
3047 } | 3130 } |
3048 | 3131 |
3049 | 3132 |
3050 } // namespace compiler | 3133 } // namespace compiler |
3051 } // namespace internal | 3134 } // namespace internal |
3052 } // namespace v8 | 3135 } // namespace v8 |
OLD | NEW |