OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
| 7 #include "src/arm64/delayed-masm-arm64-inl.h" |
7 #include "src/arm64/lithium-gap-resolver-arm64.h" | 8 #include "src/arm64/lithium-gap-resolver-arm64.h" |
8 #include "src/arm64/lithium-codegen-arm64.h" | 9 #include "src/arm64/lithium-codegen-arm64.h" |
9 | 10 |
10 namespace v8 { | 11 namespace v8 { |
11 namespace internal { | 12 namespace internal { |
12 | 13 |
13 // We use the root register to spill a value while breaking a cycle in parallel | 14 #define __ ACCESS_MASM((&masm_)) |
14 // moves. We don't need access to roots while resolving the move list and using | |
15 // the root register has two advantages: | |
16 // - It is not in crankshaft allocatable registers list, so it can't interfere | |
17 // with any of the moves we are resolving. | |
18 // - We don't need to push it on the stack, as we can reload it with its value | |
19 // once we have resolved a cycle. | |
20 #define kSavedValue root | |
21 | 15 |
22 // We use the MacroAssembler floating-point scratch register to break a cycle | 16 |
23 // involving double values as the MacroAssembler will not need it for the | 17 void DelayedGapMasm::EndDelayedUse() { |
24 // operations performed by the gap resolver. | 18 DelayedMasm::EndDelayedUse(); |
25 #define kSavedDoubleValue fp_scratch | 19 if (scratch_register_used()) { |
| 20 ASSERT(ScratchRegister().Is(root)); |
| 21 ASSERT(!pending()); |
| 22 InitializeRootRegister(); |
| 23 reset_scratch_register_used(); |
| 24 } |
| 25 } |
26 | 26 |
27 | 27 |
28 LGapResolver::LGapResolver(LCodeGen* owner) | 28 LGapResolver::LGapResolver(LCodeGen* owner) |
29 : cgen_(owner), moves_(32, owner->zone()), root_index_(0), in_cycle_(false), | 29 : cgen_(owner), masm_(owner, owner->masm()), moves_(32, owner->zone()), |
30 saved_destination_(NULL), need_to_restore_root_(false) { } | 30 root_index_(0), in_cycle_(false), saved_destination_(NULL) { |
| 31 } |
31 | 32 |
32 | 33 |
33 #define __ ACCESS_MASM(cgen_->masm()) | |
34 | |
35 void LGapResolver::Resolve(LParallelMove* parallel_move) { | 34 void LGapResolver::Resolve(LParallelMove* parallel_move) { |
36 ASSERT(moves_.is_empty()); | 35 ASSERT(moves_.is_empty()); |
| 36 ASSERT(!masm_.pending()); |
37 | 37 |
38 // Build up a worklist of moves. | 38 // Build up a worklist of moves. |
39 BuildInitialMoveList(parallel_move); | 39 BuildInitialMoveList(parallel_move); |
40 | 40 |
41 for (int i = 0; i < moves_.length(); ++i) { | 41 for (int i = 0; i < moves_.length(); ++i) { |
42 LMoveOperands move = moves_[i]; | 42 LMoveOperands move = moves_[i]; |
43 | 43 |
44 // Skip constants to perform them last. They don't block other moves | 44 // Skip constants to perform them last. They don't block other moves |
45 // and skipping such moves with register destinations keeps those | 45 // and skipping such moves with register destinations keeps those |
46 // registers free for the whole algorithm. | 46 // registers free for the whole algorithm. |
47 if (!move.IsEliminated() && !move.source()->IsConstantOperand()) { | 47 if (!move.IsEliminated() && !move.source()->IsConstantOperand()) { |
48 root_index_ = i; // Any cycle is found when we reach this move again. | 48 root_index_ = i; // Any cycle is found when we reach this move again. |
49 PerformMove(i); | 49 PerformMove(i); |
50 if (in_cycle_) RestoreValue(); | 50 if (in_cycle_) RestoreValue(); |
51 } | 51 } |
52 } | 52 } |
53 | 53 |
54 // Perform the moves with constant sources. | 54 // Perform the moves with constant sources. |
55 for (int i = 0; i < moves_.length(); ++i) { | 55 for (int i = 0; i < moves_.length(); ++i) { |
56 LMoveOperands move = moves_[i]; | 56 LMoveOperands move = moves_[i]; |
57 | 57 |
58 if (!move.IsEliminated()) { | 58 if (!move.IsEliminated()) { |
59 ASSERT(move.source()->IsConstantOperand()); | 59 ASSERT(move.source()->IsConstantOperand()); |
60 EmitMove(i); | 60 EmitMove(i); |
61 } | 61 } |
62 } | 62 } |
63 | 63 |
64 if (need_to_restore_root_) { | 64 __ EndDelayedUse(); |
65 ASSERT(kSavedValue.Is(root)); | |
66 __ InitializeRootRegister(); | |
67 need_to_restore_root_ = false; | |
68 } | |
69 | 65 |
70 moves_.Rewind(0); | 66 moves_.Rewind(0); |
71 } | 67 } |
72 | 68 |
73 | 69 |
74 void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) { | 70 void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) { |
75 // Perform a linear sweep of the moves to add them to the initial list of | 71 // Perform a linear sweep of the moves to add them to the initial list of |
76 // moves to perform, ignoring any move that is redundant (the source is | 72 // moves to perform, ignoring any move that is redundant (the source is |
77 // the same as the destination, the destination is ignored and | 73 // the same as the destination, the destination is ignored and |
78 // unallocated, or the move was already eliminated). | 74 // unallocated, or the move was already eliminated). |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 } | 141 } |
146 } | 142 } |
147 #endif | 143 #endif |
148 } | 144 } |
149 | 145 |
150 | 146 |
151 void LGapResolver::BreakCycle(int index) { | 147 void LGapResolver::BreakCycle(int index) { |
152 ASSERT(moves_[index].destination()->Equals(moves_[root_index_].source())); | 148 ASSERT(moves_[index].destination()->Equals(moves_[root_index_].source())); |
153 ASSERT(!in_cycle_); | 149 ASSERT(!in_cycle_); |
154 | 150 |
155 // We use registers which are not allocatable by crankshaft to break the cycle | |
156 // to be sure they don't interfere with the moves we are resolving. | |
157 ASSERT(!kSavedValue.IsAllocatable()); | |
158 ASSERT(!kSavedDoubleValue.IsAllocatable()); | |
159 | |
160 // We save in a register the source of that move and we remember its | 151 // We save in a register the source of that move and we remember its |
161 // destination. Then we mark this move as resolved so the cycle is | 152 // destination. Then we mark this move as resolved so the cycle is |
162 // broken and we can perform the other moves. | 153 // broken and we can perform the other moves. |
163 in_cycle_ = true; | 154 in_cycle_ = true; |
164 LOperand* source = moves_[index].source(); | 155 LOperand* source = moves_[index].source(); |
165 saved_destination_ = moves_[index].destination(); | 156 saved_destination_ = moves_[index].destination(); |
166 | 157 |
167 if (source->IsRegister()) { | 158 if (source->IsRegister()) { |
168 need_to_restore_root_ = true; | 159 AcquireSavedValueRegister(); |
169 __ Mov(kSavedValue, cgen_->ToRegister(source)); | 160 __ Mov(SavedValueRegister(), cgen_->ToRegister(source)); |
170 } else if (source->IsStackSlot()) { | 161 } else if (source->IsStackSlot()) { |
171 need_to_restore_root_ = true; | 162 AcquireSavedValueRegister(); |
172 __ Ldr(kSavedValue, cgen_->ToMemOperand(source)); | 163 __ Load(SavedValueRegister(), cgen_->ToMemOperand(source)); |
173 } else if (source->IsDoubleRegister()) { | 164 } else if (source->IsDoubleRegister()) { |
174 ASSERT(cgen_->masm()->FPTmpList()->IncludesAliasOf(kSavedDoubleValue)); | 165 __ Fmov(SavedFPValueRegister(), cgen_->ToDoubleRegister(source)); |
175 cgen_->masm()->FPTmpList()->Remove(kSavedDoubleValue); | |
176 __ Fmov(kSavedDoubleValue, cgen_->ToDoubleRegister(source)); | |
177 } else if (source->IsDoubleStackSlot()) { | 166 } else if (source->IsDoubleStackSlot()) { |
178 ASSERT(cgen_->masm()->FPTmpList()->IncludesAliasOf(kSavedDoubleValue)); | 167 __ Load(SavedFPValueRegister(), cgen_->ToMemOperand(source)); |
179 cgen_->masm()->FPTmpList()->Remove(kSavedDoubleValue); | |
180 __ Ldr(kSavedDoubleValue, cgen_->ToMemOperand(source)); | |
181 } else { | 168 } else { |
182 UNREACHABLE(); | 169 UNREACHABLE(); |
183 } | 170 } |
184 | 171 |
185 // Mark this move as resolved. | 172 // Mark this move as resolved. |
186 // This move will be actually performed by moving the saved value to this | 173 // This move will be actually performed by moving the saved value to this |
187 // move's destination in LGapResolver::RestoreValue(). | 174 // move's destination in LGapResolver::RestoreValue(). |
188 moves_[index].Eliminate(); | 175 moves_[index].Eliminate(); |
189 } | 176 } |
190 | 177 |
191 | 178 |
192 void LGapResolver::RestoreValue() { | 179 void LGapResolver::RestoreValue() { |
193 ASSERT(in_cycle_); | 180 ASSERT(in_cycle_); |
194 ASSERT(saved_destination_ != NULL); | 181 ASSERT(saved_destination_ != NULL); |
195 | 182 |
196 if (saved_destination_->IsRegister()) { | 183 if (saved_destination_->IsRegister()) { |
197 __ Mov(cgen_->ToRegister(saved_destination_), kSavedValue); | 184 __ Mov(cgen_->ToRegister(saved_destination_), SavedValueRegister()); |
| 185 ReleaseSavedValueRegister(); |
198 } else if (saved_destination_->IsStackSlot()) { | 186 } else if (saved_destination_->IsStackSlot()) { |
199 __ Str(kSavedValue, cgen_->ToMemOperand(saved_destination_)); | 187 __ Store(SavedValueRegister(), cgen_->ToMemOperand(saved_destination_)); |
| 188 ReleaseSavedValueRegister(); |
200 } else if (saved_destination_->IsDoubleRegister()) { | 189 } else if (saved_destination_->IsDoubleRegister()) { |
201 __ Fmov(cgen_->ToDoubleRegister(saved_destination_), kSavedDoubleValue); | 190 __ Fmov(cgen_->ToDoubleRegister(saved_destination_), |
202 cgen_->masm()->FPTmpList()->Combine(kSavedDoubleValue); | 191 SavedFPValueRegister()); |
203 } else if (saved_destination_->IsDoubleStackSlot()) { | 192 } else if (saved_destination_->IsDoubleStackSlot()) { |
204 __ Str(kSavedDoubleValue, cgen_->ToMemOperand(saved_destination_)); | 193 __ Store(SavedFPValueRegister(), cgen_->ToMemOperand(saved_destination_)); |
205 cgen_->masm()->FPTmpList()->Combine(kSavedDoubleValue); | |
206 } else { | 194 } else { |
207 UNREACHABLE(); | 195 UNREACHABLE(); |
208 } | 196 } |
209 | 197 |
210 in_cycle_ = false; | 198 in_cycle_ = false; |
211 saved_destination_ = NULL; | 199 saved_destination_ = NULL; |
212 } | 200 } |
213 | 201 |
214 | 202 |
215 void LGapResolver::EmitMove(int index) { | 203 void LGapResolver::EmitMove(int index) { |
216 LOperand* source = moves_[index].source(); | 204 LOperand* source = moves_[index].source(); |
217 LOperand* destination = moves_[index].destination(); | 205 LOperand* destination = moves_[index].destination(); |
218 | 206 |
219 // Dispatch on the source and destination operand kinds. Not all | 207 // Dispatch on the source and destination operand kinds. Not all |
220 // combinations are possible. | 208 // combinations are possible. |
221 | 209 |
222 if (source->IsRegister()) { | 210 if (source->IsRegister()) { |
223 Register source_register = cgen_->ToRegister(source); | 211 Register source_register = cgen_->ToRegister(source); |
224 if (destination->IsRegister()) { | 212 if (destination->IsRegister()) { |
225 __ Mov(cgen_->ToRegister(destination), source_register); | 213 __ Mov(cgen_->ToRegister(destination), source_register); |
226 } else { | 214 } else { |
227 ASSERT(destination->IsStackSlot()); | 215 ASSERT(destination->IsStackSlot()); |
228 __ Str(source_register, cgen_->ToMemOperand(destination)); | 216 __ Store(source_register, cgen_->ToMemOperand(destination)); |
229 } | 217 } |
230 | 218 |
231 } else if (source->IsStackSlot()) { | 219 } else if (source->IsStackSlot()) { |
232 MemOperand source_operand = cgen_->ToMemOperand(source); | 220 MemOperand source_operand = cgen_->ToMemOperand(source); |
233 if (destination->IsRegister()) { | 221 if (destination->IsRegister()) { |
234 __ Ldr(cgen_->ToRegister(destination), source_operand); | 222 __ Load(cgen_->ToRegister(destination), source_operand); |
235 } else { | 223 } else { |
236 ASSERT(destination->IsStackSlot()); | 224 ASSERT(destination->IsStackSlot()); |
237 EmitStackSlotMove(index); | 225 EmitStackSlotMove(index); |
238 } | 226 } |
239 | 227 |
240 } else if (source->IsConstantOperand()) { | 228 } else if (source->IsConstantOperand()) { |
241 LConstantOperand* constant_source = LConstantOperand::cast(source); | 229 LConstantOperand* constant_source = LConstantOperand::cast(source); |
242 if (destination->IsRegister()) { | 230 if (destination->IsRegister()) { |
243 Register dst = cgen_->ToRegister(destination); | 231 Register dst = cgen_->ToRegister(destination); |
244 if (cgen_->IsSmi(constant_source)) { | 232 if (cgen_->IsSmi(constant_source)) { |
245 __ Mov(dst, cgen_->ToSmi(constant_source)); | 233 __ Mov(dst, cgen_->ToSmi(constant_source)); |
246 } else if (cgen_->IsInteger32Constant(constant_source)) { | 234 } else if (cgen_->IsInteger32Constant(constant_source)) { |
247 __ Mov(dst, cgen_->ToInteger32(constant_source)); | 235 __ Mov(dst, cgen_->ToInteger32(constant_source)); |
248 } else { | 236 } else { |
249 __ LoadObject(dst, cgen_->ToHandle(constant_source)); | 237 __ LoadObject(dst, cgen_->ToHandle(constant_source)); |
250 } | 238 } |
251 } else if (destination->IsDoubleRegister()) { | 239 } else if (destination->IsDoubleRegister()) { |
252 DoubleRegister result = cgen_->ToDoubleRegister(destination); | 240 DoubleRegister result = cgen_->ToDoubleRegister(destination); |
253 __ Fmov(result, cgen_->ToDouble(constant_source)); | 241 __ Fmov(result, cgen_->ToDouble(constant_source)); |
254 } else { | 242 } else { |
255 ASSERT(destination->IsStackSlot()); | 243 ASSERT(destination->IsStackSlot()); |
256 ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone. | 244 ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone. |
257 need_to_restore_root_ = true; | |
258 if (cgen_->IsSmi(constant_source)) { | 245 if (cgen_->IsSmi(constant_source)) { |
259 __ Mov(kSavedValue, cgen_->ToSmi(constant_source)); | 246 Smi* smi = cgen_->ToSmi(constant_source); |
| 247 __ StoreConstant(reinterpret_cast<intptr_t>(smi), |
| 248 cgen_->ToMemOperand(destination)); |
260 } else if (cgen_->IsInteger32Constant(constant_source)) { | 249 } else if (cgen_->IsInteger32Constant(constant_source)) { |
261 __ Mov(kSavedValue, cgen_->ToInteger32(constant_source)); | 250 __ StoreConstant(cgen_->ToInteger32(constant_source), |
| 251 cgen_->ToMemOperand(destination)); |
262 } else { | 252 } else { |
263 __ LoadObject(kSavedValue, cgen_->ToHandle(constant_source)); | 253 Handle<Object> handle = cgen_->ToHandle(constant_source); |
| 254 AllowDeferredHandleDereference smi_object_check; |
| 255 if (handle->IsSmi()) { |
| 256 Object* obj = *handle; |
| 257 ASSERT(!obj->IsHeapObject()); |
| 258 __ StoreConstant(reinterpret_cast<intptr_t>(obj), |
| 259 cgen_->ToMemOperand(destination)); |
| 260 } else { |
| 261 AcquireSavedValueRegister(); |
| 262 __ LoadObject(SavedValueRegister(), handle); |
| 263 __ Store(SavedValueRegister(), cgen_->ToMemOperand(destination)); |
| 264 ReleaseSavedValueRegister(); |
| 265 } |
264 } | 266 } |
265 __ Str(kSavedValue, cgen_->ToMemOperand(destination)); | |
266 } | 267 } |
267 | 268 |
268 } else if (source->IsDoubleRegister()) { | 269 } else if (source->IsDoubleRegister()) { |
269 DoubleRegister src = cgen_->ToDoubleRegister(source); | 270 DoubleRegister src = cgen_->ToDoubleRegister(source); |
270 if (destination->IsDoubleRegister()) { | 271 if (destination->IsDoubleRegister()) { |
271 __ Fmov(cgen_->ToDoubleRegister(destination), src); | 272 __ Fmov(cgen_->ToDoubleRegister(destination), src); |
272 } else { | 273 } else { |
273 ASSERT(destination->IsDoubleStackSlot()); | 274 ASSERT(destination->IsDoubleStackSlot()); |
274 __ Str(src, cgen_->ToMemOperand(destination)); | 275 __ Store(src, cgen_->ToMemOperand(destination)); |
275 } | 276 } |
276 | 277 |
277 } else if (source->IsDoubleStackSlot()) { | 278 } else if (source->IsDoubleStackSlot()) { |
278 MemOperand src = cgen_->ToMemOperand(source); | 279 MemOperand src = cgen_->ToMemOperand(source); |
279 if (destination->IsDoubleRegister()) { | 280 if (destination->IsDoubleRegister()) { |
280 __ Ldr(cgen_->ToDoubleRegister(destination), src); | 281 __ Load(cgen_->ToDoubleRegister(destination), src); |
281 } else { | 282 } else { |
282 ASSERT(destination->IsDoubleStackSlot()); | 283 ASSERT(destination->IsDoubleStackSlot()); |
283 EmitStackSlotMove(index); | 284 EmitStackSlotMove(index); |
284 } | 285 } |
285 | 286 |
286 } else { | 287 } else { |
287 UNREACHABLE(); | 288 UNREACHABLE(); |
288 } | 289 } |
289 | 290 |
290 // The move has been emitted, we can eliminate it. | 291 // The move has been emitted, we can eliminate it. |
291 moves_[index].Eliminate(); | 292 moves_[index].Eliminate(); |
292 } | 293 } |
293 | 294 |
294 | |
295 void LGapResolver::EmitStackSlotMove(int index) { | |
296 // We need a temp register to perform a stack slot to stack slot move, and | |
297 // the register must not be involved in breaking cycles. | |
298 | |
299 // Use the Crankshaft double scratch register as the temporary. | |
300 DoubleRegister temp = crankshaft_fp_scratch; | |
301 | |
302 LOperand* src = moves_[index].source(); | |
303 LOperand* dst = moves_[index].destination(); | |
304 | |
305 ASSERT(src->IsStackSlot()); | |
306 ASSERT(dst->IsStackSlot()); | |
307 __ Ldr(temp, cgen_->ToMemOperand(src)); | |
308 __ Str(temp, cgen_->ToMemOperand(dst)); | |
309 } | |
310 | |
311 } } // namespace v8::internal | 295 } } // namespace v8::internal |
OLD | NEW |