| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/linkage.h" | 5 #include "src/compiler/linkage.h" |
| 6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
| 7 #include "src/string-stream.h" | 7 #include "src/string-stream.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 next_(nullptr), | 130 next_(nullptr), |
| 131 current_interval_(nullptr), | 131 current_interval_(nullptr), |
| 132 last_processed_use_(nullptr), | 132 last_processed_use_(nullptr), |
| 133 current_hint_operand_(nullptr), | 133 current_hint_operand_(nullptr), |
| 134 spill_start_index_(kMaxInt), | 134 spill_start_index_(kMaxInt), |
| 135 spill_type_(SpillType::kNoSpillType), | 135 spill_type_(SpillType::kNoSpillType), |
| 136 spill_operand_(nullptr), | 136 spill_operand_(nullptr), |
| 137 spills_at_definition_(nullptr) {} | 137 spills_at_definition_(nullptr) {} |
| 138 | 138 |
| 139 | 139 |
| 140 void LiveRange::set_assigned_register(int reg, | 140 void LiveRange::set_assigned_register(int reg) { |
| 141 InstructionOperandCache* operand_cache) { | |
| 142 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 141 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
| 143 assigned_register_ = reg; | 142 assigned_register_ = reg; |
| 144 // TODO(dcarney): stop aliasing hint operands. | 143 // TODO(dcarney): stop aliasing hint operands. |
| 145 ConvertUsesToOperand(GetAssignedOperand(operand_cache), nullptr); | 144 ConvertUsesToOperand(GetAssignedOperand(), nullptr); |
| 146 } | 145 } |
| 147 | 146 |
| 148 | 147 |
| 149 void LiveRange::MakeSpilled() { | 148 void LiveRange::MakeSpilled() { |
| 150 DCHECK(!IsSpilled()); | 149 DCHECK(!IsSpilled()); |
| 151 DCHECK(!TopLevel()->HasNoSpillType()); | 150 DCHECK(!TopLevel()->HasNoSpillType()); |
| 152 spilled_ = true; | 151 spilled_ = true; |
| 153 assigned_register_ = kInvalidAssignment; | 152 assigned_register_ = kInvalidAssignment; |
| 154 } | 153 } |
| 155 | 154 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 | 260 |
| 262 bool LiveRange::CanBeSpilled(LifetimePosition pos) { | 261 bool LiveRange::CanBeSpilled(LifetimePosition pos) { |
| 263 // We cannot spill a live range that has a use requiring a register | 262 // We cannot spill a live range that has a use requiring a register |
| 264 // at the current or the immediate next position. | 263 // at the current or the immediate next position. |
| 265 auto use_pos = NextRegisterPosition(pos); | 264 auto use_pos = NextRegisterPosition(pos); |
| 266 if (use_pos == nullptr) return true; | 265 if (use_pos == nullptr) return true; |
| 267 return use_pos->pos().Value() > pos.NextStart().End().Value(); | 266 return use_pos->pos().Value() > pos.NextStart().End().Value(); |
| 268 } | 267 } |
| 269 | 268 |
| 270 | 269 |
| 271 InstructionOperand* LiveRange::GetAssignedOperand( | |
| 272 InstructionOperandCache* cache) const { | |
| 273 if (HasRegisterAssigned()) { | |
| 274 DCHECK(!IsSpilled()); | |
| 275 switch (Kind()) { | |
| 276 case GENERAL_REGISTERS: | |
| 277 return cache->GetRegisterOperand(assigned_register()); | |
| 278 case DOUBLE_REGISTERS: | |
| 279 return cache->GetDoubleRegisterOperand(assigned_register()); | |
| 280 default: | |
| 281 UNREACHABLE(); | |
| 282 } | |
| 283 } | |
| 284 DCHECK(IsSpilled()); | |
| 285 DCHECK(!HasRegisterAssigned()); | |
| 286 auto op = TopLevel()->GetSpillOperand(); | |
| 287 DCHECK(!op->IsUnallocated()); | |
| 288 return op; | |
| 289 } | |
| 290 | |
| 291 | |
| 292 InstructionOperand LiveRange::GetAssignedOperand() const { | 270 InstructionOperand LiveRange::GetAssignedOperand() const { |
| 293 if (HasRegisterAssigned()) { | 271 if (HasRegisterAssigned()) { |
| 294 DCHECK(!IsSpilled()); | 272 DCHECK(!IsSpilled()); |
| 295 switch (Kind()) { | 273 switch (Kind()) { |
| 296 case GENERAL_REGISTERS: | 274 case GENERAL_REGISTERS: |
| 297 return RegisterOperand(assigned_register()); | 275 return RegisterOperand(assigned_register()); |
| 298 case DOUBLE_REGISTERS: | 276 case DOUBLE_REGISTERS: |
| 299 return DoubleRegisterOperand(assigned_register()); | 277 return DoubleRegisterOperand(assigned_register()); |
| 300 default: | 278 default: |
| 301 UNREACHABLE(); | 279 UNREACHABLE(); |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 use_pos->next_ = prev->next_; | 497 use_pos->next_ = prev->next_; |
| 520 prev->next_ = use_pos; | 498 prev->next_ = use_pos; |
| 521 } | 499 } |
| 522 | 500 |
| 523 if (prev_hint == nullptr && use_pos->HasHint()) { | 501 if (prev_hint == nullptr && use_pos->HasHint()) { |
| 524 current_hint_operand_ = hint; | 502 current_hint_operand_ = hint; |
| 525 } | 503 } |
| 526 } | 504 } |
| 527 | 505 |
| 528 | 506 |
| 529 void LiveRange::ConvertUsesToOperand(InstructionOperand* op, | 507 void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, |
| 530 InstructionOperand* spill_op) { | 508 InstructionOperand* spill_op) { |
| 531 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { | 509 for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { |
| 532 DCHECK(Start().Value() <= pos->pos().Value() && | 510 DCHECK(Start().Value() <= pos->pos().Value() && |
| 533 pos->pos().Value() <= End().Value()); | 511 pos->pos().Value() <= End().Value()); |
| 534 if (!pos->HasOperand()) { | 512 if (!pos->HasOperand()) { |
| 535 continue; | 513 continue; |
| 536 } | 514 } |
| 537 switch (pos->type()) { | 515 switch (pos->type()) { |
| 538 case UsePositionType::kRequiresSlot: | 516 case UsePositionType::kRequiresSlot: |
| 539 if (spill_op != nullptr) { | 517 if (spill_op != nullptr) { |
| 540 InstructionOperand::ReplaceWith(pos->operand(), spill_op); | 518 InstructionOperand::ReplaceWith(pos->operand(), spill_op); |
| 541 } | 519 } |
| 542 break; | 520 break; |
| 543 case UsePositionType::kRequiresRegister: | 521 case UsePositionType::kRequiresRegister: |
| 544 DCHECK(op->IsRegister() || op->IsDoubleRegister()); | 522 DCHECK(op.IsRegister() || op.IsDoubleRegister()); |
| 545 // Fall through. | 523 // Fall through. |
| 546 case UsePositionType::kAny: | 524 case UsePositionType::kAny: |
| 547 InstructionOperand::ReplaceWith(pos->operand(), op); | 525 InstructionOperand::ReplaceWith(pos->operand(), &op); |
| 548 break; | 526 break; |
| 549 } | 527 } |
| 550 } | 528 } |
| 551 } | 529 } |
| 552 | 530 |
| 553 | 531 |
| 554 bool LiveRange::CanCover(LifetimePosition position) const { | 532 bool LiveRange::CanCover(LifetimePosition position) const { |
| 555 if (IsEmpty()) return false; | 533 if (IsEmpty()) return false; |
| 556 return Start().Value() <= position.Value() && | 534 return Start().Value() <= position.Value() && |
| 557 position.Value() < End().Value(); | 535 position.Value() < End().Value(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 if (a == nullptr || a->start().Value() > other->End().Value()) break; | 568 if (a == nullptr || a->start().Value() > other->End().Value()) break; |
| 591 AdvanceLastProcessedMarker(a, advance_last_processed_up_to); | 569 AdvanceLastProcessedMarker(a, advance_last_processed_up_to); |
| 592 } else { | 570 } else { |
| 593 b = b->next(); | 571 b = b->next(); |
| 594 } | 572 } |
| 595 } | 573 } |
| 596 return LifetimePosition::Invalid(); | 574 return LifetimePosition::Invalid(); |
| 597 } | 575 } |
| 598 | 576 |
| 599 | 577 |
| 600 InstructionOperandCache::InstructionOperandCache() { | |
| 601 for (size_t i = 0; i < arraysize(general_register_operands_); ++i) { | |
| 602 general_register_operands_[i] = RegisterOperand(static_cast<int>(i)); | |
| 603 } | |
| 604 for (size_t i = 0; i < arraysize(double_register_operands_); ++i) { | |
| 605 double_register_operands_[i] = DoubleRegisterOperand(static_cast<int>(i)); | |
| 606 } | |
| 607 } | |
| 608 | |
| 609 | |
| 610 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, | 578 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, |
| 611 Zone* zone, Frame* frame, | 579 Zone* zone, Frame* frame, |
| 612 InstructionSequence* code, | 580 InstructionSequence* code, |
| 613 const char* debug_name) | 581 const char* debug_name) |
| 614 : local_zone_(zone), | 582 : local_zone_(zone), |
| 615 frame_(frame), | 583 frame_(frame), |
| 616 code_(code), | 584 code_(code), |
| 617 debug_name_(debug_name), | 585 debug_name_(debug_name), |
| 618 config_(config), | 586 config_(config), |
| 619 operand_cache_(new (code_zone()) InstructionOperandCache()), | |
| 620 phi_map_(local_zone()), | 587 phi_map_(local_zone()), |
| 621 live_in_sets_(code->InstructionBlockCount(), nullptr, local_zone()), | 588 live_in_sets_(code->InstructionBlockCount(), nullptr, local_zone()), |
| 622 live_ranges_(code->VirtualRegisterCount() * 2, nullptr, local_zone()), | 589 live_ranges_(code->VirtualRegisterCount() * 2, nullptr, local_zone()), |
| 623 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, | 590 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, |
| 624 local_zone()), | 591 local_zone()), |
| 625 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, | 592 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, |
| 626 local_zone()), | 593 local_zone()), |
| 627 unhandled_live_ranges_(local_zone()), | 594 unhandled_live_ranges_(local_zone()), |
| 628 active_live_ranges_(local_zone()), | 595 active_live_ranges_(local_zone()), |
| 629 inactive_live_ranges_(local_zone()), | 596 inactive_live_ranges_(local_zone()), |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 980 : AllocatedOperand::STACK_SLOT; | 947 : AllocatedOperand::STACK_SLOT; |
| 981 auto op = AllocatedOperand::New(code_zone(), op_kind, index); | 948 auto op = AllocatedOperand::New(code_zone(), op_kind, index); |
| 982 range->SetOperand(op); | 949 range->SetOperand(op); |
| 983 } | 950 } |
| 984 } | 951 } |
| 985 | 952 |
| 986 | 953 |
| 987 void RegisterAllocator::CommitAssignment() { | 954 void RegisterAllocator::CommitAssignment() { |
| 988 for (auto range : live_ranges()) { | 955 for (auto range : live_ranges()) { |
| 989 if (range == nullptr || range->IsEmpty()) continue; | 956 if (range == nullptr || range->IsEmpty()) continue; |
| 990 auto assigned = range->GetAssignedOperand(operand_cache()); | |
| 991 InstructionOperand* spill_operand = nullptr; | 957 InstructionOperand* spill_operand = nullptr; |
| 992 if (!range->TopLevel()->HasNoSpillType()) { | 958 if (!range->TopLevel()->HasNoSpillType()) { |
| 993 spill_operand = range->TopLevel()->GetSpillOperand(); | 959 spill_operand = range->TopLevel()->GetSpillOperand(); |
| 994 } | 960 } |
| 961 auto assigned = range->GetAssignedOperand(); |
| 995 range->ConvertUsesToOperand(assigned, spill_operand); | 962 range->ConvertUsesToOperand(assigned, spill_operand); |
| 996 if (!range->IsChild() && spill_operand != nullptr) { | 963 if (!range->IsChild() && spill_operand != nullptr) { |
| 997 range->CommitSpillsAtDefinition(code(), spill_operand, | 964 range->CommitSpillsAtDefinition(code(), spill_operand, |
| 998 range->has_slot_use()); | 965 range->has_slot_use()); |
| 999 } | 966 } |
| 1000 } | 967 } |
| 1001 } | 968 } |
| 1002 | 969 |
| 1003 | 970 |
| 1004 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 971 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1456 first_range = second_range, second_range = second_range->next()) { | 1423 first_range = second_range, second_range = second_range->next()) { |
| 1457 auto pos = second_range->Start(); | 1424 auto pos = second_range->Start(); |
| 1458 // Add gap move if the two live ranges touch and there is no block | 1425 // Add gap move if the two live ranges touch and there is no block |
| 1459 // boundary. | 1426 // boundary. |
| 1460 if (second_range->IsSpilled()) continue; | 1427 if (second_range->IsSpilled()) continue; |
| 1461 if (first_range->End().Value() != pos.Value()) continue; | 1428 if (first_range->End().Value() != pos.Value()) continue; |
| 1462 if (IsBlockBoundary(pos) && | 1429 if (IsBlockBoundary(pos) && |
| 1463 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { | 1430 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { |
| 1464 continue; | 1431 continue; |
| 1465 } | 1432 } |
| 1466 auto prev_operand = first_range->GetAssignedOperand(operand_cache()); | 1433 auto prev = first_range->GetAssignedOperand(); |
| 1467 auto cur_operand = second_range->GetAssignedOperand(operand_cache()); | 1434 auto cur = second_range->GetAssignedOperand(); |
| 1468 if (prev_operand->Equals(cur_operand)) continue; | 1435 if (prev == cur) continue; |
| 1469 bool delay_insertion = false; | 1436 bool delay_insertion = false; |
| 1470 Instruction::GapPosition gap_pos; | 1437 Instruction::GapPosition gap_pos; |
| 1471 int gap_index = pos.ToInstructionIndex(); | 1438 int gap_index = pos.ToInstructionIndex(); |
| 1472 if (pos.IsGapPosition()) { | 1439 if (pos.IsGapPosition()) { |
| 1473 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; | 1440 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; |
| 1474 } else { | 1441 } else { |
| 1475 if (pos.IsStart()) { | 1442 if (pos.IsStart()) { |
| 1476 delay_insertion = true; | 1443 delay_insertion = true; |
| 1477 } else { | 1444 } else { |
| 1478 gap_index++; | 1445 gap_index++; |
| 1479 } | 1446 } |
| 1480 gap_pos = delay_insertion ? Instruction::END : Instruction::START; | 1447 gap_pos = delay_insertion ? Instruction::END : Instruction::START; |
| 1481 } | 1448 } |
| 1482 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( | 1449 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( |
| 1483 gap_pos, code_zone()); | 1450 gap_pos, code_zone()); |
| 1451 auto prev_operand = InstructionOperand::New(code_zone(), prev); |
| 1452 auto cur_operand = InstructionOperand::New(code_zone(), cur); |
| 1484 if (!delay_insertion) { | 1453 if (!delay_insertion) { |
| 1485 move->AddMove(prev_operand, cur_operand, code_zone()); | 1454 move->AddMove(prev_operand, cur_operand, code_zone()); |
| 1486 } else { | 1455 } else { |
| 1487 delayed_insertion_map.insert( | 1456 delayed_insertion_map.insert( |
| 1488 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); | 1457 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); |
| 1489 } | 1458 } |
| 1490 } | 1459 } |
| 1491 } | 1460 } |
| 1492 if (delayed_insertion_map.empty()) return; | 1461 if (delayed_insertion_map.empty()) return; |
| 1493 // Insert all the moves which should occur after the stored move. | 1462 // Insert all the moves which should occur after the stored move. |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1671 BitVector::Iterator iterator(live); | 1640 BitVector::Iterator iterator(live); |
| 1672 while (!iterator.Done()) { | 1641 while (!iterator.Done()) { |
| 1673 auto* array = finder.ArrayFor(iterator.Current()); | 1642 auto* array = finder.ArrayFor(iterator.Current()); |
| 1674 for (auto pred : block->predecessors()) { | 1643 for (auto pred : block->predecessors()) { |
| 1675 FindResult result; | 1644 FindResult result; |
| 1676 const auto* pred_block = code()->InstructionBlockAt(pred); | 1645 const auto* pred_block = code()->InstructionBlockAt(pred); |
| 1677 array->Find(block, pred_block, &result); | 1646 array->Find(block, pred_block, &result); |
| 1678 if (result.cur_cover_ == result.pred_cover_ || | 1647 if (result.cur_cover_ == result.pred_cover_ || |
| 1679 result.cur_cover_->IsSpilled()) | 1648 result.cur_cover_->IsSpilled()) |
| 1680 continue; | 1649 continue; |
| 1681 auto pred_op = result.pred_cover_->GetAssignedOperand(operand_cache()); | 1650 auto pred_op = result.pred_cover_->GetAssignedOperand(); |
| 1682 auto cur_op = result.cur_cover_->GetAssignedOperand(operand_cache()); | 1651 auto cur_op = result.cur_cover_->GetAssignedOperand(); |
| 1683 ResolveControlFlow(block, cur_op, pred_block, pred_op); | 1652 if (pred_op == cur_op) continue; |
| 1653 auto pred_ptr = InstructionOperand::New(code_zone(), pred_op); |
| 1654 auto cur_ptr = InstructionOperand::New(code_zone(), cur_op); |
| 1655 ResolveControlFlow(block, cur_ptr, pred_block, pred_ptr); |
| 1684 } | 1656 } |
| 1685 iterator.Advance(); | 1657 iterator.Advance(); |
| 1686 } | 1658 } |
| 1687 } | 1659 } |
| 1688 } | 1660 } |
| 1689 | 1661 |
| 1690 | 1662 |
| 1691 void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, | 1663 void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, |
| 1692 InstructionOperand* cur_op, | 1664 InstructionOperand* cur_op, |
| 1693 const InstructionBlock* pred, | 1665 const InstructionBlock* pred, |
| 1694 InstructionOperand* pred_op) { | 1666 InstructionOperand* pred_op) { |
| 1695 if (pred_op->Equals(cur_op)) return; | 1667 DCHECK(!pred_op->Equals(cur_op)); |
| 1696 int gap_index; | 1668 int gap_index; |
| 1697 Instruction::GapPosition position; | 1669 Instruction::GapPosition position; |
| 1698 if (block->PredecessorCount() == 1) { | 1670 if (block->PredecessorCount() == 1) { |
| 1699 gap_index = block->first_instruction_index(); | 1671 gap_index = block->first_instruction_index(); |
| 1700 position = Instruction::START; | 1672 position = Instruction::START; |
| 1701 } else { | 1673 } else { |
| 1702 DCHECK(pred->SuccessorCount() == 1); | 1674 DCHECK(pred->SuccessorCount() == 1); |
| 1703 DCHECK(!InstructionAt(pred->last_instruction_index())->HasReferenceMap()); | 1675 DCHECK(!InstructionAt(pred->last_instruction_index())->HasReferenceMap()); |
| 1704 gap_index = pred->last_instruction_index(); | 1676 gap_index = pred->last_instruction_index(); |
| 1705 position = Instruction::END; | 1677 position = Instruction::END; |
| (...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2527 | 2499 |
| 2528 | 2500 |
| 2529 void RegisterAllocator::SetLiveRangeAssignedRegister(LiveRange* range, | 2501 void RegisterAllocator::SetLiveRangeAssignedRegister(LiveRange* range, |
| 2530 int reg) { | 2502 int reg) { |
| 2531 if (range->Kind() == DOUBLE_REGISTERS) { | 2503 if (range->Kind() == DOUBLE_REGISTERS) { |
| 2532 assigned_double_registers_->Add(reg); | 2504 assigned_double_registers_->Add(reg); |
| 2533 } else { | 2505 } else { |
| 2534 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2506 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 2535 assigned_registers_->Add(reg); | 2507 assigned_registers_->Add(reg); |
| 2536 } | 2508 } |
| 2537 range->set_assigned_register(reg, operand_cache()); | 2509 range->set_assigned_register(reg); |
| 2538 } | 2510 } |
| 2539 | 2511 |
| 2540 } // namespace compiler | 2512 } // namespace compiler |
| 2541 } // namespace internal | 2513 } // namespace internal |
| 2542 } // namespace v8 | 2514 } // namespace v8 |
| OLD | NEW |