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/delayed-masm-arm64-inl.h" |
8 #include "src/arm64/lithium-codegen-arm64.h" | 8 #include "src/arm64/lithium-codegen-arm64.h" |
9 #include "src/arm64/lithium-gap-resolver-arm64.h" | 9 #include "src/arm64/lithium-gap-resolver-arm64.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 | 13 |
14 #define __ ACCESS_MASM((&masm_)) | 14 #define __ ACCESS_MASM((&masm_)) |
15 | 15 |
16 | 16 |
17 void DelayedGapMasm::EndDelayedUse() { | 17 void DelayedGapMasm::EndDelayedUse() { |
18 DelayedMasm::EndDelayedUse(); | 18 DelayedMasm::EndDelayedUse(); |
19 if (scratch_register_used()) { | 19 if (scratch_register_used()) { |
20 ASSERT(ScratchRegister().Is(root)); | 20 DCHECK(ScratchRegister().Is(root)); |
21 ASSERT(!pending()); | 21 DCHECK(!pending()); |
22 InitializeRootRegister(); | 22 InitializeRootRegister(); |
23 reset_scratch_register_used(); | 23 reset_scratch_register_used(); |
24 } | 24 } |
25 } | 25 } |
26 | 26 |
27 | 27 |
28 LGapResolver::LGapResolver(LCodeGen* owner) | 28 LGapResolver::LGapResolver(LCodeGen* owner) |
29 : cgen_(owner), masm_(owner, owner->masm()), moves_(32, owner->zone()), | 29 : cgen_(owner), masm_(owner, owner->masm()), moves_(32, owner->zone()), |
30 root_index_(0), in_cycle_(false), saved_destination_(NULL) { | 30 root_index_(0), in_cycle_(false), saved_destination_(NULL) { |
31 } | 31 } |
32 | 32 |
33 | 33 |
34 void LGapResolver::Resolve(LParallelMove* parallel_move) { | 34 void LGapResolver::Resolve(LParallelMove* parallel_move) { |
35 ASSERT(moves_.is_empty()); | 35 DCHECK(moves_.is_empty()); |
36 ASSERT(!masm_.pending()); | 36 DCHECK(!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 DCHECK(move.source()->IsConstantOperand()); |
60 EmitMove(i); | 60 EmitMove(i); |
61 } | 61 } |
62 } | 62 } |
63 | 63 |
64 __ EndDelayedUse(); | 64 __ EndDelayedUse(); |
65 | 65 |
66 moves_.Rewind(0); | 66 moves_.Rewind(0); |
67 } | 67 } |
68 | 68 |
69 | 69 |
(...skipping 11 matching lines...) Expand all Loading... |
81 } | 81 } |
82 | 82 |
83 | 83 |
84 void LGapResolver::PerformMove(int index) { | 84 void LGapResolver::PerformMove(int index) { |
85 // Each call to this function performs a move and deletes it from the move | 85 // Each call to this function performs a move and deletes it from the move |
86 // graph. We first recursively perform any move blocking this one. We | 86 // graph. We first recursively perform any move blocking this one. We |
87 // mark a move as "pending" on entry to PerformMove in order to detect | 87 // mark a move as "pending" on entry to PerformMove in order to detect |
88 // cycles in the move graph. | 88 // cycles in the move graph. |
89 LMoveOperands& current_move = moves_[index]; | 89 LMoveOperands& current_move = moves_[index]; |
90 | 90 |
91 ASSERT(!current_move.IsPending()); | 91 DCHECK(!current_move.IsPending()); |
92 ASSERT(!current_move.IsRedundant()); | 92 DCHECK(!current_move.IsRedundant()); |
93 | 93 |
94 // Clear this move's destination to indicate a pending move. The actual | 94 // Clear this move's destination to indicate a pending move. The actual |
95 // destination is saved in a stack allocated local. Multiple moves can | 95 // destination is saved in a stack allocated local. Multiple moves can |
96 // be pending because this function is recursive. | 96 // be pending because this function is recursive. |
97 ASSERT(current_move.source() != NULL); // Otherwise it will look eliminated. | 97 DCHECK(current_move.source() != NULL); // Otherwise it will look eliminated. |
98 LOperand* destination = current_move.destination(); | 98 LOperand* destination = current_move.destination(); |
99 current_move.set_destination(NULL); | 99 current_move.set_destination(NULL); |
100 | 100 |
101 // Perform a depth-first traversal of the move graph to resolve | 101 // Perform a depth-first traversal of the move graph to resolve |
102 // dependencies. Any unperformed, unpending move with a source the same | 102 // dependencies. Any unperformed, unpending move with a source the same |
103 // as this one's destination blocks this one so recursively perform all | 103 // as this one's destination blocks this one so recursively perform all |
104 // such moves. | 104 // such moves. |
105 for (int i = 0; i < moves_.length(); ++i) { | 105 for (int i = 0; i < moves_.length(); ++i) { |
106 LMoveOperands other_move = moves_[i]; | 106 LMoveOperands other_move = moves_[i]; |
107 if (other_move.Blocks(destination) && !other_move.IsPending()) { | 107 if (other_move.Blocks(destination) && !other_move.IsPending()) { |
108 PerformMove(i); | 108 PerformMove(i); |
109 // If there is a blocking, pending move it must be moves_[root_index_] | 109 // If there is a blocking, pending move it must be moves_[root_index_] |
110 // and all other moves with the same source as moves_[root_index_] are | 110 // and all other moves with the same source as moves_[root_index_] are |
111 // sucessfully executed (because they are cycle-free) by this loop. | 111 // sucessfully executed (because they are cycle-free) by this loop. |
112 } | 112 } |
113 } | 113 } |
114 | 114 |
115 // We are about to resolve this move and don't need it marked as | 115 // We are about to resolve this move and don't need it marked as |
116 // pending, so restore its destination. | 116 // pending, so restore its destination. |
117 current_move.set_destination(destination); | 117 current_move.set_destination(destination); |
118 | 118 |
119 // The move may be blocked on a pending move, which must be the starting move. | 119 // The move may be blocked on a pending move, which must be the starting move. |
120 // In this case, we have a cycle, and we save the source of this move to | 120 // In this case, we have a cycle, and we save the source of this move to |
121 // a scratch register to break it. | 121 // a scratch register to break it. |
122 LMoveOperands other_move = moves_[root_index_]; | 122 LMoveOperands other_move = moves_[root_index_]; |
123 if (other_move.Blocks(destination)) { | 123 if (other_move.Blocks(destination)) { |
124 ASSERT(other_move.IsPending()); | 124 DCHECK(other_move.IsPending()); |
125 BreakCycle(index); | 125 BreakCycle(index); |
126 return; | 126 return; |
127 } | 127 } |
128 | 128 |
129 // This move is no longer blocked. | 129 // This move is no longer blocked. |
130 EmitMove(index); | 130 EmitMove(index); |
131 } | 131 } |
132 | 132 |
133 | 133 |
134 void LGapResolver::Verify() { | 134 void LGapResolver::Verify() { |
135 #ifdef ENABLE_SLOW_ASSERTS | 135 #ifdef ENABLE_SLOW_DCHECKS |
136 // No operand should be the destination for more than one move. | 136 // No operand should be the destination for more than one move. |
137 for (int i = 0; i < moves_.length(); ++i) { | 137 for (int i = 0; i < moves_.length(); ++i) { |
138 LOperand* destination = moves_[i].destination(); | 138 LOperand* destination = moves_[i].destination(); |
139 for (int j = i + 1; j < moves_.length(); ++j) { | 139 for (int j = i + 1; j < moves_.length(); ++j) { |
140 SLOW_ASSERT(!destination->Equals(moves_[j].destination())); | 140 SLOW_DCHECK(!destination->Equals(moves_[j].destination())); |
141 } | 141 } |
142 } | 142 } |
143 #endif | 143 #endif |
144 } | 144 } |
145 | 145 |
146 | 146 |
147 void LGapResolver::BreakCycle(int index) { | 147 void LGapResolver::BreakCycle(int index) { |
148 ASSERT(moves_[index].destination()->Equals(moves_[root_index_].source())); | 148 DCHECK(moves_[index].destination()->Equals(moves_[root_index_].source())); |
149 ASSERT(!in_cycle_); | 149 DCHECK(!in_cycle_); |
150 | 150 |
151 // 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 |
152 // 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 |
153 // broken and we can perform the other moves. | 153 // broken and we can perform the other moves. |
154 in_cycle_ = true; | 154 in_cycle_ = true; |
155 LOperand* source = moves_[index].source(); | 155 LOperand* source = moves_[index].source(); |
156 saved_destination_ = moves_[index].destination(); | 156 saved_destination_ = moves_[index].destination(); |
157 | 157 |
158 if (source->IsRegister()) { | 158 if (source->IsRegister()) { |
159 AcquireSavedValueRegister(); | 159 AcquireSavedValueRegister(); |
(...skipping 10 matching lines...) Expand all Loading... |
170 } | 170 } |
171 | 171 |
172 // Mark this move as resolved. | 172 // Mark this move as resolved. |
173 // 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 |
174 // move's destination in LGapResolver::RestoreValue(). | 174 // move's destination in LGapResolver::RestoreValue(). |
175 moves_[index].Eliminate(); | 175 moves_[index].Eliminate(); |
176 } | 176 } |
177 | 177 |
178 | 178 |
179 void LGapResolver::RestoreValue() { | 179 void LGapResolver::RestoreValue() { |
180 ASSERT(in_cycle_); | 180 DCHECK(in_cycle_); |
181 ASSERT(saved_destination_ != NULL); | 181 DCHECK(saved_destination_ != NULL); |
182 | 182 |
183 if (saved_destination_->IsRegister()) { | 183 if (saved_destination_->IsRegister()) { |
184 __ Mov(cgen_->ToRegister(saved_destination_), SavedValueRegister()); | 184 __ Mov(cgen_->ToRegister(saved_destination_), SavedValueRegister()); |
185 ReleaseSavedValueRegister(); | 185 ReleaseSavedValueRegister(); |
186 } else if (saved_destination_->IsStackSlot()) { | 186 } else if (saved_destination_->IsStackSlot()) { |
187 __ Store(SavedValueRegister(), cgen_->ToMemOperand(saved_destination_)); | 187 __ Store(SavedValueRegister(), cgen_->ToMemOperand(saved_destination_)); |
188 ReleaseSavedValueRegister(); | 188 ReleaseSavedValueRegister(); |
189 } else if (saved_destination_->IsDoubleRegister()) { | 189 } else if (saved_destination_->IsDoubleRegister()) { |
190 __ Fmov(cgen_->ToDoubleRegister(saved_destination_), | 190 __ Fmov(cgen_->ToDoubleRegister(saved_destination_), |
191 SavedFPValueRegister()); | 191 SavedFPValueRegister()); |
(...skipping 13 matching lines...) Expand all Loading... |
205 LOperand* destination = moves_[index].destination(); | 205 LOperand* destination = moves_[index].destination(); |
206 | 206 |
207 // Dispatch on the source and destination operand kinds. Not all | 207 // Dispatch on the source and destination operand kinds. Not all |
208 // combinations are possible. | 208 // combinations are possible. |
209 | 209 |
210 if (source->IsRegister()) { | 210 if (source->IsRegister()) { |
211 Register source_register = cgen_->ToRegister(source); | 211 Register source_register = cgen_->ToRegister(source); |
212 if (destination->IsRegister()) { | 212 if (destination->IsRegister()) { |
213 __ Mov(cgen_->ToRegister(destination), source_register); | 213 __ Mov(cgen_->ToRegister(destination), source_register); |
214 } else { | 214 } else { |
215 ASSERT(destination->IsStackSlot()); | 215 DCHECK(destination->IsStackSlot()); |
216 __ Store(source_register, cgen_->ToMemOperand(destination)); | 216 __ Store(source_register, cgen_->ToMemOperand(destination)); |
217 } | 217 } |
218 | 218 |
219 } else if (source->IsStackSlot()) { | 219 } else if (source->IsStackSlot()) { |
220 MemOperand source_operand = cgen_->ToMemOperand(source); | 220 MemOperand source_operand = cgen_->ToMemOperand(source); |
221 if (destination->IsRegister()) { | 221 if (destination->IsRegister()) { |
222 __ Load(cgen_->ToRegister(destination), source_operand); | 222 __ Load(cgen_->ToRegister(destination), source_operand); |
223 } else { | 223 } else { |
224 ASSERT(destination->IsStackSlot()); | 224 DCHECK(destination->IsStackSlot()); |
225 EmitStackSlotMove(index); | 225 EmitStackSlotMove(index); |
226 } | 226 } |
227 | 227 |
228 } else if (source->IsConstantOperand()) { | 228 } else if (source->IsConstantOperand()) { |
229 LConstantOperand* constant_source = LConstantOperand::cast(source); | 229 LConstantOperand* constant_source = LConstantOperand::cast(source); |
230 if (destination->IsRegister()) { | 230 if (destination->IsRegister()) { |
231 Register dst = cgen_->ToRegister(destination); | 231 Register dst = cgen_->ToRegister(destination); |
232 if (cgen_->IsSmi(constant_source)) { | 232 if (cgen_->IsSmi(constant_source)) { |
233 __ Mov(dst, cgen_->ToSmi(constant_source)); | 233 __ Mov(dst, cgen_->ToSmi(constant_source)); |
234 } else if (cgen_->IsInteger32Constant(constant_source)) { | 234 } else if (cgen_->IsInteger32Constant(constant_source)) { |
235 __ Mov(dst, cgen_->ToInteger32(constant_source)); | 235 __ Mov(dst, cgen_->ToInteger32(constant_source)); |
236 } else { | 236 } else { |
237 __ LoadObject(dst, cgen_->ToHandle(constant_source)); | 237 __ LoadObject(dst, cgen_->ToHandle(constant_source)); |
238 } | 238 } |
239 } else if (destination->IsDoubleRegister()) { | 239 } else if (destination->IsDoubleRegister()) { |
240 DoubleRegister result = cgen_->ToDoubleRegister(destination); | 240 DoubleRegister result = cgen_->ToDoubleRegister(destination); |
241 __ Fmov(result, cgen_->ToDouble(constant_source)); | 241 __ Fmov(result, cgen_->ToDouble(constant_source)); |
242 } else { | 242 } else { |
243 ASSERT(destination->IsStackSlot()); | 243 DCHECK(destination->IsStackSlot()); |
244 ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone. | 244 DCHECK(!in_cycle_); // Constant moves happen after all cycles are gone. |
245 if (cgen_->IsSmi(constant_source)) { | 245 if (cgen_->IsSmi(constant_source)) { |
246 Smi* smi = cgen_->ToSmi(constant_source); | 246 Smi* smi = cgen_->ToSmi(constant_source); |
247 __ StoreConstant(reinterpret_cast<intptr_t>(smi), | 247 __ StoreConstant(reinterpret_cast<intptr_t>(smi), |
248 cgen_->ToMemOperand(destination)); | 248 cgen_->ToMemOperand(destination)); |
249 } else if (cgen_->IsInteger32Constant(constant_source)) { | 249 } else if (cgen_->IsInteger32Constant(constant_source)) { |
250 __ StoreConstant(cgen_->ToInteger32(constant_source), | 250 __ StoreConstant(cgen_->ToInteger32(constant_source), |
251 cgen_->ToMemOperand(destination)); | 251 cgen_->ToMemOperand(destination)); |
252 } else { | 252 } else { |
253 Handle<Object> handle = cgen_->ToHandle(constant_source); | 253 Handle<Object> handle = cgen_->ToHandle(constant_source); |
254 AllowDeferredHandleDereference smi_object_check; | 254 AllowDeferredHandleDereference smi_object_check; |
255 if (handle->IsSmi()) { | 255 if (handle->IsSmi()) { |
256 Object* obj = *handle; | 256 Object* obj = *handle; |
257 ASSERT(!obj->IsHeapObject()); | 257 DCHECK(!obj->IsHeapObject()); |
258 __ StoreConstant(reinterpret_cast<intptr_t>(obj), | 258 __ StoreConstant(reinterpret_cast<intptr_t>(obj), |
259 cgen_->ToMemOperand(destination)); | 259 cgen_->ToMemOperand(destination)); |
260 } else { | 260 } else { |
261 AcquireSavedValueRegister(); | 261 AcquireSavedValueRegister(); |
262 __ LoadObject(SavedValueRegister(), handle); | 262 __ LoadObject(SavedValueRegister(), handle); |
263 __ Store(SavedValueRegister(), cgen_->ToMemOperand(destination)); | 263 __ Store(SavedValueRegister(), cgen_->ToMemOperand(destination)); |
264 ReleaseSavedValueRegister(); | 264 ReleaseSavedValueRegister(); |
265 } | 265 } |
266 } | 266 } |
267 } | 267 } |
268 | 268 |
269 } else if (source->IsDoubleRegister()) { | 269 } else if (source->IsDoubleRegister()) { |
270 DoubleRegister src = cgen_->ToDoubleRegister(source); | 270 DoubleRegister src = cgen_->ToDoubleRegister(source); |
271 if (destination->IsDoubleRegister()) { | 271 if (destination->IsDoubleRegister()) { |
272 __ Fmov(cgen_->ToDoubleRegister(destination), src); | 272 __ Fmov(cgen_->ToDoubleRegister(destination), src); |
273 } else { | 273 } else { |
274 ASSERT(destination->IsDoubleStackSlot()); | 274 DCHECK(destination->IsDoubleStackSlot()); |
275 __ Store(src, cgen_->ToMemOperand(destination)); | 275 __ Store(src, cgen_->ToMemOperand(destination)); |
276 } | 276 } |
277 | 277 |
278 } else if (source->IsDoubleStackSlot()) { | 278 } else if (source->IsDoubleStackSlot()) { |
279 MemOperand src = cgen_->ToMemOperand(source); | 279 MemOperand src = cgen_->ToMemOperand(source); |
280 if (destination->IsDoubleRegister()) { | 280 if (destination->IsDoubleRegister()) { |
281 __ Load(cgen_->ToDoubleRegister(destination), src); | 281 __ Load(cgen_->ToDoubleRegister(destination), src); |
282 } else { | 282 } else { |
283 ASSERT(destination->IsDoubleStackSlot()); | 283 DCHECK(destination->IsDoubleStackSlot()); |
284 EmitStackSlotMove(index); | 284 EmitStackSlotMove(index); |
285 } | 285 } |
286 | 286 |
287 } else { | 287 } else { |
288 UNREACHABLE(); | 288 UNREACHABLE(); |
289 } | 289 } |
290 | 290 |
291 // The move has been emitted, we can eliminate it. | 291 // The move has been emitted, we can eliminate it. |
292 moves_[index].Eliminate(); | 292 moves_[index].Eliminate(); |
293 } | 293 } |
294 | 294 |
295 } } // namespace v8::internal | 295 } } // namespace v8::internal |
OLD | NEW |