Chromium Code Reviews| 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 |