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 |