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/move-optimizer.h" | 5 #include "src/compiler/move-optimizer.h" |
6 | 6 |
7 namespace v8 { | 7 namespace v8 { |
8 namespace internal { | 8 namespace internal { |
9 namespace compiler { | 9 namespace compiler { |
10 | 10 |
11 namespace { | 11 namespace { |
12 | 12 |
13 struct MoveKey { | 13 struct MoveKey { |
14 InstructionOperand source; | 14 InstructionOperand source; |
15 InstructionOperand destination; | 15 InstructionOperand destination; |
16 }; | 16 }; |
17 | 17 |
18 struct MoveKeyCompare { | 18 struct MoveKeyCompare { |
19 bool operator()(const MoveKey& a, const MoveKey& b) const { | 19 bool operator()(const MoveKey& a, const MoveKey& b) const { |
20 if (a.source.EqualsCanonicalized(b.source)) { | 20 if (a.source.EqualsCanonicalized(b.source)) { |
21 return a.destination.CompareCanonicalized(b.destination); | 21 return a.destination.CompareCanonicalized(b.destination); |
22 } | 22 } |
23 return a.source.CompareCanonicalized(b.source); | 23 return a.source.CompareCanonicalized(b.source); |
24 } | 24 } |
25 }; | 25 }; |
26 | 26 |
27 typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap; | 27 typedef ZoneMap<MoveKey, unsigned, MoveKeyCompare> MoveMap; |
28 typedef ZoneSet<InstructionOperand, CompareOperandModuloType> OperandSet; | |
29 | 28 |
30 bool Blocks(const OperandSet& set, const InstructionOperand& operand) { | 29 class OperandSet { |
31 return set.find(operand) != set.end(); | 30 public: |
32 } | 31 explicit OperandSet(Zone* zone) : set_(zone), fp_reps_(0) {} |
| 32 |
| 33 void InsertOp(const InstructionOperand& op) { |
| 34 set_.insert(op); |
| 35 if (!kSimpleFPAliasing && op.IsFPRegister()) |
| 36 fp_reps_ |= RepBit(LocationOperand::cast(op).representation()); |
| 37 } |
| 38 |
| 39 bool ContainsOpOrAlias(const InstructionOperand& op) const { |
| 40 if (set_.find(op) != set_.end()) return true; |
| 41 |
| 42 if (!kSimpleFPAliasing && op.IsFPRegister()) { |
| 43 // Platforms where FP registers have complex aliasing need extra checks. |
| 44 const LocationOperand& loc = LocationOperand::cast(op); |
| 45 MachineRepresentation rep = loc.representation(); |
| 46 // If haven't encountered mixed rep FP registers, skip the extra checks. |
| 47 if (!HasMixedFPReps(fp_reps_ | RepBit(rep))) return false; |
| 48 |
| 49 // Check register against aliasing registers of other FP representations. |
| 50 MachineRepresentation other_rep1, other_rep2; |
| 51 switch (rep) { |
| 52 case MachineRepresentation::kFloat32: |
| 53 other_rep1 = MachineRepresentation::kFloat64; |
| 54 other_rep2 = MachineRepresentation::kSimd128; |
| 55 break; |
| 56 case MachineRepresentation::kFloat64: |
| 57 other_rep1 = MachineRepresentation::kFloat32; |
| 58 other_rep2 = MachineRepresentation::kSimd128; |
| 59 break; |
| 60 case MachineRepresentation::kSimd128: |
| 61 other_rep1 = MachineRepresentation::kFloat32; |
| 62 other_rep2 = MachineRepresentation::kFloat64; |
| 63 break; |
| 64 default: |
| 65 UNREACHABLE(); |
| 66 break; |
| 67 } |
| 68 const RegisterConfiguration* config = RegisterConfiguration::Turbofan(); |
| 69 int base = -1; |
| 70 int aliases = |
| 71 config->GetAliases(rep, loc.register_code(), other_rep1, &base); |
| 72 DCHECK(aliases > 0 || (aliases == 0 && base == -1)); |
| 73 while (aliases--) { |
| 74 if (set_.find(AllocatedOperand(LocationOperand::REGISTER, other_rep1, |
| 75 base + aliases)) != set_.end()) |
| 76 return true; |
| 77 } |
| 78 aliases = config->GetAliases(rep, loc.register_code(), other_rep2, &base); |
| 79 DCHECK(aliases > 0 || (aliases == 0 && base == -1)); |
| 80 while (aliases--) { |
| 81 if (set_.find(AllocatedOperand(LocationOperand::REGISTER, other_rep2, |
| 82 base + aliases)) != set_.end()) |
| 83 return true; |
| 84 } |
| 85 } |
| 86 return false; |
| 87 } |
| 88 |
| 89 private: |
| 90 static int RepBit(MachineRepresentation rep) { |
| 91 return 1 << static_cast<int>(rep); |
| 92 } |
| 93 |
| 94 static bool HasMixedFPReps(int reps) { |
| 95 return reps && !base::bits::IsPowerOfTwo32(reps); |
| 96 } |
| 97 |
| 98 ZoneSet<InstructionOperand, CompareOperandModuloType> set_; |
| 99 int fp_reps_; |
| 100 }; |
33 | 101 |
34 int FindFirstNonEmptySlot(const Instruction* instr) { | 102 int FindFirstNonEmptySlot(const Instruction* instr) { |
35 int i = Instruction::FIRST_GAP_POSITION; | 103 int i = Instruction::FIRST_GAP_POSITION; |
36 for (; i <= Instruction::LAST_GAP_POSITION; i++) { | 104 for (; i <= Instruction::LAST_GAP_POSITION; i++) { |
37 ParallelMove* moves = instr->parallel_moves()[i]; | 105 ParallelMove* moves = instr->parallel_moves()[i]; |
38 if (moves == nullptr) continue; | 106 if (moves == nullptr) continue; |
39 for (MoveOperands* move : *moves) { | 107 for (MoveOperands* move : *moves) { |
40 if (!move->IsRedundant()) return i; | 108 if (!move->IsRedundant()) return i; |
41 move->Eliminate(); | 109 move->Eliminate(); |
42 } | 110 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 | 159 |
92 DCHECK(instruction->parallel_moves()[1] == nullptr || | 160 DCHECK(instruction->parallel_moves()[1] == nullptr || |
93 instruction->parallel_moves()[1]->empty()); | 161 instruction->parallel_moves()[1]->empty()); |
94 | 162 |
95 OperandSet outputs(local_zone()); | 163 OperandSet outputs(local_zone()); |
96 OperandSet inputs(local_zone()); | 164 OperandSet inputs(local_zone()); |
97 | 165 |
98 // Outputs and temps are treated together as potentially clobbering a | 166 // Outputs and temps are treated together as potentially clobbering a |
99 // destination operand. | 167 // destination operand. |
100 for (size_t i = 0; i < instruction->OutputCount(); ++i) { | 168 for (size_t i = 0; i < instruction->OutputCount(); ++i) { |
101 outputs.insert(*instruction->OutputAt(i)); | 169 outputs.InsertOp(*instruction->OutputAt(i)); |
102 } | 170 } |
103 for (size_t i = 0; i < instruction->TempCount(); ++i) { | 171 for (size_t i = 0; i < instruction->TempCount(); ++i) { |
104 outputs.insert(*instruction->TempAt(i)); | 172 outputs.InsertOp(*instruction->TempAt(i)); |
105 } | 173 } |
106 | 174 |
107 // Input operands block elisions. | 175 // Input operands block elisions. |
108 for (size_t i = 0; i < instruction->InputCount(); ++i) { | 176 for (size_t i = 0; i < instruction->InputCount(); ++i) { |
109 inputs.insert(*instruction->InputAt(i)); | 177 inputs.InsertOp(*instruction->InputAt(i)); |
110 } | 178 } |
111 | 179 |
112 // Elide moves made redundant by the instruction. | 180 // Elide moves made redundant by the instruction. |
113 for (MoveOperands* move : *moves) { | 181 for (MoveOperands* move : *moves) { |
114 if (outputs.find(move->destination()) != outputs.end() && | 182 if (outputs.ContainsOpOrAlias(move->destination()) && |
115 inputs.find(move->destination()) == inputs.end()) { | 183 !inputs.ContainsOpOrAlias(move->destination())) { |
116 move->Eliminate(); | 184 move->Eliminate(); |
117 } | 185 } |
118 } | 186 } |
119 | 187 |
120 // The ret instruction makes any assignment before it unnecessary, except for | 188 // The ret instruction makes any assignment before it unnecessary, except for |
121 // the one for its input. | 189 // the one for its input. |
122 if (instruction->IsRet() || instruction->IsTailCall()) { | 190 if (instruction->IsRet() || instruction->IsTailCall()) { |
123 for (MoveOperands* move : *moves) { | 191 for (MoveOperands* move : *moves) { |
124 if (inputs.find(move->destination()) == inputs.end()) { | 192 if (!inputs.ContainsOpOrAlias(move->destination())) { |
125 move->Eliminate(); | 193 move->Eliminate(); |
126 } | 194 } |
127 } | 195 } |
128 } | 196 } |
129 } | 197 } |
130 | 198 |
131 void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { | 199 void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { |
132 if (from->IsCall()) return; | 200 if (from->IsCall()) return; |
133 | 201 |
134 ParallelMove* from_moves = from->parallel_moves()[0]; | 202 ParallelMove* from_moves = from->parallel_moves()[0]; |
135 if (from_moves == nullptr || from_moves->empty()) return; | 203 if (from_moves == nullptr || from_moves->empty()) return; |
136 | 204 |
137 OperandSet dst_cant_be(local_zone()); | 205 OperandSet dst_cant_be(local_zone()); |
138 OperandSet src_cant_be(local_zone()); | 206 OperandSet src_cant_be(local_zone()); |
139 | 207 |
140 // If an operand is an input to the instruction, we cannot move assignments | 208 // If an operand is an input to the instruction, we cannot move assignments |
141 // where it appears on the LHS. | 209 // where it appears on the LHS. |
142 for (size_t i = 0; i < from->InputCount(); ++i) { | 210 for (size_t i = 0; i < from->InputCount(); ++i) { |
143 dst_cant_be.insert(*from->InputAt(i)); | 211 dst_cant_be.InsertOp(*from->InputAt(i)); |
144 } | 212 } |
145 // If an operand is output to the instruction, we cannot move assignments | 213 // If an operand is output to the instruction, we cannot move assignments |
146 // where it appears on the RHS, because we would lose its value before the | 214 // where it appears on the RHS, because we would lose its value before the |
147 // instruction. | 215 // instruction. |
148 // Same for temp operands. | 216 // Same for temp operands. |
149 // The output can't appear on the LHS because we performed | 217 // The output can't appear on the LHS because we performed |
150 // RemoveClobberedDestinations for the "from" instruction. | 218 // RemoveClobberedDestinations for the "from" instruction. |
151 for (size_t i = 0; i < from->OutputCount(); ++i) { | 219 for (size_t i = 0; i < from->OutputCount(); ++i) { |
152 src_cant_be.insert(*from->OutputAt(i)); | 220 src_cant_be.InsertOp(*from->OutputAt(i)); |
153 } | 221 } |
154 for (size_t i = 0; i < from->TempCount(); ++i) { | 222 for (size_t i = 0; i < from->TempCount(); ++i) { |
155 src_cant_be.insert(*from->TempAt(i)); | 223 src_cant_be.InsertOp(*from->TempAt(i)); |
156 } | 224 } |
157 for (MoveOperands* move : *from_moves) { | 225 for (MoveOperands* move : *from_moves) { |
158 if (move->IsRedundant()) continue; | 226 if (move->IsRedundant()) continue; |
159 // Assume dest has a value "V". If we have a "dest = y" move, then we can't | 227 // Assume dest has a value "V". If we have a "dest = y" move, then we can't |
160 // move "z = dest", because z would become y rather than "V". | 228 // move "z = dest", because z would become y rather than "V". |
161 // We assume CompressMoves has happened before this, which means we don't | 229 // We assume CompressMoves has happened before this, which means we don't |
162 // have more than one assignment to dest. | 230 // have more than one assignment to dest. |
163 src_cant_be.insert(move->destination()); | 231 src_cant_be.InsertOp(move->destination()); |
164 } | 232 } |
165 | 233 |
166 ZoneSet<MoveKey, MoveKeyCompare> move_candidates(local_zone()); | 234 ZoneSet<MoveKey, MoveKeyCompare> move_candidates(local_zone()); |
167 // We start with all the moves that don't have conflicting source or | 235 // We start with all the moves that don't have conflicting source or |
168 // destination operands are eligible for being moved down. | 236 // destination operands are eligible for being moved down. |
169 for (MoveOperands* move : *from_moves) { | 237 for (MoveOperands* move : *from_moves) { |
170 if (move->IsRedundant()) continue; | 238 if (move->IsRedundant()) continue; |
171 if (!Blocks(dst_cant_be, move->destination())) { | 239 if (!dst_cant_be.ContainsOpOrAlias(move->destination())) { |
172 MoveKey key = {move->source(), move->destination()}; | 240 MoveKey key = {move->source(), move->destination()}; |
173 move_candidates.insert(key); | 241 move_candidates.insert(key); |
174 } | 242 } |
175 } | 243 } |
176 if (move_candidates.empty()) return; | 244 if (move_candidates.empty()) return; |
177 | 245 |
178 // Stabilize the candidate set. | 246 // Stabilize the candidate set. |
179 bool changed = false; | 247 bool changed = false; |
180 do { | 248 do { |
181 changed = false; | 249 changed = false; |
182 for (auto iter = move_candidates.begin(); iter != move_candidates.end();) { | 250 for (auto iter = move_candidates.begin(); iter != move_candidates.end();) { |
183 auto current = iter; | 251 auto current = iter; |
184 ++iter; | 252 ++iter; |
185 InstructionOperand src = current->source; | 253 InstructionOperand src = current->source; |
186 if (Blocks(src_cant_be, src)) { | 254 if (src_cant_be.ContainsOpOrAlias(src)) { |
187 src_cant_be.insert(current->destination); | 255 src_cant_be.InsertOp(current->destination); |
188 move_candidates.erase(current); | 256 move_candidates.erase(current); |
189 changed = true; | 257 changed = true; |
190 } | 258 } |
191 } | 259 } |
192 } while (changed); | 260 } while (changed); |
193 | 261 |
194 ParallelMove to_move(local_zone()); | 262 ParallelMove to_move(local_zone()); |
195 for (MoveOperands* move : *from_moves) { | 263 for (MoveOperands* move : *from_moves) { |
196 if (move->IsRedundant()) continue; | 264 if (move->IsRedundant()) continue; |
197 MoveKey key = {move->source(), move->destination()}; | 265 MoveKey key = {move->source(), move->destination()}; |
(...skipping 18 matching lines...) Expand all Loading... |
216 if (right == nullptr) return; | 284 if (right == nullptr) return; |
217 | 285 |
218 MoveOpVector& eliminated = local_vector(); | 286 MoveOpVector& eliminated = local_vector(); |
219 DCHECK(eliminated.empty()); | 287 DCHECK(eliminated.empty()); |
220 | 288 |
221 if (!left->empty()) { | 289 if (!left->empty()) { |
222 // Modify the right moves in place and collect moves that will be killed by | 290 // Modify the right moves in place and collect moves that will be killed by |
223 // merging the two gaps. | 291 // merging the two gaps. |
224 for (MoveOperands* move : *right) { | 292 for (MoveOperands* move : *right) { |
225 if (move->IsRedundant()) continue; | 293 if (move->IsRedundant()) continue; |
226 MoveOperands* to_eliminate = left->PrepareInsertAfter(move); | 294 left->PrepareInsertAfter(move, &eliminated); |
227 if (to_eliminate != nullptr) eliminated.push_back(to_eliminate); | |
228 } | 295 } |
229 // Eliminate dead moves. | 296 // Eliminate dead moves. |
230 for (MoveOperands* to_eliminate : eliminated) { | 297 for (MoveOperands* to_eliminate : eliminated) { |
231 to_eliminate->Eliminate(); | 298 to_eliminate->Eliminate(); |
232 } | 299 } |
233 eliminated.clear(); | 300 eliminated.clear(); |
234 } | 301 } |
235 // Add all possibly modified moves from right side. | 302 // Add all possibly modified moves from right side. |
236 for (MoveOperands* move : *right) { | 303 for (MoveOperands* move : *right) { |
237 if (move->IsRedundant()) continue; | 304 if (move->IsRedundant()) continue; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 OperandSet conflicting_srcs(local_zone()); | 420 OperandSet conflicting_srcs(local_zone()); |
354 for (auto iter = move_map.begin(), end = move_map.end(); iter != end;) { | 421 for (auto iter = move_map.begin(), end = move_map.end(); iter != end;) { |
355 auto current = iter; | 422 auto current = iter; |
356 ++iter; | 423 ++iter; |
357 if (current->second != block->PredecessorCount()) { | 424 if (current->second != block->PredecessorCount()) { |
358 InstructionOperand dest = current->first.destination; | 425 InstructionOperand dest = current->first.destination; |
359 // Not all the moves in all the gaps are the same. Maybe some are. If | 426 // Not all the moves in all the gaps are the same. Maybe some are. If |
360 // there are such moves, we could move them, but the destination of the | 427 // there are such moves, we could move them, but the destination of the |
361 // moves staying behind can't appear as a source of a common move, | 428 // moves staying behind can't appear as a source of a common move, |
362 // because the move staying behind will clobber this destination. | 429 // because the move staying behind will clobber this destination. |
363 conflicting_srcs.insert(dest); | 430 conflicting_srcs.InsertOp(dest); |
364 move_map.erase(current); | 431 move_map.erase(current); |
365 } | 432 } |
366 } | 433 } |
367 | 434 |
368 bool changed = false; | 435 bool changed = false; |
369 do { | 436 do { |
370 // If a common move can't be pushed to the common successor, then its | 437 // If a common move can't be pushed to the common successor, then its |
371 // destination also can't appear as source to any move being pushed. | 438 // destination also can't appear as source to any move being pushed. |
372 changed = false; | 439 changed = false; |
373 for (auto iter = move_map.begin(), end = move_map.end(); iter != end;) { | 440 for (auto iter = move_map.begin(), end = move_map.end(); iter != end;) { |
374 auto current = iter; | 441 auto current = iter; |
375 ++iter; | 442 ++iter; |
376 DCHECK_EQ(block->PredecessorCount(), current->second); | 443 DCHECK_EQ(block->PredecessorCount(), current->second); |
377 if (conflicting_srcs.find(current->first.source) != | 444 if (conflicting_srcs.ContainsOpOrAlias(current->first.source)) { |
378 conflicting_srcs.end()) { | 445 conflicting_srcs.InsertOp(current->first.destination); |
379 conflicting_srcs.insert(current->first.destination); | |
380 move_map.erase(current); | 446 move_map.erase(current); |
381 changed = true; | 447 changed = true; |
382 } | 448 } |
383 } | 449 } |
384 } while (changed); | 450 } while (changed); |
385 } | 451 } |
386 | 452 |
387 if (move_map.empty()) return; | 453 if (move_map.empty()) return; |
388 | 454 |
389 DCHECK_NOT_NULL(instr); | 455 DCHECK_NOT_NULL(instr); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 static_cast<Instruction::GapPosition>(1), code_zone()); | 540 static_cast<Instruction::GapPosition>(1), code_zone()); |
475 slot_1->AddMove(group_begin->destination(), load->destination()); | 541 slot_1->AddMove(group_begin->destination(), load->destination()); |
476 load->Eliminate(); | 542 load->Eliminate(); |
477 } | 543 } |
478 loads.clear(); | 544 loads.clear(); |
479 } | 545 } |
480 | 546 |
481 } // namespace compiler | 547 } // namespace compiler |
482 } // namespace internal | 548 } // namespace internal |
483 } // namespace v8 | 549 } // namespace v8 |
OLD | NEW |