| 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 |