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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 | 67 |
68 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { | 68 void UseInterval::SplitAt(LifetimePosition pos, Zone* zone) { |
69 DCHECK(Contains(pos) && pos.Value() != start().Value()); | 69 DCHECK(Contains(pos) && pos.Value() != start().Value()); |
70 auto after = new (zone) UseInterval(pos, end_); | 70 auto after = new (zone) UseInterval(pos, end_); |
71 after->next_ = next_; | 71 after->next_ = next_; |
72 next_ = after; | 72 next_ = after; |
73 end_ = pos; | 73 end_ = pos; |
74 } | 74 } |
75 | 75 |
76 | 76 |
| 77 struct LiveRange::SpillAtDefinitionList : ZoneObject { |
| 78 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, |
| 79 SpillAtDefinitionList* next) |
| 80 : gap_index(gap_index), operand(operand), next(next) {} |
| 81 const int gap_index; |
| 82 InstructionOperand* const operand; |
| 83 SpillAtDefinitionList* const next; |
| 84 }; |
| 85 |
| 86 |
77 #ifdef DEBUG | 87 #ifdef DEBUG |
78 | 88 |
79 | 89 |
80 void LiveRange::Verify() const { | 90 void LiveRange::Verify() const { |
81 UsePosition* cur = first_pos_; | 91 UsePosition* cur = first_pos_; |
82 while (cur != nullptr) { | 92 while (cur != nullptr) { |
83 DCHECK(Start().Value() <= cur->pos().Value() && | 93 DCHECK(Start().Value() <= cur->pos().Value() && |
84 cur->pos().Value() <= End().Value()); | 94 cur->pos().Value() <= End().Value()); |
85 cur = cur->next(); | 95 cur = cur->next(); |
86 } | 96 } |
(...skipping 25 matching lines...) Expand all Loading... |
112 kind_(UNALLOCATED_REGISTERS), | 122 kind_(UNALLOCATED_REGISTERS), |
113 assigned_register_(kInvalidAssignment), | 123 assigned_register_(kInvalidAssignment), |
114 last_interval_(nullptr), | 124 last_interval_(nullptr), |
115 first_interval_(nullptr), | 125 first_interval_(nullptr), |
116 first_pos_(nullptr), | 126 first_pos_(nullptr), |
117 parent_(nullptr), | 127 parent_(nullptr), |
118 next_(nullptr), | 128 next_(nullptr), |
119 current_interval_(nullptr), | 129 current_interval_(nullptr), |
120 last_processed_use_(nullptr), | 130 last_processed_use_(nullptr), |
121 current_hint_operand_(nullptr), | 131 current_hint_operand_(nullptr), |
122 spill_operand_(new (zone) InstructionOperand()), | |
123 spill_start_index_(kMaxInt), | 132 spill_start_index_(kMaxInt), |
124 spill_range_(nullptr) {} | 133 spill_type_(SpillType::kNoSpillType), |
| 134 spill_operand_(nullptr), |
| 135 spills_at_definition_(nullptr) {} |
125 | 136 |
126 | 137 |
127 void LiveRange::set_assigned_register(int reg, Zone* zone) { | 138 void LiveRange::set_assigned_register(int reg, Zone* zone) { |
128 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 139 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
129 assigned_register_ = reg; | 140 assigned_register_ = reg; |
130 if (spill_range_ == nullptr) { | 141 // TODO(dcarney): stop aliasing hint operands. |
131 ConvertOperands(zone); | 142 ConvertUsesToOperand(CreateAssignedOperand(zone)); |
132 } | |
133 } | 143 } |
134 | 144 |
135 | 145 |
136 void LiveRange::MakeSpilled(Zone* zone) { | 146 void LiveRange::MakeSpilled() { |
137 DCHECK(!IsSpilled()); | 147 DCHECK(!IsSpilled()); |
138 DCHECK(TopLevel()->HasAllocatedSpillOperand()); | 148 DCHECK(!TopLevel()->HasNoSpillType()); |
139 spilled_ = true; | 149 spilled_ = true; |
140 assigned_register_ = kInvalidAssignment; | 150 assigned_register_ = kInvalidAssignment; |
141 ConvertOperands(zone); | |
142 } | 151 } |
143 | 152 |
144 | 153 |
145 bool LiveRange::HasAllocatedSpillOperand() const { | 154 void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, |
146 DCHECK(spill_operand_ != nullptr); | 155 InstructionOperand* operand) { |
147 return !spill_operand_->IsIgnored() || spill_range_ != nullptr; | 156 DCHECK(HasNoSpillType()); |
| 157 spills_at_definition_ = new (zone) |
| 158 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); |
| 159 } |
| 160 |
| 161 |
| 162 void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, |
| 163 InstructionOperand* op) { |
| 164 auto to_spill = TopLevel()->spills_at_definition_; |
| 165 if (to_spill == nullptr) return; |
| 166 auto zone = sequence->zone(); |
| 167 for (; to_spill != nullptr; to_spill = to_spill->next) { |
| 168 auto gap = sequence->GapAt(to_spill->gap_index); |
| 169 auto move = gap->GetOrCreateParallelMove(GapInstruction::START, zone); |
| 170 move->AddMove(to_spill->operand, op, zone); |
| 171 } |
| 172 TopLevel()->spills_at_definition_ = nullptr; |
148 } | 173 } |
149 | 174 |
150 | 175 |
151 void LiveRange::SetSpillOperand(InstructionOperand* operand) { | 176 void LiveRange::SetSpillOperand(InstructionOperand* operand) { |
| 177 DCHECK(HasNoSpillType()); |
152 DCHECK(!operand->IsUnallocated()); | 178 DCHECK(!operand->IsUnallocated()); |
153 DCHECK(spill_operand_ != nullptr); | 179 spill_type_ = SpillType::kSpillOperand; |
154 DCHECK(spill_operand_->IsIgnored()); | 180 spill_operand_ = operand; |
155 spill_operand_->ConvertTo(operand->kind(), operand->index()); | 181 } |
| 182 |
| 183 |
| 184 void LiveRange::SetSpillRange(SpillRange* spill_range) { |
| 185 DCHECK(HasNoSpillType() || HasSpillRange()); |
| 186 DCHECK_NE(spill_range, nullptr); |
| 187 spill_type_ = SpillType::kSpillRange; |
| 188 spill_range_ = spill_range; |
156 } | 189 } |
157 | 190 |
158 | 191 |
159 void LiveRange::CommitSpillOperand(InstructionOperand* operand) { | 192 void LiveRange::CommitSpillOperand(InstructionOperand* operand) { |
160 DCHECK(spill_range_ != nullptr); | 193 DCHECK(HasSpillRange()); |
| 194 DCHECK(!operand->IsUnallocated()); |
161 DCHECK(!IsChild()); | 195 DCHECK(!IsChild()); |
162 spill_range_ = nullptr; | 196 spill_type_ = SpillType::kSpillOperand; |
163 SetSpillOperand(operand); | 197 spill_operand_ = operand; |
164 for (auto range = this; range != nullptr; range = range->next()) { | |
165 if (range->IsSpilled()) { | |
166 range->ConvertUsesToOperand(operand); | |
167 } | |
168 } | |
169 } | 198 } |
170 | 199 |
171 | 200 |
172 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { | 201 UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { |
173 UsePosition* use_pos = last_processed_use_; | 202 UsePosition* use_pos = last_processed_use_; |
174 if (use_pos == nullptr) use_pos = first_pos(); | 203 if (use_pos == nullptr) use_pos = first_pos(); |
175 while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) { | 204 while (use_pos != nullptr && use_pos->pos().Value() < start.Value()) { |
176 use_pos = use_pos->next(); | 205 use_pos = use_pos->next(); |
177 } | 206 } |
178 last_processed_use_ = use_pos; | 207 last_processed_use_ = use_pos; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 switch (Kind()) { | 257 switch (Kind()) { |
229 case GENERAL_REGISTERS: | 258 case GENERAL_REGISTERS: |
230 op = RegisterOperand::Create(assigned_register(), zone); | 259 op = RegisterOperand::Create(assigned_register(), zone); |
231 break; | 260 break; |
232 case DOUBLE_REGISTERS: | 261 case DOUBLE_REGISTERS: |
233 op = DoubleRegisterOperand::Create(assigned_register(), zone); | 262 op = DoubleRegisterOperand::Create(assigned_register(), zone); |
234 break; | 263 break; |
235 default: | 264 default: |
236 UNREACHABLE(); | 265 UNREACHABLE(); |
237 } | 266 } |
238 } else if (IsSpilled()) { | 267 } else { |
| 268 DCHECK(IsSpilled()); |
239 DCHECK(!HasRegisterAssigned()); | 269 DCHECK(!HasRegisterAssigned()); |
240 op = TopLevel()->GetSpillOperand(); | 270 op = TopLevel()->GetSpillOperand(); |
241 DCHECK(!op->IsUnallocated()); | 271 DCHECK(!op->IsUnallocated()); |
242 } else { | |
243 UnallocatedOperand* unalloc = | |
244 new (zone) UnallocatedOperand(UnallocatedOperand::NONE); | |
245 unalloc->set_virtual_register(id_); | |
246 op = unalloc; | |
247 } | 272 } |
248 return op; | 273 return op; |
249 } | 274 } |
250 | 275 |
251 | 276 |
252 UseInterval* LiveRange::FirstSearchIntervalForPosition( | 277 UseInterval* LiveRange::FirstSearchIntervalForPosition( |
253 LifetimePosition position) const { | 278 LifetimePosition position) const { |
254 if (current_interval_ == nullptr) return first_interval_; | 279 if (current_interval_ == nullptr) return first_interval_; |
255 if (current_interval_->start().Value() > position.Value()) { | 280 if (current_interval_->start().Value() > position.Value()) { |
256 current_interval_ = nullptr; | 281 current_interval_ = nullptr; |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 if (use_pos->HasOperand()) { | 500 if (use_pos->HasOperand()) { |
476 DCHECK(op->IsRegister() || op->IsDoubleRegister() || | 501 DCHECK(op->IsRegister() || op->IsDoubleRegister() || |
477 !use_pos->RequiresRegister()); | 502 !use_pos->RequiresRegister()); |
478 use_pos->operand()->ConvertTo(op->kind(), op->index()); | 503 use_pos->operand()->ConvertTo(op->kind(), op->index()); |
479 } | 504 } |
480 use_pos = use_pos->next(); | 505 use_pos = use_pos->next(); |
481 } | 506 } |
482 } | 507 } |
483 | 508 |
484 | 509 |
485 void LiveRange::ConvertOperands(Zone* zone) { | |
486 ConvertUsesToOperand(CreateAssignedOperand(zone)); | |
487 } | |
488 | |
489 | |
490 bool LiveRange::CanCover(LifetimePosition position) const { | 510 bool LiveRange::CanCover(LifetimePosition position) const { |
491 if (IsEmpty()) return false; | 511 if (IsEmpty()) return false; |
492 return Start().Value() <= position.Value() && | 512 return Start().Value() <= position.Value() && |
493 position.Value() < End().Value(); | 513 position.Value() < End().Value(); |
494 } | 514 } |
495 | 515 |
496 | 516 |
497 bool LiveRange::Covers(LifetimePosition position) { | 517 bool LiveRange::Covers(LifetimePosition position) { |
498 if (!CanCover(position)) return false; | 518 if (!CanCover(position)) return false; |
499 auto start_search = FirstSearchIntervalForPosition(position); | 519 auto start_search = FirstSearchIntervalForPosition(position); |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
810 result = new_node; | 830 result = new_node; |
811 } else { | 831 } else { |
812 node->set_next(new_node); | 832 node->set_next(new_node); |
813 } | 833 } |
814 node = new_node; | 834 node = new_node; |
815 src = src->next(); | 835 src = src->next(); |
816 } | 836 } |
817 use_interval_ = result; | 837 use_interval_ = result; |
818 live_ranges().push_back(range); | 838 live_ranges().push_back(range); |
819 end_position_ = node->end(); | 839 end_position_ = node->end(); |
820 DCHECK(range->GetSpillRange() == nullptr); | 840 DCHECK(!range->HasSpillRange()); |
821 range->SetSpillRange(this); | 841 range->SetSpillRange(this); |
822 } | 842 } |
823 | 843 |
824 | 844 |
825 bool SpillRange::IsIntersectingWith(SpillRange* other) const { | 845 bool SpillRange::IsIntersectingWith(SpillRange* other) const { |
826 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || | 846 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || |
827 this->End().Value() <= other->use_interval_->start().Value() || | 847 this->End().Value() <= other->use_interval_->start().Value() || |
828 other->End().Value() <= this->use_interval_->start().Value()) { | 848 other->End().Value() <= this->use_interval_->start().Value()) { |
829 return false; | 849 return false; |
830 } | 850 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
914 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 934 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
915 auto op_kind = kind == DOUBLE_REGISTERS | 935 auto op_kind = kind == DOUBLE_REGISTERS |
916 ? InstructionOperand::DOUBLE_STACK_SLOT | 936 ? InstructionOperand::DOUBLE_STACK_SLOT |
917 : InstructionOperand::STACK_SLOT; | 937 : InstructionOperand::STACK_SLOT; |
918 auto op = new (code_zone()) InstructionOperand(op_kind, index); | 938 auto op = new (code_zone()) InstructionOperand(op_kind, index); |
919 range->SetOperand(op); | 939 range->SetOperand(op); |
920 } | 940 } |
921 } | 941 } |
922 | 942 |
923 | 943 |
| 944 void RegisterAllocator::CommitAssignment() { |
| 945 for (auto range : live_ranges()) { |
| 946 if (range == nullptr || range->IsEmpty()) continue; |
| 947 // Register assignments were committed in set_assigned_register. |
| 948 if (range->HasRegisterAssigned()) continue; |
| 949 auto assigned = range->CreateAssignedOperand(code_zone()); |
| 950 range->ConvertUsesToOperand(assigned); |
| 951 if (range->IsSpilled()) { |
| 952 range->CommitSpillsAtDefinition(code(), assigned); |
| 953 } |
| 954 } |
| 955 } |
| 956 |
| 957 |
924 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 958 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
925 DCHECK(FLAG_turbo_reuse_spill_slots); | 959 DCHECK(FLAG_turbo_reuse_spill_slots); |
926 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); | 960 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); |
927 spill_ranges().push_back(spill_range); | 961 spill_ranges().push_back(spill_range); |
928 return spill_range; | 962 return spill_range; |
929 } | 963 } |
930 | 964 |
931 | 965 |
932 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { | 966 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
933 DCHECK(FLAG_turbo_reuse_spill_slots); | 967 DCHECK(FLAG_turbo_reuse_spill_slots); |
934 DCHECK(!range->HasAllocatedSpillOperand()); | 968 DCHECK(range->HasNoSpillType()); |
935 if (range->IsChild() || !range->is_phi()) return false; | 969 if (range->IsChild() || !range->is_phi()) return false; |
936 | 970 |
937 auto lookup = phi_map_.find(range->id()); | 971 auto lookup = phi_map_.find(range->id()); |
938 DCHECK(lookup != phi_map_.end()); | 972 DCHECK(lookup != phi_map_.end()); |
939 auto phi = lookup->second.phi; | 973 auto phi = lookup->second.phi; |
940 auto block = lookup->second.block; | 974 auto block = lookup->second.block; |
941 // Count the number of spilled operands. | 975 // Count the number of spilled operands. |
942 size_t spilled_count = 0; | 976 size_t spilled_count = 0; |
943 LiveRange* first_op = nullptr; | 977 LiveRange* first_op = nullptr; |
944 for (size_t i = 0; i < phi->operands().size(); i++) { | 978 for (size_t i = 0; i < phi->operands().size(); i++) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 | 1102 |
1069 code()->AddGapMove(gap_index, output, output_copy); | 1103 code()->AddGapMove(gap_index, output, output_copy); |
1070 } | 1104 } |
1071 } | 1105 } |
1072 | 1106 |
1073 if (!assigned) { | 1107 if (!assigned) { |
1074 for (auto succ : block->successors()) { | 1108 for (auto succ : block->successors()) { |
1075 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1109 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
1076 DCHECK(successor->PredecessorCount() == 1); | 1110 DCHECK(successor->PredecessorCount() == 1); |
1077 int gap_index = successor->first_instruction_index() + 1; | 1111 int gap_index = successor->first_instruction_index() + 1; |
| 1112 range->SpillAtDefinition(local_zone(), gap_index, output); |
1078 range->SetSpillStartIndex(gap_index); | 1113 range->SetSpillStartIndex(gap_index); |
1079 | |
1080 // This move to spill operand is not a real use. Liveness analysis | |
1081 // and splitting of live ranges do not account for it. | |
1082 // Thus it should be inserted to a lifetime position corresponding to | |
1083 // the instruction end. | |
1084 auto gap = code()->GapAt(gap_index); | |
1085 auto move = | |
1086 gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()); | |
1087 move->AddMove(output, range->GetSpillOperand(), code_zone()); | |
1088 } | 1114 } |
1089 } | 1115 } |
1090 } | 1116 } |
1091 } | 1117 } |
1092 | 1118 |
1093 | 1119 |
1094 void RegisterAllocator::MeetConstraintsBetween(Instruction* first, | 1120 void RegisterAllocator::MeetConstraintsBetween(Instruction* first, |
1095 Instruction* second, | 1121 Instruction* second, |
1096 int gap_index) { | 1122 int gap_index) { |
1097 if (first != nullptr) { | 1123 if (first != nullptr) { |
(...skipping 28 matching lines...) Expand all Loading... |
1126 range->SetSpillOperand(first_output); | 1152 range->SetSpillOperand(first_output); |
1127 range->SetSpillStartIndex(gap_index - 1); | 1153 range->SetSpillStartIndex(gap_index - 1); |
1128 assigned = true; | 1154 assigned = true; |
1129 } | 1155 } |
1130 code()->AddGapMove(gap_index, first_output, output_copy); | 1156 code()->AddGapMove(gap_index, first_output, output_copy); |
1131 } | 1157 } |
1132 | 1158 |
1133 // Make sure we add a gap move for spilling (if we have not done | 1159 // Make sure we add a gap move for spilling (if we have not done |
1134 // so already). | 1160 // so already). |
1135 if (!assigned) { | 1161 if (!assigned) { |
| 1162 range->SpillAtDefinition(local_zone(), gap_index, first_output); |
1136 range->SetSpillStartIndex(gap_index); | 1163 range->SetSpillStartIndex(gap_index); |
1137 | |
1138 // This move to spill operand is not a real use. Liveness analysis | |
1139 // and splitting of live ranges do not account for it. | |
1140 // Thus it should be inserted to a lifetime position corresponding to | |
1141 // the instruction end. | |
1142 auto gap = code()->GapAt(gap_index); | |
1143 auto move = | |
1144 gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()); | |
1145 move->AddMove(first_output, range->GetSpillOperand(), code_zone()); | |
1146 } | 1164 } |
1147 } | 1165 } |
1148 } | 1166 } |
1149 } | 1167 } |
1150 | 1168 |
1151 if (second != nullptr) { | 1169 if (second != nullptr) { |
1152 // Handle fixed input operands of second instruction. | 1170 // Handle fixed input operands of second instruction. |
1153 for (size_t i = 0; i < second->InputCount(); i++) { | 1171 for (size_t i = 0; i < second->InputCount(); i++) { |
1154 auto input = second->InputAt(i); | 1172 auto input = second->InputAt(i); |
1155 if (input->IsImmediate()) continue; // Ignore immediates. | 1173 if (input->IsImmediate()) continue; // Ignore immediates. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1231 if (instr->IsGapMoves()) { | 1249 if (instr->IsGapMoves()) { |
1232 // Process the moves of the gap instruction, making their sources live. | 1250 // Process the moves of the gap instruction, making their sources live. |
1233 auto gap = code()->GapAt(index); | 1251 auto gap = code()->GapAt(index); |
1234 | 1252 |
1235 // TODO(titzer): no need to create the parallel move if it doesn't exist. | 1253 // TODO(titzer): no need to create the parallel move if it doesn't exist. |
1236 auto move = | 1254 auto move = |
1237 gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()); | 1255 gap->GetOrCreateParallelMove(GapInstruction::START, code_zone()); |
1238 const ZoneList<MoveOperands>* move_operands = move->move_operands(); | 1256 const ZoneList<MoveOperands>* move_operands = move->move_operands(); |
1239 for (int i = 0; i < move_operands->length(); ++i) { | 1257 for (int i = 0; i < move_operands->length(); ++i) { |
1240 auto cur = &move_operands->at(i); | 1258 auto cur = &move_operands->at(i); |
1241 if (cur->IsIgnored()) continue; | |
1242 auto from = cur->source(); | 1259 auto from = cur->source(); |
1243 auto to = cur->destination(); | 1260 auto to = cur->destination(); |
1244 auto hint = to; | 1261 auto hint = to; |
1245 if (to->IsUnallocated()) { | 1262 if (to->IsUnallocated()) { |
1246 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); | 1263 int to_vreg = UnallocatedOperand::cast(to)->virtual_register(); |
1247 auto to_range = LiveRangeFor(to_vreg); | 1264 auto to_range = LiveRangeFor(to_vreg); |
1248 if (to_range->is_phi()) { | 1265 if (to_range->is_phi()) { |
1249 DCHECK(!FLAG_turbo_delay_ssa_decon); | 1266 DCHECK(!FLAG_turbo_delay_ssa_decon); |
1250 if (to_range->is_non_loop_phi()) { | 1267 if (to_range->is_non_loop_phi()) { |
1251 hint = to_range->current_hint_operand(); | 1268 hint = to_range->current_hint_operand(); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1354 code()->InstructionBlockAt(block->predecessors()[i]); | 1371 code()->InstructionBlockAt(block->predecessors()[i]); |
1355 // The gap move must be added without any special processing as in | 1372 // The gap move must be added without any special processing as in |
1356 // the AddConstraintsGapMove. | 1373 // the AddConstraintsGapMove. |
1357 code()->AddGapMove(cur_block->last_instruction_index() - 1, | 1374 code()->AddGapMove(cur_block->last_instruction_index() - 1, |
1358 phi->inputs()[i], output); | 1375 phi->inputs()[i], output); |
1359 DCHECK(!InstructionAt(cur_block->last_instruction_index()) | 1376 DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
1360 ->HasPointerMap()); | 1377 ->HasPointerMap()); |
1361 } | 1378 } |
1362 } | 1379 } |
1363 auto live_range = LiveRangeFor(phi_vreg); | 1380 auto live_range = LiveRangeFor(phi_vreg); |
1364 auto block_start = code()->GetBlockStart(block->rpo_number()); | 1381 int gap_index = block->first_instruction_index(); |
1365 block_start->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone()) | 1382 live_range->SpillAtDefinition(local_zone(), gap_index, output); |
1366 ->AddMove(output, live_range->GetSpillOperand(), code_zone()); | 1383 live_range->SetSpillStartIndex(gap_index); |
1367 live_range->SetSpillStartIndex(block->first_instruction_index()); | |
1368 // We use the phi-ness of some nodes in some later heuristics. | 1384 // We use the phi-ness of some nodes in some later heuristics. |
1369 live_range->set_is_phi(true); | 1385 live_range->set_is_phi(true); |
1370 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); | 1386 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
1371 } | 1387 } |
1372 } | 1388 } |
1373 | 1389 |
1374 | 1390 |
1375 void RegisterAllocator::MeetRegisterConstraints() { | 1391 void RegisterAllocator::MeetRegisterConstraints() { |
1376 for (auto block : code()->instruction_blocks()) { | 1392 for (auto block : code()->instruction_blocks()) { |
1377 MeetRegisterConstraints(block); | 1393 MeetRegisterConstraints(block); |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1716 } | 1732 } |
1717 } | 1733 } |
1718 | 1734 |
1719 for (auto range : live_ranges()) { | 1735 for (auto range : live_ranges()) { |
1720 if (range == nullptr) continue; | 1736 if (range == nullptr) continue; |
1721 range->kind_ = RequiredRegisterKind(range->id()); | 1737 range->kind_ = RequiredRegisterKind(range->id()); |
1722 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1738 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
1723 // live ranges, every use requires the constant to be in a register. | 1739 // live ranges, every use requires the constant to be in a register. |
1724 // Without this hack, all uses with "any" policy would get the constant | 1740 // Without this hack, all uses with "any" policy would get the constant |
1725 // operand assigned. | 1741 // operand assigned. |
1726 if (range->HasAllocatedSpillOperand() && | 1742 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { |
1727 range->GetSpillOperand()->IsConstant()) { | |
1728 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { | 1743 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { |
1729 pos->register_beneficial_ = true; | 1744 pos->register_beneficial_ = true; |
1730 // TODO(dcarney): should the else case assert requires_reg_ == false? | 1745 // TODO(dcarney): should the else case assert requires_reg_ == false? |
1731 // Can't mark phis as needing a register. | 1746 // Can't mark phis as needing a register. |
1732 if (!code() | 1747 if (!code() |
1733 ->InstructionAt(pos->pos().InstructionIndex()) | 1748 ->InstructionAt(pos->pos().InstructionIndex()) |
1734 ->IsGapMoves()) { | 1749 ->IsGapMoves()) { |
1735 pos->requires_reg_ = true; | 1750 pos->requires_reg_ = true; |
1736 } | 1751 } |
1737 } | 1752 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1821 // safe point position. | 1836 // safe point position. |
1822 auto safe_point_pos = LifetimePosition::FromInstructionIndex(safe_point); | 1837 auto safe_point_pos = LifetimePosition::FromInstructionIndex(safe_point); |
1823 auto cur = range; | 1838 auto cur = range; |
1824 while (cur != nullptr && !cur->Covers(safe_point_pos)) { | 1839 while (cur != nullptr && !cur->Covers(safe_point_pos)) { |
1825 cur = cur->next(); | 1840 cur = cur->next(); |
1826 } | 1841 } |
1827 if (cur == nullptr) continue; | 1842 if (cur == nullptr) continue; |
1828 | 1843 |
1829 // Check if the live range is spilled and the safe point is after | 1844 // Check if the live range is spilled and the safe point is after |
1830 // the spill position. | 1845 // the spill position. |
1831 if (range->HasAllocatedSpillOperand() && | 1846 if (range->HasSpillOperand() && |
1832 safe_point >= range->spill_start_index() && | 1847 safe_point >= range->spill_start_index() && |
1833 !range->GetSpillOperand()->IsConstant()) { | 1848 !range->GetSpillOperand()->IsConstant()) { |
1834 TraceAlloc("Pointer for range %d (spilled at %d) at safe point %d\n", | 1849 TraceAlloc("Pointer for range %d (spilled at %d) at safe point %d\n", |
1835 range->id(), range->spill_start_index(), safe_point); | 1850 range->id(), range->spill_start_index(), safe_point); |
1836 map->RecordPointer(range->GetSpillOperand(), code_zone()); | 1851 map->RecordPointer(range->GetSpillOperand(), code_zone()); |
1837 } | 1852 } |
1838 | 1853 |
1839 if (!cur->IsSpilled()) { | 1854 if (!cur->IsSpilled()) { |
1840 TraceAlloc( | 1855 TraceAlloc( |
1841 "Pointer in register for range %d (start at %d) " | 1856 "Pointer in register for range %d (start at %d) " |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1901 auto current = unhandled_live_ranges().back(); | 1916 auto current = unhandled_live_ranges().back(); |
1902 unhandled_live_ranges().pop_back(); | 1917 unhandled_live_ranges().pop_back(); |
1903 DCHECK(UnhandledIsSorted()); | 1918 DCHECK(UnhandledIsSorted()); |
1904 auto position = current->Start(); | 1919 auto position = current->Start(); |
1905 #ifdef DEBUG | 1920 #ifdef DEBUG |
1906 allocation_finger_ = position; | 1921 allocation_finger_ = position; |
1907 #endif | 1922 #endif |
1908 TraceAlloc("Processing interval %d start=%d\n", current->id(), | 1923 TraceAlloc("Processing interval %d start=%d\n", current->id(), |
1909 position.Value()); | 1924 position.Value()); |
1910 | 1925 |
1911 if (current->HasAllocatedSpillOperand()) { | 1926 if (!current->HasNoSpillType()) { |
1912 TraceAlloc("Live range %d already has a spill operand\n", current->id()); | 1927 TraceAlloc("Live range %d already has a spill operand\n", current->id()); |
1913 auto next_pos = position; | 1928 auto next_pos = position; |
1914 if (code()->IsGapAt(next_pos.InstructionIndex())) { | 1929 if (code()->IsGapAt(next_pos.InstructionIndex())) { |
1915 next_pos = next_pos.NextInstruction(); | 1930 next_pos = next_pos.NextInstruction(); |
1916 } | 1931 } |
1917 auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); | 1932 auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); |
1918 // If the range already has a spill operand and it doesn't need a | 1933 // If the range already has a spill operand and it doesn't need a |
1919 // register immediately, split it and spill the first part of the range. | 1934 // register immediately, split it and spill the first part of the range. |
1920 if (pos == nullptr) { | 1935 if (pos == nullptr) { |
1921 Spill(current); | 1936 Spill(current); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2066 if (a->Start().Value() < b->Start().Value()) return false; | 2081 if (a->Start().Value() < b->Start().Value()) return false; |
2067 } | 2082 } |
2068 return true; | 2083 return true; |
2069 } | 2084 } |
2070 | 2085 |
2071 | 2086 |
2072 void RegisterAllocator::FreeSpillSlot(LiveRange* range) { | 2087 void RegisterAllocator::FreeSpillSlot(LiveRange* range) { |
2073 DCHECK(!FLAG_turbo_reuse_spill_slots); | 2088 DCHECK(!FLAG_turbo_reuse_spill_slots); |
2074 // Check that we are the last range. | 2089 // Check that we are the last range. |
2075 if (range->next() != nullptr) return; | 2090 if (range->next() != nullptr) return; |
2076 if (!range->TopLevel()->HasAllocatedSpillOperand()) return; | 2091 if (!range->TopLevel()->HasSpillOperand()) return; |
2077 auto spill_operand = range->TopLevel()->GetSpillOperand(); | 2092 auto spill_operand = range->TopLevel()->GetSpillOperand(); |
2078 if (spill_operand->IsConstant()) return; | 2093 if (spill_operand->IsConstant()) return; |
2079 if (spill_operand->index() >= 0) { | 2094 if (spill_operand->index() >= 0) { |
2080 reusable_slots().push_back(range); | 2095 reusable_slots().push_back(range); |
2081 } | 2096 } |
2082 } | 2097 } |
2083 | 2098 |
2084 | 2099 |
2085 InstructionOperand* RegisterAllocator::TryReuseSpillSlot(LiveRange* range) { | 2100 InstructionOperand* RegisterAllocator::TryReuseSpillSlot(LiveRange* range) { |
2086 DCHECK(!FLAG_turbo_reuse_spill_slots); | 2101 DCHECK(!FLAG_turbo_reuse_spill_slots); |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2481 // Nothing to spill. Just put it to unhandled as whole. | 2496 // Nothing to spill. Just put it to unhandled as whole. |
2482 AddToUnhandledSorted(second_part); | 2497 AddToUnhandledSorted(second_part); |
2483 } | 2498 } |
2484 } | 2499 } |
2485 | 2500 |
2486 | 2501 |
2487 void RegisterAllocator::Spill(LiveRange* range) { | 2502 void RegisterAllocator::Spill(LiveRange* range) { |
2488 DCHECK(!range->IsSpilled()); | 2503 DCHECK(!range->IsSpilled()); |
2489 TraceAlloc("Spilling live range %d\n", range->id()); | 2504 TraceAlloc("Spilling live range %d\n", range->id()); |
2490 auto first = range->TopLevel(); | 2505 auto first = range->TopLevel(); |
2491 if (!first->HasAllocatedSpillOperand()) { | 2506 if (first->HasNoSpillType()) { |
2492 if (FLAG_turbo_reuse_spill_slots) { | 2507 if (FLAG_turbo_reuse_spill_slots) { |
2493 AssignSpillRangeToLiveRange(first); | 2508 AssignSpillRangeToLiveRange(first); |
2494 } else { | 2509 } else { |
2495 auto op = TryReuseSpillSlot(range); | 2510 auto op = TryReuseSpillSlot(range); |
2496 if (op == nullptr) { | 2511 if (op == nullptr) { |
2497 // Allocate a new operand referring to the spill slot. | 2512 // Allocate a new operand referring to the spill slot. |
2498 RegisterKind kind = range->Kind(); | 2513 RegisterKind kind = range->Kind(); |
2499 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 2514 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
2500 if (kind == DOUBLE_REGISTERS) { | 2515 auto op_kind = kind == DOUBLE_REGISTERS |
2501 op = DoubleStackSlotOperand::Create(index, local_zone()); | 2516 ? InstructionOperand::DOUBLE_STACK_SLOT |
2502 } else { | 2517 : InstructionOperand::STACK_SLOT; |
2503 DCHECK(kind == GENERAL_REGISTERS); | 2518 op = new (code_zone()) InstructionOperand(op_kind, index); |
2504 op = StackSlotOperand::Create(index, local_zone()); | |
2505 } | |
2506 } | 2519 } |
2507 first->SetSpillOperand(op); | 2520 first->SetSpillOperand(op); |
2508 } | 2521 } |
2509 } | 2522 } |
2510 range->MakeSpilled(code_zone()); | 2523 range->MakeSpilled(); |
2511 } | 2524 } |
2512 | 2525 |
2513 | 2526 |
2514 int RegisterAllocator::RegisterCount() const { return num_registers_; } | 2527 int RegisterAllocator::RegisterCount() const { return num_registers_; } |
2515 | 2528 |
2516 | 2529 |
2517 #ifdef DEBUG | 2530 #ifdef DEBUG |
2518 | 2531 |
2519 | 2532 |
2520 void RegisterAllocator::Verify() const { | 2533 void RegisterAllocator::Verify() const { |
(...skipping 13 matching lines...) Expand all Loading... |
2534 } else { | 2547 } else { |
2535 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2548 DCHECK(range->Kind() == GENERAL_REGISTERS); |
2536 assigned_registers_->Add(reg); | 2549 assigned_registers_->Add(reg); |
2537 } | 2550 } |
2538 range->set_assigned_register(reg, code_zone()); | 2551 range->set_assigned_register(reg, code_zone()); |
2539 } | 2552 } |
2540 | 2553 |
2541 } // namespace compiler | 2554 } // namespace compiler |
2542 } // namespace internal | 2555 } // namespace internal |
2543 } // namespace v8 | 2556 } // namespace v8 |
OLD | NEW |