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