Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Side by Side Diff: src/compiler/move-optimizer.cc

Issue 2410673002: [Turbofan] Add concept of FP register aliasing on ARM 32. (Closed)
Patch Set: Add a TODO. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/instruction.cc ('k') | src/compiler/register-allocator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/instruction.cc ('k') | src/compiler/register-allocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698