| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/x64/lithium-codegen-x64.h" | 9 #include "src/x64/lithium-codegen-x64.h" |
| 10 #include "src/x64/lithium-gap-resolver-x64.h" | 10 #include "src/x64/lithium-gap-resolver-x64.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 LGapResolver::LGapResolver(LCodeGen* owner) | 15 LGapResolver::LGapResolver(LCodeGen* owner) |
| 16 : cgen_(owner), moves_(32, owner->zone()) {} | 16 : cgen_(owner), moves_(32, owner->zone()) {} |
| 17 | 17 |
| 18 | 18 |
| 19 void LGapResolver::Resolve(LParallelMove* parallel_move) { | 19 void LGapResolver::Resolve(LParallelMove* parallel_move) { |
| 20 ASSERT(moves_.is_empty()); | 20 DCHECK(moves_.is_empty()); |
| 21 // Build up a worklist of moves. | 21 // Build up a worklist of moves. |
| 22 BuildInitialMoveList(parallel_move); | 22 BuildInitialMoveList(parallel_move); |
| 23 | 23 |
| 24 for (int i = 0; i < moves_.length(); ++i) { | 24 for (int i = 0; i < moves_.length(); ++i) { |
| 25 LMoveOperands move = moves_[i]; | 25 LMoveOperands move = moves_[i]; |
| 26 // Skip constants to perform them last. They don't block other moves | 26 // Skip constants to perform them last. They don't block other moves |
| 27 // and skipping such moves with register destinations keeps those | 27 // and skipping such moves with register destinations keeps those |
| 28 // registers free for the whole algorithm. | 28 // registers free for the whole algorithm. |
| 29 if (!move.IsEliminated() && !move.source()->IsConstantOperand()) { | 29 if (!move.IsEliminated() && !move.source()->IsConstantOperand()) { |
| 30 PerformMove(i); | 30 PerformMove(i); |
| 31 } | 31 } |
| 32 } | 32 } |
| 33 | 33 |
| 34 // Perform the moves with constant sources. | 34 // Perform the moves with constant sources. |
| 35 for (int i = 0; i < moves_.length(); ++i) { | 35 for (int i = 0; i < moves_.length(); ++i) { |
| 36 if (!moves_[i].IsEliminated()) { | 36 if (!moves_[i].IsEliminated()) { |
| 37 ASSERT(moves_[i].source()->IsConstantOperand()); | 37 DCHECK(moves_[i].source()->IsConstantOperand()); |
| 38 EmitMove(i); | 38 EmitMove(i); |
| 39 } | 39 } |
| 40 } | 40 } |
| 41 | 41 |
| 42 moves_.Rewind(0); | 42 moves_.Rewind(0); |
| 43 } | 43 } |
| 44 | 44 |
| 45 | 45 |
| 46 void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) { | 46 void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) { |
| 47 // Perform a linear sweep of the moves to add them to the initial list of | 47 // Perform a linear sweep of the moves to add them to the initial list of |
| (...skipping 10 matching lines...) Expand all Loading... |
| 58 | 58 |
| 59 | 59 |
| 60 void LGapResolver::PerformMove(int index) { | 60 void LGapResolver::PerformMove(int index) { |
| 61 // Each call to this function performs a move and deletes it from the move | 61 // Each call to this function performs a move and deletes it from the move |
| 62 // graph. We first recursively perform any move blocking this one. We | 62 // graph. We first recursively perform any move blocking this one. We |
| 63 // mark a move as "pending" on entry to PerformMove in order to detect | 63 // mark a move as "pending" on entry to PerformMove in order to detect |
| 64 // cycles in the move graph. We use operand swaps to resolve cycles, | 64 // cycles in the move graph. We use operand swaps to resolve cycles, |
| 65 // which means that a call to PerformMove could change any source operand | 65 // which means that a call to PerformMove could change any source operand |
| 66 // in the move graph. | 66 // in the move graph. |
| 67 | 67 |
| 68 ASSERT(!moves_[index].IsPending()); | 68 DCHECK(!moves_[index].IsPending()); |
| 69 ASSERT(!moves_[index].IsRedundant()); | 69 DCHECK(!moves_[index].IsRedundant()); |
| 70 | 70 |
| 71 // Clear this move's destination to indicate a pending move. The actual | 71 // Clear this move's destination to indicate a pending move. The actual |
| 72 // destination is saved in a stack-allocated local. Recursion may allow | 72 // destination is saved in a stack-allocated local. Recursion may allow |
| 73 // multiple moves to be pending. | 73 // multiple moves to be pending. |
| 74 ASSERT(moves_[index].source() != NULL); // Or else it will look eliminated. | 74 DCHECK(moves_[index].source() != NULL); // Or else it will look eliminated. |
| 75 LOperand* destination = moves_[index].destination(); | 75 LOperand* destination = moves_[index].destination(); |
| 76 moves_[index].set_destination(NULL); | 76 moves_[index].set_destination(NULL); |
| 77 | 77 |
| 78 // Perform a depth-first traversal of the move graph to resolve | 78 // Perform a depth-first traversal of the move graph to resolve |
| 79 // dependencies. Any unperformed, unpending move with a source the same | 79 // dependencies. Any unperformed, unpending move with a source the same |
| 80 // as this one's destination blocks this one so recursively perform all | 80 // as this one's destination blocks this one so recursively perform all |
| 81 // such moves. | 81 // such moves. |
| 82 for (int i = 0; i < moves_.length(); ++i) { | 82 for (int i = 0; i < moves_.length(); ++i) { |
| 83 LMoveOperands other_move = moves_[i]; | 83 LMoveOperands other_move = moves_[i]; |
| 84 if (other_move.Blocks(destination) && !other_move.IsPending()) { | 84 if (other_move.Blocks(destination) && !other_move.IsPending()) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 105 moves_[index].Eliminate(); | 105 moves_[index].Eliminate(); |
| 106 return; | 106 return; |
| 107 } | 107 } |
| 108 | 108 |
| 109 // The move may be blocked on a (at most one) pending move, in which case | 109 // The move may be blocked on a (at most one) pending move, in which case |
| 110 // we have a cycle. Search for such a blocking move and perform a swap to | 110 // we have a cycle. Search for such a blocking move and perform a swap to |
| 111 // resolve it. | 111 // resolve it. |
| 112 for (int i = 0; i < moves_.length(); ++i) { | 112 for (int i = 0; i < moves_.length(); ++i) { |
| 113 LMoveOperands other_move = moves_[i]; | 113 LMoveOperands other_move = moves_[i]; |
| 114 if (other_move.Blocks(destination)) { | 114 if (other_move.Blocks(destination)) { |
| 115 ASSERT(other_move.IsPending()); | 115 DCHECK(other_move.IsPending()); |
| 116 EmitSwap(index); | 116 EmitSwap(index); |
| 117 return; | 117 return; |
| 118 } | 118 } |
| 119 } | 119 } |
| 120 | 120 |
| 121 // This move is not blocked. | 121 // This move is not blocked. |
| 122 EmitMove(index); | 122 EmitMove(index); |
| 123 } | 123 } |
| 124 | 124 |
| 125 | 125 |
| 126 void LGapResolver::Verify() { | 126 void LGapResolver::Verify() { |
| 127 #ifdef ENABLE_SLOW_ASSERTS | 127 #ifdef ENABLE_SLOW_DCHECKS |
| 128 // No operand should be the destination for more than one move. | 128 // No operand should be the destination for more than one move. |
| 129 for (int i = 0; i < moves_.length(); ++i) { | 129 for (int i = 0; i < moves_.length(); ++i) { |
| 130 LOperand* destination = moves_[i].destination(); | 130 LOperand* destination = moves_[i].destination(); |
| 131 for (int j = i + 1; j < moves_.length(); ++j) { | 131 for (int j = i + 1; j < moves_.length(); ++j) { |
| 132 SLOW_ASSERT(!destination->Equals(moves_[j].destination())); | 132 SLOW_DCHECK(!destination->Equals(moves_[j].destination())); |
| 133 } | 133 } |
| 134 } | 134 } |
| 135 #endif | 135 #endif |
| 136 } | 136 } |
| 137 | 137 |
| 138 | 138 |
| 139 #define __ ACCESS_MASM(cgen_->masm()) | 139 #define __ ACCESS_MASM(cgen_->masm()) |
| 140 | 140 |
| 141 | 141 |
| 142 void LGapResolver::EmitMove(int index) { | 142 void LGapResolver::EmitMove(int index) { |
| 143 LOperand* source = moves_[index].source(); | 143 LOperand* source = moves_[index].source(); |
| 144 LOperand* destination = moves_[index].destination(); | 144 LOperand* destination = moves_[index].destination(); |
| 145 | 145 |
| 146 // Dispatch on the source and destination operand kinds. Not all | 146 // Dispatch on the source and destination operand kinds. Not all |
| 147 // combinations are possible. | 147 // combinations are possible. |
| 148 if (source->IsRegister()) { | 148 if (source->IsRegister()) { |
| 149 Register src = cgen_->ToRegister(source); | 149 Register src = cgen_->ToRegister(source); |
| 150 if (destination->IsRegister()) { | 150 if (destination->IsRegister()) { |
| 151 Register dst = cgen_->ToRegister(destination); | 151 Register dst = cgen_->ToRegister(destination); |
| 152 __ movp(dst, src); | 152 __ movp(dst, src); |
| 153 } else { | 153 } else { |
| 154 ASSERT(destination->IsStackSlot()); | 154 DCHECK(destination->IsStackSlot()); |
| 155 Operand dst = cgen_->ToOperand(destination); | 155 Operand dst = cgen_->ToOperand(destination); |
| 156 __ movp(dst, src); | 156 __ movp(dst, src); |
| 157 } | 157 } |
| 158 | 158 |
| 159 } else if (source->IsStackSlot()) { | 159 } else if (source->IsStackSlot()) { |
| 160 Operand src = cgen_->ToOperand(source); | 160 Operand src = cgen_->ToOperand(source); |
| 161 if (destination->IsRegister()) { | 161 if (destination->IsRegister()) { |
| 162 Register dst = cgen_->ToRegister(destination); | 162 Register dst = cgen_->ToRegister(destination); |
| 163 __ movp(dst, src); | 163 __ movp(dst, src); |
| 164 } else { | 164 } else { |
| 165 ASSERT(destination->IsStackSlot()); | 165 DCHECK(destination->IsStackSlot()); |
| 166 Operand dst = cgen_->ToOperand(destination); | 166 Operand dst = cgen_->ToOperand(destination); |
| 167 __ movp(kScratchRegister, src); | 167 __ movp(kScratchRegister, src); |
| 168 __ movp(dst, kScratchRegister); | 168 __ movp(dst, kScratchRegister); |
| 169 } | 169 } |
| 170 | 170 |
| 171 } else if (source->IsConstantOperand()) { | 171 } else if (source->IsConstantOperand()) { |
| 172 LConstantOperand* constant_source = LConstantOperand::cast(source); | 172 LConstantOperand* constant_source = LConstantOperand::cast(source); |
| 173 if (destination->IsRegister()) { | 173 if (destination->IsRegister()) { |
| 174 Register dst = cgen_->ToRegister(destination); | 174 Register dst = cgen_->ToRegister(destination); |
| 175 if (cgen_->IsSmiConstant(constant_source)) { | 175 if (cgen_->IsSmiConstant(constant_source)) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 190 double v = cgen_->ToDouble(constant_source); | 190 double v = cgen_->ToDouble(constant_source); |
| 191 uint64_t int_val = BitCast<uint64_t, double>(v); | 191 uint64_t int_val = BitCast<uint64_t, double>(v); |
| 192 XMMRegister dst = cgen_->ToDoubleRegister(destination); | 192 XMMRegister dst = cgen_->ToDoubleRegister(destination); |
| 193 if (int_val == 0) { | 193 if (int_val == 0) { |
| 194 __ xorps(dst, dst); | 194 __ xorps(dst, dst); |
| 195 } else { | 195 } else { |
| 196 __ Set(kScratchRegister, int_val); | 196 __ Set(kScratchRegister, int_val); |
| 197 __ movq(dst, kScratchRegister); | 197 __ movq(dst, kScratchRegister); |
| 198 } | 198 } |
| 199 } else { | 199 } else { |
| 200 ASSERT(destination->IsStackSlot()); | 200 DCHECK(destination->IsStackSlot()); |
| 201 Operand dst = cgen_->ToOperand(destination); | 201 Operand dst = cgen_->ToOperand(destination); |
| 202 if (cgen_->IsSmiConstant(constant_source)) { | 202 if (cgen_->IsSmiConstant(constant_source)) { |
| 203 __ Move(dst, cgen_->ToSmi(constant_source)); | 203 __ Move(dst, cgen_->ToSmi(constant_source)); |
| 204 } else if (cgen_->IsInteger32Constant(constant_source)) { | 204 } else if (cgen_->IsInteger32Constant(constant_source)) { |
| 205 // Do sign extension to 64 bits when stored into stack slot. | 205 // Do sign extension to 64 bits when stored into stack slot. |
| 206 __ movp(dst, Immediate(cgen_->ToInteger32(constant_source))); | 206 __ movp(dst, Immediate(cgen_->ToInteger32(constant_source))); |
| 207 } else { | 207 } else { |
| 208 __ Move(kScratchRegister, cgen_->ToHandle(constant_source)); | 208 __ Move(kScratchRegister, cgen_->ToHandle(constant_source)); |
| 209 __ movp(dst, kScratchRegister); | 209 __ movp(dst, kScratchRegister); |
| 210 } | 210 } |
| 211 } | 211 } |
| 212 | 212 |
| 213 } else if (source->IsDoubleRegister()) { | 213 } else if (source->IsDoubleRegister()) { |
| 214 XMMRegister src = cgen_->ToDoubleRegister(source); | 214 XMMRegister src = cgen_->ToDoubleRegister(source); |
| 215 if (destination->IsDoubleRegister()) { | 215 if (destination->IsDoubleRegister()) { |
| 216 __ movaps(cgen_->ToDoubleRegister(destination), src); | 216 __ movaps(cgen_->ToDoubleRegister(destination), src); |
| 217 } else { | 217 } else { |
| 218 ASSERT(destination->IsDoubleStackSlot()); | 218 DCHECK(destination->IsDoubleStackSlot()); |
| 219 __ movsd(cgen_->ToOperand(destination), src); | 219 __ movsd(cgen_->ToOperand(destination), src); |
| 220 } | 220 } |
| 221 } else if (source->IsDoubleStackSlot()) { | 221 } else if (source->IsDoubleStackSlot()) { |
| 222 Operand src = cgen_->ToOperand(source); | 222 Operand src = cgen_->ToOperand(source); |
| 223 if (destination->IsDoubleRegister()) { | 223 if (destination->IsDoubleRegister()) { |
| 224 __ movsd(cgen_->ToDoubleRegister(destination), src); | 224 __ movsd(cgen_->ToDoubleRegister(destination), src); |
| 225 } else { | 225 } else { |
| 226 ASSERT(destination->IsDoubleStackSlot()); | 226 DCHECK(destination->IsDoubleStackSlot()); |
| 227 __ movsd(xmm0, src); | 227 __ movsd(xmm0, src); |
| 228 __ movsd(cgen_->ToOperand(destination), xmm0); | 228 __ movsd(cgen_->ToOperand(destination), xmm0); |
| 229 } | 229 } |
| 230 } else { | 230 } else { |
| 231 UNREACHABLE(); | 231 UNREACHABLE(); |
| 232 } | 232 } |
| 233 | 233 |
| 234 moves_[index].Eliminate(); | 234 moves_[index].Eliminate(); |
| 235 } | 235 } |
| 236 | 236 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) { | 271 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) { |
| 272 // Swap two double registers. | 272 // Swap two double registers. |
| 273 XMMRegister source_reg = cgen_->ToDoubleRegister(source); | 273 XMMRegister source_reg = cgen_->ToDoubleRegister(source); |
| 274 XMMRegister destination_reg = cgen_->ToDoubleRegister(destination); | 274 XMMRegister destination_reg = cgen_->ToDoubleRegister(destination); |
| 275 __ movaps(xmm0, source_reg); | 275 __ movaps(xmm0, source_reg); |
| 276 __ movaps(source_reg, destination_reg); | 276 __ movaps(source_reg, destination_reg); |
| 277 __ movaps(destination_reg, xmm0); | 277 __ movaps(destination_reg, xmm0); |
| 278 | 278 |
| 279 } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) { | 279 } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) { |
| 280 // Swap a double register and a double stack slot. | 280 // Swap a double register and a double stack slot. |
| 281 ASSERT((source->IsDoubleRegister() && destination->IsDoubleStackSlot()) || | 281 DCHECK((source->IsDoubleRegister() && destination->IsDoubleStackSlot()) || |
| 282 (source->IsDoubleStackSlot() && destination->IsDoubleRegister())); | 282 (source->IsDoubleStackSlot() && destination->IsDoubleRegister())); |
| 283 XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister() | 283 XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister() |
| 284 ? source | 284 ? source |
| 285 : destination); | 285 : destination); |
| 286 LOperand* other = source->IsDoubleRegister() ? destination : source; | 286 LOperand* other = source->IsDoubleRegister() ? destination : source; |
| 287 ASSERT(other->IsDoubleStackSlot()); | 287 DCHECK(other->IsDoubleStackSlot()); |
| 288 Operand other_operand = cgen_->ToOperand(other); | 288 Operand other_operand = cgen_->ToOperand(other); |
| 289 __ movsd(xmm0, other_operand); | 289 __ movsd(xmm0, other_operand); |
| 290 __ movsd(other_operand, reg); | 290 __ movsd(other_operand, reg); |
| 291 __ movaps(reg, xmm0); | 291 __ movaps(reg, xmm0); |
| 292 | 292 |
| 293 } else { | 293 } else { |
| 294 // No other combinations are possible. | 294 // No other combinations are possible. |
| 295 UNREACHABLE(); | 295 UNREACHABLE(); |
| 296 } | 296 } |
| 297 | 297 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 310 moves_[i].set_source(source); | 310 moves_[i].set_source(source); |
| 311 } | 311 } |
| 312 } | 312 } |
| 313 } | 313 } |
| 314 | 314 |
| 315 #undef __ | 315 #undef __ |
| 316 | 316 |
| 317 } } // namespace v8::internal | 317 } } // namespace v8::internal |
| 318 | 318 |
| 319 #endif // V8_TARGET_ARCH_X64 | 319 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |