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

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

Issue 2410673002: [Turbofan] Add concept of FP register aliasing on ARM 32. (Closed)
Patch Set: Fix reg codes (ia32) and register allocator (arm32). Created 4 years, 2 months 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
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; 28 typedef ZoneSet<InstructionOperand, CompareOperandModuloType> OperandSet;
29 29
30 bool Blocks(const OperandSet& set, const InstructionOperand& operand) { 30 #define REP_BIT(rep) (1 << static_cast<int>(rep));
31 return set.find(operand) != set.end(); 31
32 bool HasMixedFPReps(int reps) {
33 return reps && !base::bits::IsPowerOfTwo32(reps);
34 }
35
36 void InsertOp(OperandSet* set, const InstructionOperand& op, int* fp_reg_reps) {
Mircea Trofin 2016/10/12 21:09:26 would it be overkill to define InsertOp as a membe
bbudge 2016/10/12 23:07:17 OperandSet is only a typedef. We could have it inh
Mircea Trofin 2016/10/14 20:58:39 Mind adding a todo on the typedef to investigate d
bbudge 2016/10/15 01:30:25 I replaced the typedef with a class. It's much cle
37 set->insert(op);
38 if (!kSimpleFPAliasing && op.IsFPRegister())
39 *fp_reg_reps |= REP_BIT(LocationOperand::cast(op).representation());
40 }
41
42 bool ContainsOpOrAlias(const OperandSet& set, const InstructionOperand& op,
Mircea Trofin 2016/10/12 21:09:26 same for this API
bbudge 2016/10/12 23:07:17 Ditto
43 int fp_reg_reps) {
44 if (set.find(op) != set.end()) return true;
45
46 if (!kSimpleFPAliasing && op.IsFPRegister()) {
47 // Platforms where FP registers have complex aliasing need extra checks.
48 const LocationOperand& loc = LocationOperand::cast(op);
49 MachineRepresentation rep = loc.representation();
50 // If we haven't encountered mixed FP registers, skip the extra checks.
51 fp_reg_reps |= REP_BIT(rep);
52 if (!HasMixedFPReps(fp_reg_reps)) return false;
53
54 // Check register against aliasing registers of other FP representations.
55 MachineRepresentation other_rep1, other_rep2;
56 switch (rep) {
57 case MachineRepresentation::kFloat32:
58 other_rep1 = MachineRepresentation::kFloat64;
59 other_rep2 = MachineRepresentation::kSimd128;
60 break;
61 case MachineRepresentation::kFloat64:
62 other_rep1 = MachineRepresentation::kFloat32;
63 other_rep2 = MachineRepresentation::kSimd128;
64 break;
65 case MachineRepresentation::kSimd128:
66 other_rep1 = MachineRepresentation::kFloat32;
67 other_rep2 = MachineRepresentation::kFloat64;
68 break;
69 default:
70 UNREACHABLE();
71 break;
72 }
73 const RegisterConfiguration* config = RegisterConfiguration::Turbofan();
74 int base = -1;
75 int aliases =
76 config->GetAliases(rep, loc.register_code(), other_rep1, &base);
77 DCHECK(aliases > 0 || (aliases == 0 && base == -1));
78 while (aliases--) {
79 if (set.find(AllocatedOperand(LocationOperand::REGISTER, other_rep1,
80 base + aliases)) != set.end())
81 return true;
82 }
83 aliases = config->GetAliases(rep, loc.register_code(), other_rep2, &base);
84 DCHECK(aliases > 0 || (aliases == 0 && base == -1));
85 while (aliases--) {
86 if (set.find(AllocatedOperand(LocationOperand::REGISTER, other_rep2,
87 base + aliases)) != set.end())
88 return true;
89 }
90 }
91 return false;
32 } 92 }
33 93
34 int FindFirstNonEmptySlot(const Instruction* instr) { 94 int FindFirstNonEmptySlot(const Instruction* instr) {
35 int i = Instruction::FIRST_GAP_POSITION; 95 int i = Instruction::FIRST_GAP_POSITION;
36 for (; i <= Instruction::LAST_GAP_POSITION; i++) { 96 for (; i <= Instruction::LAST_GAP_POSITION; i++) {
37 ParallelMove* moves = instr->parallel_moves()[i]; 97 ParallelMove* moves = instr->parallel_moves()[i];
38 if (moves == nullptr) continue; 98 if (moves == nullptr) continue;
39 for (MoveOperands* move : *moves) { 99 for (MoveOperands* move : *moves) {
40 if (!move->IsRedundant()) return i; 100 if (!move->IsRedundant()) return i;
41 move->Eliminate(); 101 move->Eliminate();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 void MoveOptimizer::RemoveClobberedDestinations(Instruction* instruction) { 147 void MoveOptimizer::RemoveClobberedDestinations(Instruction* instruction) {
88 if (instruction->IsCall()) return; 148 if (instruction->IsCall()) return;
89 ParallelMove* moves = instruction->parallel_moves()[0]; 149 ParallelMove* moves = instruction->parallel_moves()[0];
90 if (moves == nullptr) return; 150 if (moves == nullptr) return;
91 151
92 DCHECK(instruction->parallel_moves()[1] == nullptr || 152 DCHECK(instruction->parallel_moves()[1] == nullptr ||
93 instruction->parallel_moves()[1]->empty()); 153 instruction->parallel_moves()[1]->empty());
94 154
95 OperandSet outputs(local_zone()); 155 OperandSet outputs(local_zone());
96 OperandSet inputs(local_zone()); 156 OperandSet inputs(local_zone());
157 int input_fp_reg_reps = 0;
158 int output_fp_reg_reps = 0;
97 159
98 // Outputs and temps are treated together as potentially clobbering a 160 // Outputs and temps are treated together as potentially clobbering a
99 // destination operand. 161 // destination operand.
100 for (size_t i = 0; i < instruction->OutputCount(); ++i) { 162 for (size_t i = 0; i < instruction->OutputCount(); ++i) {
101 outputs.insert(*instruction->OutputAt(i)); 163 InsertOp(&outputs, *instruction->OutputAt(i), &output_fp_reg_reps);
102 } 164 }
103 for (size_t i = 0; i < instruction->TempCount(); ++i) { 165 for (size_t i = 0; i < instruction->TempCount(); ++i) {
104 outputs.insert(*instruction->TempAt(i)); 166 InsertOp(&outputs, *instruction->TempAt(i), &output_fp_reg_reps);
105 } 167 }
106 168
107 // Input operands block elisions. 169 // Input operands block elisions.
108 for (size_t i = 0; i < instruction->InputCount(); ++i) { 170 for (size_t i = 0; i < instruction->InputCount(); ++i) {
109 inputs.insert(*instruction->InputAt(i)); 171 InsertOp(&inputs, *instruction->InputAt(i), &input_fp_reg_reps);
110 } 172 }
111 173
112 // Elide moves made redundant by the instruction. 174 // Elide moves made redundant by the instruction.
113 for (MoveOperands* move : *moves) { 175 for (MoveOperands* move : *moves) {
114 if (outputs.find(move->destination()) != outputs.end() && 176 if (ContainsOpOrAlias(outputs, move->destination(), output_fp_reg_reps) &&
115 inputs.find(move->destination()) == inputs.end()) { 177 !ContainsOpOrAlias(inputs, move->destination(), input_fp_reg_reps)) {
116 move->Eliminate(); 178 move->Eliminate();
117 } 179 }
118 } 180 }
119 181
120 // The ret instruction makes any assignment before it unnecessary, except for 182 // The ret instruction makes any assignment before it unnecessary, except for
121 // the one for its input. 183 // the one for its input.
122 if (instruction->IsRet() || instruction->IsTailCall()) { 184 if (instruction->IsRet() || instruction->IsTailCall()) {
123 for (MoveOperands* move : *moves) { 185 for (MoveOperands* move : *moves) {
124 if (inputs.find(move->destination()) == inputs.end()) { 186 if (!ContainsOpOrAlias(inputs, move->destination(), input_fp_reg_reps)) {
125 move->Eliminate(); 187 move->Eliminate();
126 } 188 }
127 } 189 }
128 } 190 }
129 } 191 }
130 192
131 void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) { 193 void MoveOptimizer::MigrateMoves(Instruction* to, Instruction* from) {
132 if (from->IsCall()) return; 194 if (from->IsCall()) return;
133 195
134 ParallelMove* from_moves = from->parallel_moves()[0]; 196 ParallelMove* from_moves = from->parallel_moves()[0];
135 if (from_moves == nullptr || from_moves->empty()) return; 197 if (from_moves == nullptr || from_moves->empty()) return;
136 198
137 OperandSet dst_cant_be(local_zone()); 199 OperandSet dst_cant_be(local_zone());
138 OperandSet src_cant_be(local_zone()); 200 OperandSet src_cant_be(local_zone());
201 int dst_fp_reg_reps = 0;
202 int src_fp_reg_reps = 0;
139 203
140 // If an operand is an input to the instruction, we cannot move assignments 204 // If an operand is an input to the instruction, we cannot move assignments
141 // where it appears on the LHS. 205 // where it appears on the LHS.
142 for (size_t i = 0; i < from->InputCount(); ++i) { 206 for (size_t i = 0; i < from->InputCount(); ++i) {
143 dst_cant_be.insert(*from->InputAt(i)); 207 InsertOp(&dst_cant_be, *from->InputAt(i), &dst_fp_reg_reps);
144 } 208 }
145 // If an operand is output to the instruction, we cannot move assignments 209 // 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 210 // where it appears on the RHS, because we would lose its value before the
147 // instruction. 211 // instruction.
148 // Same for temp operands. 212 // Same for temp operands.
149 // The output can't appear on the LHS because we performed 213 // The output can't appear on the LHS because we performed
150 // RemoveClobberedDestinations for the "from" instruction. 214 // RemoveClobberedDestinations for the "from" instruction.
151 for (size_t i = 0; i < from->OutputCount(); ++i) { 215 for (size_t i = 0; i < from->OutputCount(); ++i) {
152 src_cant_be.insert(*from->OutputAt(i)); 216 InsertOp(&src_cant_be, *from->OutputAt(i), &src_fp_reg_reps);
153 } 217 }
154 for (size_t i = 0; i < from->TempCount(); ++i) { 218 for (size_t i = 0; i < from->TempCount(); ++i) {
155 src_cant_be.insert(*from->TempAt(i)); 219 InsertOp(&src_cant_be, *from->TempAt(i), &src_fp_reg_reps);
156 } 220 }
157 for (MoveOperands* move : *from_moves) { 221 for (MoveOperands* move : *from_moves) {
158 if (move->IsRedundant()) continue; 222 if (move->IsRedundant()) continue;
159 // Assume dest has a value "V". If we have a "dest = y" move, then we can't 223 // 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". 224 // move "z = dest", because z would become y rather than "V".
161 // We assume CompressMoves has happened before this, which means we don't 225 // We assume CompressMoves has happened before this, which means we don't
162 // have more than one assignment to dest. 226 // have more than one assignment to dest.
163 src_cant_be.insert(move->destination()); 227 InsertOp(&src_cant_be, move->destination(), &src_fp_reg_reps);
164 } 228 }
165 229
166 ZoneSet<MoveKey, MoveKeyCompare> move_candidates(local_zone()); 230 ZoneSet<MoveKey, MoveKeyCompare> move_candidates(local_zone());
167 // We start with all the moves that don't have conflicting source or 231 // We start with all the moves that don't have conflicting source or
168 // destination operands are eligible for being moved down. 232 // destination operands are eligible for being moved down.
169 for (MoveOperands* move : *from_moves) { 233 for (MoveOperands* move : *from_moves) {
170 if (move->IsRedundant()) continue; 234 if (move->IsRedundant()) continue;
171 if (!Blocks(dst_cant_be, move->destination())) { 235 if (!ContainsOpOrAlias(dst_cant_be, move->destination(), dst_fp_reg_reps)) {
172 MoveKey key = {move->source(), move->destination()}; 236 MoveKey key = {move->source(), move->destination()};
173 move_candidates.insert(key); 237 move_candidates.insert(key);
174 } 238 }
175 } 239 }
176 if (move_candidates.empty()) return; 240 if (move_candidates.empty()) return;
177 241
178 // Stabilize the candidate set. 242 // Stabilize the candidate set.
179 bool changed = false; 243 bool changed = false;
180 do { 244 do {
181 changed = false; 245 changed = false;
182 for (auto iter = move_candidates.begin(); iter != move_candidates.end();) { 246 for (auto iter = move_candidates.begin(); iter != move_candidates.end();) {
183 auto current = iter; 247 auto current = iter;
184 ++iter; 248 ++iter;
185 InstructionOperand src = current->source; 249 InstructionOperand src = current->source;
186 if (Blocks(src_cant_be, src)) { 250 if (ContainsOpOrAlias(src_cant_be, src, src_fp_reg_reps)) {
187 src_cant_be.insert(current->destination); 251 InsertOp(&src_cant_be, current->destination, &src_fp_reg_reps);
188 move_candidates.erase(current); 252 move_candidates.erase(current);
189 changed = true; 253 changed = true;
190 } 254 }
191 } 255 }
192 } while (changed); 256 } while (changed);
193 257
194 ParallelMove to_move(local_zone()); 258 ParallelMove to_move(local_zone());
195 for (MoveOperands* move : *from_moves) { 259 for (MoveOperands* move : *from_moves) {
196 if (move->IsRedundant()) continue; 260 if (move->IsRedundant()) continue;
197 MoveKey key = {move->source(), move->destination()}; 261 MoveKey key = {move->source(), move->destination()};
(...skipping 18 matching lines...) Expand all
216 if (right == nullptr) return; 280 if (right == nullptr) return;
217 281
218 MoveOpVector& eliminated = local_vector(); 282 MoveOpVector& eliminated = local_vector();
219 DCHECK(eliminated.empty()); 283 DCHECK(eliminated.empty());
220 284
221 if (!left->empty()) { 285 if (!left->empty()) {
222 // Modify the right moves in place and collect moves that will be killed by 286 // Modify the right moves in place and collect moves that will be killed by
223 // merging the two gaps. 287 // merging the two gaps.
224 for (MoveOperands* move : *right) { 288 for (MoveOperands* move : *right) {
225 if (move->IsRedundant()) continue; 289 if (move->IsRedundant()) continue;
226 MoveOperands* to_eliminate = left->PrepareInsertAfter(move); 290 left->PrepareInsertAfter(move, &eliminated);
227 if (to_eliminate != nullptr) eliminated.push_back(to_eliminate);
228 } 291 }
229 // Eliminate dead moves. 292 // Eliminate dead moves.
230 for (MoveOperands* to_eliminate : eliminated) { 293 for (MoveOperands* to_eliminate : eliminated) {
231 to_eliminate->Eliminate(); 294 to_eliminate->Eliminate();
232 } 295 }
233 eliminated.clear(); 296 eliminated.clear();
234 } 297 }
235 // Add all possibly modified moves from right side. 298 // Add all possibly modified moves from right side.
236 for (MoveOperands* move : *right) { 299 for (MoveOperands* move : *right) {
237 if (move->IsRedundant()) continue; 300 if (move->IsRedundant()) continue;
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 static_cast<Instruction::GapPosition>(1), code_zone()); 537 static_cast<Instruction::GapPosition>(1), code_zone());
475 slot_1->AddMove(group_begin->destination(), load->destination()); 538 slot_1->AddMove(group_begin->destination(), load->destination());
476 load->Eliminate(); 539 load->Eliminate();
477 } 540 }
478 loads.clear(); 541 loads.clear();
479 } 542 }
480 543
481 } // namespace compiler 544 } // namespace compiler
482 } // namespace internal 545 } // namespace internal
483 } // namespace v8 546 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698