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