| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 is_double_(false), | 132 is_double_(false), |
| 133 assigned_register_(kInvalidAssignment), | 133 assigned_register_(kInvalidAssignment), |
| 134 last_interval_(NULL), | 134 last_interval_(NULL), |
| 135 first_interval_(NULL), | 135 first_interval_(NULL), |
| 136 first_pos_(NULL), | 136 first_pos_(NULL), |
| 137 parent_(NULL), | 137 parent_(NULL), |
| 138 next_(NULL), | 138 next_(NULL), |
| 139 current_interval_(NULL), | 139 current_interval_(NULL), |
| 140 last_processed_use_(NULL), | 140 last_processed_use_(NULL), |
| 141 spill_operand_(new(zone) LOperand()), | 141 spill_operand_(new(zone) LOperand()), |
| 142 spill_start_index_(kMaxInt) { } | 142 spill_start_index_(kMaxInt), |
| 143 spill_source_(NULL) { } |
| 143 | 144 |
| 144 | 145 |
| 145 void LiveRange::set_assigned_register(int reg, | 146 void LiveRange::set_assigned_register(int reg, |
| 146 RegisterKind register_kind, | 147 RegisterKind register_kind, |
| 147 Zone* zone) { | 148 Zone* zone) { |
| 148 ASSERT(!HasRegisterAssigned() && !IsSpilled()); | 149 ASSERT(!HasRegisterAssigned() && !IsSpilled()); |
| 149 assigned_register_ = reg; | 150 assigned_register_ = reg; |
| 150 is_double_ = (register_kind == DOUBLE_REGISTERS); | 151 is_double_ = (register_kind == DOUBLE_REGISTERS); |
| 151 ConvertOperands(zone); | 152 ConvertOperands(zone); |
| 152 } | 153 } |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 : zone_(graph->zone()), | 535 : zone_(graph->zone()), |
| 535 chunk_(NULL), | 536 chunk_(NULL), |
| 536 live_in_sets_(graph->blocks()->length(), zone_), | 537 live_in_sets_(graph->blocks()->length(), zone_), |
| 537 live_ranges_(num_values * 2, zone_), | 538 live_ranges_(num_values * 2, zone_), |
| 538 fixed_live_ranges_(NULL), | 539 fixed_live_ranges_(NULL), |
| 539 fixed_double_live_ranges_(NULL), | 540 fixed_double_live_ranges_(NULL), |
| 540 unhandled_live_ranges_(num_values * 2, zone_), | 541 unhandled_live_ranges_(num_values * 2, zone_), |
| 541 active_live_ranges_(8, zone_), | 542 active_live_ranges_(8, zone_), |
| 542 inactive_live_ranges_(8, zone_), | 543 inactive_live_ranges_(8, zone_), |
| 543 reusable_slots_(8, zone_), | 544 reusable_slots_(8, zone_), |
| 545 pending_spilled_(8, zone_), |
| 544 next_virtual_register_(num_values), | 546 next_virtual_register_(num_values), |
| 545 first_artificial_register_(num_values), | 547 first_artificial_register_(num_values), |
| 546 mode_(GENERAL_REGISTERS), | 548 mode_(GENERAL_REGISTERS), |
| 547 num_registers_(-1), | 549 num_registers_(-1), |
| 548 graph_(graph), | 550 graph_(graph), |
| 549 has_osr_entry_(false), | 551 has_osr_entry_(false), |
| 550 allocation_ok_(true) { } | 552 allocation_ok_(true) { } |
| 551 | 553 |
| 552 | 554 |
| 553 void LAllocator::InitializeLivenessAnalysis() { | 555 void LAllocator::InitializeLivenessAnalysis() { |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 if (temp->HasFixedPolicy()) { | 793 if (temp->HasFixedPolicy()) { |
| 792 AllocateFixed(temp, gap_index - 1, false); | 794 AllocateFixed(temp, gap_index - 1, false); |
| 793 } | 795 } |
| 794 } | 796 } |
| 795 } | 797 } |
| 796 | 798 |
| 797 // Handle fixed output operand. | 799 // Handle fixed output operand. |
| 798 if (first != NULL && first->Output() != NULL) { | 800 if (first != NULL && first->Output() != NULL) { |
| 799 LUnallocated* first_output = LUnallocated::cast(first->Output()); | 801 LUnallocated* first_output = LUnallocated::cast(first->Output()); |
| 800 LiveRange* range = LiveRangeFor(first_output->virtual_register()); | 802 LiveRange* range = LiveRangeFor(first_output->virtual_register()); |
| 801 bool assigned = false; | |
| 802 if (first_output->HasFixedPolicy()) { | 803 if (first_output->HasFixedPolicy()) { |
| 803 LUnallocated* output_copy = first_output->CopyUnconstrained(zone()); | 804 LUnallocated* output_copy = first_output->CopyUnconstrained(zone()); |
| 804 bool is_tagged = HasTaggedValue(first_output->virtual_register()); | 805 bool is_tagged = HasTaggedValue(first_output->virtual_register()); |
| 805 AllocateFixed(first_output, gap_index, is_tagged); | 806 AllocateFixed(first_output, gap_index, is_tagged); |
| 806 | 807 |
| 807 // This value is produced on the stack, we never need to spill it. | 808 // This value is produced on the stack, we never need to spill it. |
| 808 if (first_output->IsStackSlot()) { | 809 if (first_output->IsStackSlot()) { |
| 809 range->SetSpillOperand(first_output); | 810 range->SetSpillOperand(first_output); |
| 810 range->SetSpillStartIndex(gap_index - 1); | 811 range->set_spill_start_index(gap_index - 1); |
| 811 assigned = true; | |
| 812 } | 812 } |
| 813 chunk_->AddGapMove(gap_index, first_output, output_copy); | 813 chunk_->AddGapMove(gap_index, first_output, output_copy); |
| 814 } | 814 } |
| 815 | 815 |
| 816 if (!assigned) { | 816 if (!range->HasAllocatedSpillOperand()) { |
| 817 range->SetSpillStartIndex(gap_index); | 817 // Instructions that are emitted at uses produce values multiple times |
| 818 // from different spill sources. There is however no dominance relation |
| 819 // between different occurrence of the same constant and thus we have to |
| 820 // emit spill stores eagerly at all of them. |
| 821 if (range->spill_source() != NULL) { |
| 822 if (range->HasPendingSpillStore()) { |
| 823 EmitSpillStore(range); |
| 824 range->DisableSpillStoreSinking(); |
| 825 } |
| 818 | 826 |
| 819 // This move to spill operand is not a real use. Liveness analysis | 827 EmitSpillStore(gap_index, first_output, range->GetSpillOperand()); |
| 820 // and splitting of live ranges do not account for it. | 828 } else { |
| 821 // Thus it should be inserted to a lifetime position corresponding to | 829 range->set_spill_start_index(gap_index); |
| 822 // the instruction end. | 830 range->set_spill_source(first_output); |
| 823 LGap* gap = GapAt(gap_index); | 831 } |
| 824 LParallelMove* move = gap->GetOrCreateParallelMove(LGap::BEFORE, zone()); | |
| 825 move->AddMove(first_output, range->GetSpillOperand(), zone()); | |
| 826 } | 832 } |
| 827 } | 833 } |
| 828 | 834 |
| 829 // Handle fixed input operands of second instruction. | 835 // Handle fixed input operands of second instruction. |
| 830 if (second != NULL) { | 836 if (second != NULL) { |
| 831 for (UseIterator it(second); !it.Done(); it.Advance()) { | 837 for (UseIterator it(second); !it.Done(); it.Advance()) { |
| 832 LUnallocated* cur_input = LUnallocated::cast(it.Current()); | 838 LUnallocated* cur_input = LUnallocated::cast(it.Current()); |
| 833 if (cur_input->HasFixedPolicy()) { | 839 if (cur_input->HasFixedPolicy()) { |
| 834 LUnallocated* input_copy = cur_input->CopyUnconstrained(zone()); | 840 LUnallocated* input_copy = cur_input->CopyUnconstrained(zone()); |
| 835 bool is_tagged = HasTaggedValue(cur_input->virtual_register()); | 841 bool is_tagged = HasTaggedValue(cur_input->virtual_register()); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 if (branch->HasPointerMap()) { | 1053 if (branch->HasPointerMap()) { |
| 1048 if (phi->representation().IsTagged()) { | 1054 if (phi->representation().IsTagged()) { |
| 1049 branch->pointer_map()->RecordPointer(phi_operand, zone()); | 1055 branch->pointer_map()->RecordPointer(phi_operand, zone()); |
| 1050 } else if (!phi->representation().IsDouble()) { | 1056 } else if (!phi->representation().IsDouble()) { |
| 1051 branch->pointer_map()->RecordUntagged(phi_operand, zone()); | 1057 branch->pointer_map()->RecordUntagged(phi_operand, zone()); |
| 1052 } | 1058 } |
| 1053 } | 1059 } |
| 1054 } | 1060 } |
| 1055 | 1061 |
| 1056 LiveRange* live_range = LiveRangeFor(phi->id()); | 1062 LiveRange* live_range = LiveRangeFor(phi->id()); |
| 1057 LLabel* label = chunk_->GetLabel(phi->block()->block_id()); | 1063 live_range->set_spill_start_index(phi->block()->first_instruction_index()); |
| 1058 label->GetOrCreateParallelMove(LGap::START, zone())-> | 1064 live_range->set_spill_source(phi_operand); |
| 1059 AddMove(phi_operand, live_range->GetSpillOperand(), zone()); | |
| 1060 live_range->SetSpillStartIndex(phi->block()->first_instruction_index()); | |
| 1061 } | 1065 } |
| 1062 } | 1066 } |
| 1063 | 1067 |
| 1068 |
| 1069 bool LAllocator::TrySinkSpillStoreTo(LiveRange* range, HBasicBlock* block) { |
| 1070 LifetimePosition pos = LifetimePosition::FromInstructionIndex( |
| 1071 block->first_instruction_index()); |
| 1072 |
| 1073 if (!range->Covers(pos)) { |
| 1074 // For now we are limiting sinking to the case when initial live range |
| 1075 // extends beyond the loop and covers the position to which we are trying |
| 1076 // to sink the spill store. |
| 1077 return false; |
| 1078 } |
| 1079 |
| 1080 // Check that selected position dominates all spilled siblings. |
| 1081 for (LiveRange* sibling = range; sibling != NULL; sibling = sibling->next()) { |
| 1082 if (!sibling->IsSpilled()) { |
| 1083 continue; |
| 1084 } |
| 1085 |
| 1086 if (pos.Value() > sibling->Start().Value()) { |
| 1087 return false; |
| 1088 } |
| 1089 |
| 1090 HBasicBlock* sibling_block = GetBlock(sibling->Start()); |
| 1091 if ((block != sibling_block) && !block->Dominates(sibling_block)) { |
| 1092 return false; |
| 1093 } |
| 1094 } |
| 1095 |
| 1096 range->set_spill_start_index(pos.InstructionIndex()); |
| 1097 return true; |
| 1098 } |
| 1099 |
| 1100 |
| 1101 void LAllocator::SinkSpillStores() { |
| 1102 for (int i = 0; i < pending_spilled_.length(); i++) { |
| 1103 LiveRange* range = pending_spilled_[i]; |
| 1104 |
| 1105 HBasicBlock* range_block = GetBlock(range->Start()); |
| 1106 |
| 1107 HBasicBlock* loop_header = range_block->IsLoopHeader() ? |
| 1108 range_block : range_block->parent_loop_header(); |
| 1109 |
| 1110 bool replace_spill_source = false; |
| 1111 while (loop_header != NULL) { |
| 1112 HBasicBlock* block = loop_header->loop_information()->exit_block(); |
| 1113 if (block == NULL || !TrySinkSpillStoreTo(range, block)) { |
| 1114 break; |
| 1115 } |
| 1116 |
| 1117 replace_spill_source = true; |
| 1118 loop_header = loop_header->parent_loop_header(); |
| 1119 } |
| 1120 |
| 1121 if (replace_spill_source) { |
| 1122 // Spill store was sunk down. Replace spill source. |
| 1123 range->set_spill_source(range->CreateAssignedOperand(zone())); |
| 1124 } |
| 1125 |
| 1126 EmitSpillStore(range); |
| 1127 } |
| 1128 } |
| 1129 |
| 1064 | 1130 |
| 1065 bool LAllocator::Allocate(LChunk* chunk) { | 1131 bool LAllocator::Allocate(LChunk* chunk) { |
| 1066 ASSERT(chunk_ == NULL); | 1132 ASSERT(chunk_ == NULL); |
| 1067 chunk_ = static_cast<LPlatformChunk*>(chunk); | 1133 chunk_ = static_cast<LPlatformChunk*>(chunk); |
| 1068 MeetRegisterConstraints(); | 1134 MeetRegisterConstraints(); |
| 1069 if (!AllocationOk()) return false; | 1135 if (!AllocationOk()) return false; |
| 1070 ResolvePhis(); | 1136 ResolvePhis(); |
| 1071 BuildLiveRanges(); | 1137 BuildLiveRanges(); |
| 1072 AllocateGeneralRegisters(); | 1138 AllocateGeneralRegisters(); |
| 1073 if (!AllocationOk()) return false; | 1139 if (!AllocationOk()) return false; |
| 1074 AllocateDoubleRegisters(); | 1140 AllocateDoubleRegisters(); |
| 1075 if (!AllocationOk()) return false; | 1141 if (!AllocationOk()) return false; |
| 1142 |
| 1143 // Sink pending spill stores down to loop exits. Should be done before |
| 1144 // pointer maps are populated. |
| 1145 SinkSpillStores(); |
| 1146 |
| 1076 PopulatePointerMaps(); | 1147 PopulatePointerMaps(); |
| 1077 if (has_osr_entry_) ProcessOsrEntry(); | 1148 if (has_osr_entry_) ProcessOsrEntry(); |
| 1078 ConnectRanges(); | 1149 ConnectRanges(); |
| 1079 ResolveControlFlow(); | 1150 ResolveControlFlow(); |
| 1080 return true; | 1151 return true; |
| 1081 } | 1152 } |
| 1082 | 1153 |
| 1083 | 1154 |
| 1084 void LAllocator::MeetRegisterConstraints() { | 1155 void LAllocator::MeetRegisterConstraints() { |
| 1085 HPhase phase("L_Register constraints", chunk_); | 1156 HPhase phase("L_Register constraints", chunk_); |
| (...skipping 999 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2085 | 2156 |
| 2086 void LAllocator::Spill(LiveRange* range) { | 2157 void LAllocator::Spill(LiveRange* range) { |
| 2087 ASSERT(!range->IsSpilled()); | 2158 ASSERT(!range->IsSpilled()); |
| 2088 TraceAlloc("Spilling live range %d\n", range->id()); | 2159 TraceAlloc("Spilling live range %d\n", range->id()); |
| 2089 LiveRange* first = range->TopLevel(); | 2160 LiveRange* first = range->TopLevel(); |
| 2090 | 2161 |
| 2091 if (!first->HasAllocatedSpillOperand()) { | 2162 if (!first->HasAllocatedSpillOperand()) { |
| 2092 LOperand* op = TryReuseSpillSlot(range); | 2163 LOperand* op = TryReuseSpillSlot(range); |
| 2093 if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == DOUBLE_REGISTERS); | 2164 if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == DOUBLE_REGISTERS); |
| 2094 first->SetSpillOperand(op); | 2165 first->SetSpillOperand(op); |
| 2166 |
| 2167 // This is the first time we are spilling a sibling of this range. |
| 2168 // If the spill store was not eagerly emitted at parent's start then we need |
| 2169 // to either emit it eagerly or postpone it for spill store sinking pass. |
| 2170 if (first->HasPendingSpillStore()) { |
| 2171 HBasicBlock* loop_header = GetBlock(first->Start())->LoopHeader(); |
| 2172 if ((first != range) && |
| 2173 (loop_header != NULL) && |
| 2174 (GetBlock(range->Start())->LoopHeader() != loop_header)) { |
| 2175 // If the range was defined inside the loop but is spilled outside then |
| 2176 // we should try to sink corresponding spill store out of the loop to |
| 2177 // reduce amount of memory writes. |
| 2178 pending_spilled_.Add(first, zone_); |
| 2179 } else { |
| 2180 EmitSpillStore(first); |
| 2181 } |
| 2182 } |
| 2095 } | 2183 } |
| 2096 range->MakeSpilled(zone_); | 2184 range->MakeSpilled(zone_); |
| 2097 } | 2185 } |
| 2098 | 2186 |
| 2099 | 2187 |
| 2188 void LAllocator::EmitSpillStore(LiveRange* range) { |
| 2189 ASSERT(range->HasPendingSpillStore()); |
| 2190 EmitSpillStore(range->spill_start_index(), |
| 2191 range->spill_source(), |
| 2192 range->GetSpillOperand()); |
| 2193 } |
| 2194 |
| 2195 |
| 2196 void LAllocator::EmitSpillStore(int pos, LOperand* source, LOperand* spill) { |
| 2197 // This move to spill operand is not a real use. Liveness analysis |
| 2198 // and splitting of live ranges do not account for it. |
| 2199 // Thus it should be inserted to a lifetime position corresponding to |
| 2200 // the instruction end. |
| 2201 LGap* gap = GapAt(pos); |
| 2202 LParallelMove* move = gap->GetOrCreateParallelMove(LGap::BEFORE, zone()); |
| 2203 move->AddMove(source, spill, zone()); |
| 2204 } |
| 2205 |
| 2206 |
| 2100 int LAllocator::RegisterCount() const { | 2207 int LAllocator::RegisterCount() const { |
| 2101 return num_registers_; | 2208 return num_registers_; |
| 2102 } | 2209 } |
| 2103 | 2210 |
| 2104 | 2211 |
| 2105 #ifdef DEBUG | 2212 #ifdef DEBUG |
| 2106 | 2213 |
| 2107 | 2214 |
| 2108 void LAllocator::Verify() const { | 2215 void LAllocator::Verify() const { |
| 2109 for (int i = 0; i < live_ranges()->length(); ++i) { | 2216 for (int i = 0; i < live_ranges()->length(); ++i) { |
| 2110 LiveRange* current = live_ranges()->at(i); | 2217 LiveRange* current = live_ranges()->at(i); |
| 2111 if (current != NULL) current->Verify(); | 2218 if (current != NULL) current->Verify(); |
| 2112 } | 2219 } |
| 2113 } | 2220 } |
| 2114 | 2221 |
| 2115 | 2222 |
| 2116 #endif | 2223 #endif |
| 2117 | 2224 |
| 2118 | 2225 |
| 2119 } } // namespace v8::internal | 2226 } } // namespace v8::internal |
| OLD | NEW |