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 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
685 : LiveRange(0, machine_type, this), | 685 : LiveRange(0, machine_type, this), |
686 vreg_(vreg), | 686 vreg_(vreg), |
687 last_child_id_(0), | 687 last_child_id_(0), |
688 splintered_from_(nullptr), | 688 splintered_from_(nullptr), |
689 spill_operand_(nullptr), | 689 spill_operand_(nullptr), |
690 spills_at_definition_(nullptr), | 690 spills_at_definition_(nullptr), |
691 spilled_in_deferred_blocks_(false), | 691 spilled_in_deferred_blocks_(false), |
692 spill_start_index_(kMaxInt), | 692 spill_start_index_(kMaxInt), |
693 last_child_(this), | 693 last_child_(this), |
694 last_pos_(nullptr), | 694 last_pos_(nullptr), |
695 splinter_(nullptr) { | 695 splinter_(nullptr), |
696 elidable_def_(nullptr) { | |
696 bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); | 697 bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); |
697 } | 698 } |
698 | 699 |
699 | 700 |
700 #if DEBUG | 701 #if DEBUG |
701 int TopLevelLiveRange::debug_virt_reg() const { | 702 int TopLevelLiveRange::debug_virt_reg() const { |
702 return IsSplinter() ? splintered_from()->vreg() : vreg(); | 703 return IsSplinter() ? splintered_from()->vreg() : vreg(); |
703 } | 704 } |
704 #endif | 705 #endif |
705 | 706 |
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1618 | 1619 |
1619 | 1620 |
1620 void ConstraintBuilder::MeetConstraintsAfter(int instr_index) { | 1621 void ConstraintBuilder::MeetConstraintsAfter(int instr_index) { |
1621 auto first = code()->InstructionAt(instr_index); | 1622 auto first = code()->InstructionAt(instr_index); |
1622 // Handle fixed temporaries. | 1623 // Handle fixed temporaries. |
1623 for (size_t i = 0; i < first->TempCount(); i++) { | 1624 for (size_t i = 0; i < first->TempCount(); i++) { |
1624 auto temp = UnallocatedOperand::cast(first->TempAt(i)); | 1625 auto temp = UnallocatedOperand::cast(first->TempAt(i)); |
1625 if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); | 1626 if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); |
1626 } | 1627 } |
1627 // Handle constant/fixed output operands. | 1628 // Handle constant/fixed output operands. |
1629 bool is_prespilled_parameter = | |
1630 first->arch_opcode() == ArchOpcode::kArchNop && first->OutputCount() == 2; | |
Jarin
2015/11/12 12:08:33
This looks really brittle because we do not even c
Mircea Trofin
2015/11/12 18:01:35
I see. I thought we used ArchNop just for introduc
| |
1631 | |
1628 for (size_t i = 0; i < first->OutputCount(); i++) { | 1632 for (size_t i = 0; i < first->OutputCount(); i++) { |
1629 InstructionOperand* output = first->OutputAt(i); | 1633 InstructionOperand* output = first->OutputAt(i); |
1630 if (output->IsConstant()) { | 1634 if (output->IsConstant()) { |
1631 int output_vreg = ConstantOperand::cast(output)->virtual_register(); | 1635 int output_vreg = ConstantOperand::cast(output)->virtual_register(); |
1632 auto range = data()->GetOrCreateLiveRangeFor(output_vreg); | 1636 auto range = data()->GetOrCreateLiveRangeFor(output_vreg); |
1633 range->SetSpillStartIndex(instr_index + 1); | 1637 range->SetSpillStartIndex(instr_index + 1); |
1634 range->SetSpillOperand(output); | 1638 range->SetSpillOperand(output); |
1635 continue; | 1639 continue; |
1636 } | 1640 } |
1637 auto first_output = UnallocatedOperand::cast(output); | 1641 auto first_output = UnallocatedOperand::cast(output); |
1638 auto range = | 1642 auto range = |
1639 data()->GetOrCreateLiveRangeFor(first_output->virtual_register()); | 1643 data()->GetOrCreateLiveRangeFor(first_output->virtual_register()); |
1640 bool assigned = false; | 1644 bool assigned = false; |
1641 if (first_output->HasFixedPolicy()) { | 1645 if (first_output->HasFixedPolicy()) { |
1642 int output_vreg = first_output->virtual_register(); | 1646 int output_vreg = first_output->virtual_register(); |
1643 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); | 1647 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); |
1644 bool is_tagged = code()->IsReference(output_vreg); | 1648 bool is_tagged = code()->IsReference(output_vreg); |
1645 AllocateFixed(first_output, instr_index, is_tagged); | 1649 AllocateFixed(first_output, instr_index, is_tagged); |
1650 MoveOperands* def = data()->AddGapMove( | |
1651 instr_index + 1, Instruction::START, *first_output, output_copy); | |
1646 | 1652 |
1647 // This value is produced on the stack, we never need to spill it. | 1653 // This value is produced on the stack, we never need to spill it. |
1648 if (first_output->IsStackSlot()) { | 1654 if (first_output->IsStackSlot()) { |
1649 DCHECK(LocationOperand::cast(first_output)->index() < | 1655 DCHECK(LocationOperand::cast(first_output)->index() < |
1650 data()->frame()->GetTotalFrameSlotCount()); | 1656 data()->frame()->GetTotalFrameSlotCount()); |
1651 range->SetSpillOperand(LocationOperand::cast(first_output)); | 1657 range->SetSpillOperand(LocationOperand::cast(first_output)); |
1652 range->SetSpillStartIndex(instr_index + 1); | 1658 range->SetSpillStartIndex(instr_index + 1); |
1653 assigned = true; | 1659 assigned = true; |
1660 } else if (is_prespilled_parameter) { | |
1661 // we need the def so that the live range has the shape expected by | |
1662 // the rest of the pipeline. Upon assigning operands, if this move | |
1663 // ends up assigning to the stack slot the register value, we may | |
1664 // delete it. | |
Jarin
2015/11/12 12:08:33
To be honest, this MarkElidableDef business seems
Mircea Trofin
2015/11/12 18:01:35
Here's what happens with a vanilla fixed register:
| |
1665 range->MarkElidableDef(def); | |
1666 UnallocatedOperand* spill_op = | |
1667 UnallocatedOperand::cast(first->OutputAt(1)); | |
1668 AllocateFixed(spill_op, instr_index, is_tagged); | |
1669 range->SetSpillOperand(spill_op); | |
1670 range->SetSpillStartIndex(instr_index + 1); | |
1671 break; | |
1654 } | 1672 } |
1655 data()->AddGapMove(instr_index + 1, Instruction::START, *first_output, | |
1656 output_copy); | |
1657 } | 1673 } |
1658 // Make sure we add a gap move for spilling (if we have not done | 1674 // Make sure we add a gap move for spilling (if we have not done |
1659 // so already). | 1675 // so already). |
1660 if (!assigned) { | 1676 if (!assigned) { |
1661 range->SpillAtDefinition(allocation_zone(), instr_index + 1, | 1677 range->SpillAtDefinition(allocation_zone(), instr_index + 1, |
1662 first_output); | 1678 first_output); |
1663 range->SetSpillStartIndex(instr_index + 1); | 1679 range->SetSpillStartIndex(instr_index + 1); |
1664 } | 1680 } |
1665 } | 1681 } |
1666 } | 1682 } |
(...skipping 1342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3009 if (top_range->is_phi()) { | 3025 if (top_range->is_phi()) { |
3010 data()->GetPhiMapValueFor(top_range)->CommitAssignment( | 3026 data()->GetPhiMapValueFor(top_range)->CommitAssignment( |
3011 top_range->GetAssignedOperand()); | 3027 top_range->GetAssignedOperand()); |
3012 } | 3028 } |
3013 for (LiveRange* range = top_range; range != nullptr; | 3029 for (LiveRange* range = top_range; range != nullptr; |
3014 range = range->next()) { | 3030 range = range->next()) { |
3015 auto assigned = range->GetAssignedOperand(); | 3031 auto assigned = range->GetAssignedOperand(); |
3016 range->ConvertUsesToOperand(assigned, spill_operand); | 3032 range->ConvertUsesToOperand(assigned, spill_operand); |
3017 } | 3033 } |
3018 | 3034 |
3035 MoveOperands* move = top_range->elidable_def(); | |
3036 if (move != nullptr && move->destination().Equals(spill_operand)) { | |
3037 move->Eliminate(); | |
3038 } | |
3039 | |
3019 if (!spill_operand.IsInvalid()) { | 3040 if (!spill_operand.IsInvalid()) { |
3020 // If this top level range has a child spilled in a deferred block, we use | 3041 // If this top level range has a child spilled in a deferred block, we use |
3021 // the range and control flow connection mechanism instead of spilling at | 3042 // the range and control flow connection mechanism instead of spilling at |
3022 // definition. Refer to the ConnectLiveRanges and ResolveControlFlow | 3043 // definition. Refer to the ConnectLiveRanges and ResolveControlFlow |
3023 // phases. Normally, when we spill at definition, we do not insert a | 3044 // phases. Normally, when we spill at definition, we do not insert a |
3024 // connecting move when a successor child range is spilled - because the | 3045 // connecting move when a successor child range is spilled - because the |
3025 // spilled range picks up its value from the slot which was assigned at | 3046 // spilled range picks up its value from the slot which was assigned at |
3026 // definition. For ranges that are determined to spill only in deferred | 3047 // definition. For ranges that are determined to spill only in deferred |
3027 // blocks, we let ConnectLiveRanges and ResolveControlFlow insert such | 3048 // blocks, we let ConnectLiveRanges and ResolveControlFlow insert such |
3028 // moves between ranges. Because of how the ranges are split around | 3049 // moves between ranges. Because of how the ranges are split around |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3066 // for all spilled live ranges at this point. | 3087 // for all spilled live ranges at this point. |
3067 int last_range_start = 0; | 3088 int last_range_start = 0; |
3068 auto reference_maps = data()->code()->reference_maps(); | 3089 auto reference_maps = data()->code()->reference_maps(); |
3069 ReferenceMapDeque::const_iterator first_it = reference_maps->begin(); | 3090 ReferenceMapDeque::const_iterator first_it = reference_maps->begin(); |
3070 for (TopLevelLiveRange* range : data()->live_ranges()) { | 3091 for (TopLevelLiveRange* range : data()->live_ranges()) { |
3071 if (range == nullptr) continue; | 3092 if (range == nullptr) continue; |
3072 // Skip non-reference values. | 3093 // Skip non-reference values. |
3073 if (!data()->IsReference(range)) continue; | 3094 if (!data()->IsReference(range)) continue; |
3074 // Skip empty live ranges. | 3095 // Skip empty live ranges. |
3075 if (range->IsEmpty()) continue; | 3096 if (range->IsEmpty()) continue; |
3097 if (range->IsReferenceAccountedByCaller()) continue; | |
3076 | 3098 |
3077 // Find the extent of the range and its children. | 3099 // Find the extent of the range and its children. |
3078 int start = range->Start().ToInstructionIndex(); | 3100 int start = range->Start().ToInstructionIndex(); |
3079 int end = 0; | 3101 int end = 0; |
3080 for (LiveRange* cur = range; cur != nullptr; cur = cur->next()) { | 3102 for (LiveRange* cur = range; cur != nullptr; cur = cur->next()) { |
3081 auto this_end = cur->End(); | 3103 auto this_end = cur->End(); |
3082 if (this_end.ToInstructionIndex() > end) | 3104 if (this_end.ToInstructionIndex() > end) |
3083 end = this_end.ToInstructionIndex(); | 3105 end = this_end.ToInstructionIndex(); |
3084 DCHECK(cur->Start().ToInstructionIndex() >= start); | 3106 DCHECK(cur->Start().ToInstructionIndex() >= start); |
3085 } | 3107 } |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3441 auto eliminate = moves->PrepareInsertAfter(move); | 3463 auto eliminate = moves->PrepareInsertAfter(move); |
3442 to_insert.push_back(move); | 3464 to_insert.push_back(move); |
3443 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 3465 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
3444 } | 3466 } |
3445 } | 3467 } |
3446 | 3468 |
3447 | 3469 |
3448 } // namespace compiler | 3470 } // namespace compiler |
3449 } // namespace internal | 3471 } // namespace internal |
3450 } // namespace v8 | 3472 } // namespace v8 |
OLD | NEW |