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/crankshaft/arm64/lithium-codegen-arm64.h" | 5 #include "src/crankshaft/arm64/lithium-codegen-arm64.h" |
6 | 6 |
7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
8 #include "src/arm64/macro-assembler-arm64-inl.h" | 8 #include "src/arm64/macro-assembler-arm64-inl.h" |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/builtins/builtins-constructor.h" | 10 #include "src/builtins/builtins-constructor.h" |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 private: | 172 private: |
173 Condition cond_; | 173 Condition cond_; |
174 const Register& value_; | 174 const Register& value_; |
175 uint64_t mask_; | 175 uint64_t mask_; |
176 }; | 176 }; |
177 | 177 |
178 | 178 |
179 // Test the input and branch if it is non-zero and not a NaN. | 179 // Test the input and branch if it is non-zero and not a NaN. |
180 class BranchIfNonZeroNumber : public BranchGenerator { | 180 class BranchIfNonZeroNumber : public BranchGenerator { |
181 public: | 181 public: |
182 BranchIfNonZeroNumber(LCodeGen* codegen, const FPRegister& value, | 182 BranchIfNonZeroNumber(LCodeGen* codegen, const VRegister& value, |
183 const FPRegister& scratch) | 183 const VRegister& scratch) |
184 : BranchGenerator(codegen), value_(value), scratch_(scratch) { } | 184 : BranchGenerator(codegen), value_(value), scratch_(scratch) {} |
185 | 185 |
186 virtual void Emit(Label* label) const { | 186 virtual void Emit(Label* label) const { |
187 __ Fabs(scratch_, value_); | 187 __ Fabs(scratch_, value_); |
188 // Compare with 0.0. Because scratch_ is positive, the result can be one of | 188 // Compare with 0.0. Because scratch_ is positive, the result can be one of |
189 // nZCv (equal), nzCv (greater) or nzCV (unordered). | 189 // nZCv (equal), nzCv (greater) or nzCV (unordered). |
190 __ Fcmp(scratch_, 0.0); | 190 __ Fcmp(scratch_, 0.0); |
191 __ B(gt, label); | 191 __ B(gt, label); |
192 } | 192 } |
193 | 193 |
194 virtual void EmitInverted(Label* label) const { | 194 virtual void EmitInverted(Label* label) const { |
195 __ Fabs(scratch_, value_); | 195 __ Fabs(scratch_, value_); |
196 __ Fcmp(scratch_, 0.0); | 196 __ Fcmp(scratch_, 0.0); |
197 __ B(le, label); | 197 __ B(le, label); |
198 } | 198 } |
199 | 199 |
200 private: | 200 private: |
201 const FPRegister& value_; | 201 const VRegister& value_; |
202 const FPRegister& scratch_; | 202 const VRegister& scratch_; |
203 }; | 203 }; |
204 | 204 |
205 | 205 |
206 // Test the input and branch if it is a heap number. | 206 // Test the input and branch if it is a heap number. |
207 class BranchIfHeapNumber : public BranchGenerator { | 207 class BranchIfHeapNumber : public BranchGenerator { |
208 public: | 208 public: |
209 BranchIfHeapNumber(LCodeGen* codegen, const Register& value) | 209 BranchIfHeapNumber(LCodeGen* codegen, const Register& value) |
210 : BranchGenerator(codegen), value_(value) { } | 210 : BranchGenerator(codegen), value_(value) { } |
211 | 211 |
212 virtual void Emit(Label* label) const { | 212 virtual void Emit(Label* label) const { |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 void LCodeGen::SaveCallerDoubles() { | 540 void LCodeGen::SaveCallerDoubles() { |
541 DCHECK(info()->saves_caller_doubles()); | 541 DCHECK(info()->saves_caller_doubles()); |
542 DCHECK(NeedsEagerFrame()); | 542 DCHECK(NeedsEagerFrame()); |
543 Comment(";;; Save clobbered callee double registers"); | 543 Comment(";;; Save clobbered callee double registers"); |
544 BitVector* doubles = chunk()->allocated_double_registers(); | 544 BitVector* doubles = chunk()->allocated_double_registers(); |
545 BitVector::Iterator iterator(doubles); | 545 BitVector::Iterator iterator(doubles); |
546 int count = 0; | 546 int count = 0; |
547 while (!iterator.Done()) { | 547 while (!iterator.Done()) { |
548 // TODO(all): Is this supposed to save just the callee-saved doubles? It | 548 // TODO(all): Is this supposed to save just the callee-saved doubles? It |
549 // looks like it's saving all of them. | 549 // looks like it's saving all of them. |
550 FPRegister value = FPRegister::from_code(iterator.Current()); | 550 VRegister value = VRegister::from_code(iterator.Current()); |
551 __ Poke(value, count * kDoubleSize); | 551 __ Poke(value, count * kDoubleSize); |
552 iterator.Advance(); | 552 iterator.Advance(); |
553 count++; | 553 count++; |
554 } | 554 } |
555 } | 555 } |
556 | 556 |
557 | 557 |
558 void LCodeGen::RestoreCallerDoubles() { | 558 void LCodeGen::RestoreCallerDoubles() { |
559 DCHECK(info()->saves_caller_doubles()); | 559 DCHECK(info()->saves_caller_doubles()); |
560 DCHECK(NeedsEagerFrame()); | 560 DCHECK(NeedsEagerFrame()); |
561 Comment(";;; Restore clobbered callee double registers"); | 561 Comment(";;; Restore clobbered callee double registers"); |
562 BitVector* doubles = chunk()->allocated_double_registers(); | 562 BitVector* doubles = chunk()->allocated_double_registers(); |
563 BitVector::Iterator iterator(doubles); | 563 BitVector::Iterator iterator(doubles); |
564 int count = 0; | 564 int count = 0; |
565 while (!iterator.Done()) { | 565 while (!iterator.Done()) { |
566 // TODO(all): Is this supposed to restore just the callee-saved doubles? It | 566 // TODO(all): Is this supposed to restore just the callee-saved doubles? It |
567 // looks like it's restoring all of them. | 567 // looks like it's restoring all of them. |
568 FPRegister value = FPRegister::from_code(iterator.Current()); | 568 VRegister value = VRegister::from_code(iterator.Current()); |
569 __ Peek(value, count * kDoubleSize); | 569 __ Peek(value, count * kDoubleSize); |
570 iterator.Advance(); | 570 iterator.Advance(); |
571 count++; | 571 count++; |
572 } | 572 } |
573 } | 573 } |
574 | 574 |
575 | 575 |
576 bool LCodeGen::GeneratePrologue() { | 576 bool LCodeGen::GeneratePrologue() { |
577 DCHECK(is_generating()); | 577 DCHECK(is_generating()); |
578 | 578 |
(...skipping 549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1128 // references the end of the double registers and not the end of the stack | 1128 // references the end of the double registers and not the end of the stack |
1129 // slots. | 1129 // slots. |
1130 // In both of the cases above, we _could_ add the tracking information | 1130 // In both of the cases above, we _could_ add the tracking information |
1131 // required so that we can use jssp here, but in practice it isn't worth it. | 1131 // required so that we can use jssp here, but in practice it isn't worth it. |
1132 if ((stack_mode == kCanUseStackPointer) && | 1132 if ((stack_mode == kCanUseStackPointer) && |
1133 !info()->saves_caller_doubles()) { | 1133 !info()->saves_caller_doubles()) { |
1134 int jssp_offset_to_fp = | 1134 int jssp_offset_to_fp = |
1135 (pushed_arguments_ + GetTotalFrameSlotCount()) * kPointerSize - | 1135 (pushed_arguments_ + GetTotalFrameSlotCount()) * kPointerSize - |
1136 StandardFrameConstants::kFixedFrameSizeAboveFp; | 1136 StandardFrameConstants::kFixedFrameSizeAboveFp; |
1137 int jssp_offset = fp_offset + jssp_offset_to_fp; | 1137 int jssp_offset = fp_offset + jssp_offset_to_fp; |
1138 if (masm()->IsImmLSScaled(jssp_offset, LSDoubleWord)) { | 1138 if (masm()->IsImmLSScaled(jssp_offset, kPointerSizeLog2)) { |
1139 return MemOperand(masm()->StackPointer(), jssp_offset); | 1139 return MemOperand(masm()->StackPointer(), jssp_offset); |
1140 } | 1140 } |
1141 } | 1141 } |
1142 return MemOperand(fp, fp_offset); | 1142 return MemOperand(fp, fp_offset); |
1143 } else { | 1143 } else { |
1144 // Retrieve parameter without eager stack-frame relative to the | 1144 // Retrieve parameter without eager stack-frame relative to the |
1145 // stack-pointer. | 1145 // stack-pointer. |
1146 return MemOperand(masm()->StackPointer(), | 1146 return MemOperand(masm()->StackPointer(), |
1147 ArgumentsOffsetWithoutFrame(op->index())); | 1147 ArgumentsOffsetWithoutFrame(op->index())); |
1148 } | 1148 } |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1267 template<class InstrType> | 1267 template<class InstrType> |
1268 void LCodeGen::EmitTestAndBranch(InstrType instr, | 1268 void LCodeGen::EmitTestAndBranch(InstrType instr, |
1269 Condition condition, | 1269 Condition condition, |
1270 const Register& value, | 1270 const Register& value, |
1271 uint64_t mask) { | 1271 uint64_t mask) { |
1272 DCHECK((condition != al) && (condition != nv)); | 1272 DCHECK((condition != al) && (condition != nv)); |
1273 TestAndBranch branch(this, condition, value, mask); | 1273 TestAndBranch branch(this, condition, value, mask); |
1274 EmitBranchGeneric(instr, branch); | 1274 EmitBranchGeneric(instr, branch); |
1275 } | 1275 } |
1276 | 1276 |
1277 | 1277 template <class InstrType> |
1278 template<class InstrType> | |
1279 void LCodeGen::EmitBranchIfNonZeroNumber(InstrType instr, | 1278 void LCodeGen::EmitBranchIfNonZeroNumber(InstrType instr, |
1280 const FPRegister& value, | 1279 const VRegister& value, |
1281 const FPRegister& scratch) { | 1280 const VRegister& scratch) { |
1282 BranchIfNonZeroNumber branch(this, value, scratch); | 1281 BranchIfNonZeroNumber branch(this, value, scratch); |
1283 EmitBranchGeneric(instr, branch); | 1282 EmitBranchGeneric(instr, branch); |
1284 } | 1283 } |
1285 | 1284 |
1286 | 1285 |
1287 template<class InstrType> | 1286 template<class InstrType> |
1288 void LCodeGen::EmitBranchIfHeapNumber(InstrType instr, | 1287 void LCodeGen::EmitBranchIfHeapNumber(InstrType instr, |
1289 const Register& value) { | 1288 const Register& value) { |
1290 BranchIfHeapNumber branch(this, value); | 1289 BranchIfHeapNumber branch(this, value); |
1291 EmitBranchGeneric(instr, branch); | 1290 EmitBranchGeneric(instr, branch); |
(...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2272 // The name in the constructor is internalized because of the way the context | 2271 // The name in the constructor is internalized because of the way the context |
2273 // is booted. This routine isn't expected to work for random API-created | 2272 // is booted. This routine isn't expected to work for random API-created |
2274 // classes and it doesn't have to because you can't access it with natives | 2273 // classes and it doesn't have to because you can't access it with natives |
2275 // syntax. Since both sides are internalized it is sufficient to use an | 2274 // syntax. Since both sides are internalized it is sufficient to use an |
2276 // identity comparison. | 2275 // identity comparison. |
2277 EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); | 2276 EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); |
2278 } | 2277 } |
2279 | 2278 |
2280 void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) { | 2279 void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) { |
2281 DCHECK(instr->hydrogen()->representation().IsDouble()); | 2280 DCHECK(instr->hydrogen()->representation().IsDouble()); |
2282 FPRegister object = ToDoubleRegister(instr->object()); | 2281 VRegister object = ToDoubleRegister(instr->object()); |
2283 Register temp = ToRegister(instr->temp()); | 2282 Register temp = ToRegister(instr->temp()); |
2284 | 2283 |
2285 // If we don't have a NaN, we don't have the hole, so branch now to avoid the | 2284 // If we don't have a NaN, we don't have the hole, so branch now to avoid the |
2286 // (relatively expensive) hole-NaN check. | 2285 // (relatively expensive) hole-NaN check. |
2287 __ Fcmp(object, object); | 2286 __ Fcmp(object, object); |
2288 __ B(vc, instr->FalseLabel(chunk_)); | 2287 __ B(vc, instr->FalseLabel(chunk_)); |
2289 | 2288 |
2290 // We have a NaN, but is it the hole? | 2289 // We have a NaN, but is it the hole? |
2291 __ Fmov(temp, object); | 2290 __ Fmov(temp, object); |
2292 EmitCompareAndBranch(instr, eq, temp, kHoleNanInt64); | 2291 EmitCompareAndBranch(instr, eq, temp, kHoleNanInt64); |
(...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3269 Register object = ToRegister(instr->object()); | 3268 Register object = ToRegister(instr->object()); |
3270 | 3269 |
3271 if (access.IsExternalMemory()) { | 3270 if (access.IsExternalMemory()) { |
3272 Register result = ToRegister(instr->result()); | 3271 Register result = ToRegister(instr->result()); |
3273 __ Load(result, MemOperand(object, offset), access.representation()); | 3272 __ Load(result, MemOperand(object, offset), access.representation()); |
3274 return; | 3273 return; |
3275 } | 3274 } |
3276 | 3275 |
3277 if (instr->hydrogen()->representation().IsDouble()) { | 3276 if (instr->hydrogen()->representation().IsDouble()) { |
3278 DCHECK(access.IsInobject()); | 3277 DCHECK(access.IsInobject()); |
3279 FPRegister result = ToDoubleRegister(instr->result()); | 3278 VRegister result = ToDoubleRegister(instr->result()); |
3280 __ Ldr(result, FieldMemOperand(object, offset)); | 3279 __ Ldr(result, FieldMemOperand(object, offset)); |
3281 return; | 3280 return; |
3282 } | 3281 } |
3283 | 3282 |
3284 Register result = ToRegister(instr->result()); | 3283 Register result = ToRegister(instr->result()); |
3285 Register source; | 3284 Register source; |
3286 if (access.IsInobject()) { | 3285 if (access.IsInobject()) { |
3287 source = object; | 3286 source = object; |
3288 } else { | 3287 } else { |
3289 // Load the properties array, using result as a scratch register. | 3288 // Load the properties array, using result as a scratch register. |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3429 // never get set by the negation. This is therefore the same as the Integer32 | 3428 // never get set by the negation. This is therefore the same as the Integer32 |
3430 // case in DoMathAbs, except that it operates on 64-bit values. | 3429 // case in DoMathAbs, except that it operates on 64-bit values. |
3431 STATIC_ASSERT((kSmiValueSize == 32) && (kSmiShift == 32) && (kSmiTag == 0)); | 3430 STATIC_ASSERT((kSmiValueSize == 32) && (kSmiShift == 32) && (kSmiTag == 0)); |
3432 | 3431 |
3433 __ JumpIfNotSmi(input, deferred->entry()); | 3432 __ JumpIfNotSmi(input, deferred->entry()); |
3434 | 3433 |
3435 __ Abs(result, input, NULL, &done); | 3434 __ Abs(result, input, NULL, &done); |
3436 | 3435 |
3437 // The result is the magnitude (abs) of the smallest value a smi can | 3436 // The result is the magnitude (abs) of the smallest value a smi can |
3438 // represent, encoded as a double. | 3437 // represent, encoded as a double. |
3439 __ Mov(result_bits, double_to_rawbits(0x80000000)); | 3438 __ Mov(result_bits, bit_cast<uint64_t>(static_cast<double>(0x80000000))); |
3440 __ B(deferred->allocation_entry()); | 3439 __ B(deferred->allocation_entry()); |
3441 | 3440 |
3442 __ Bind(deferred->exit()); | 3441 __ Bind(deferred->exit()); |
3443 __ Str(result_bits, FieldMemOperand(result, HeapNumber::kValueOffset)); | 3442 __ Str(result_bits, FieldMemOperand(result, HeapNumber::kValueOffset)); |
3444 | 3443 |
3445 __ Bind(&done); | 3444 __ Bind(&done); |
3446 } | 3445 } |
3447 | 3446 |
3448 void LCodeGen::DoMathCos(LMathCos* instr) { | 3447 void LCodeGen::DoMathCos(LMathCos* instr) { |
3449 DCHECK(instr->IsMarkedAsCall()); | 3448 DCHECK(instr->IsMarkedAsCall()); |
(...skipping 1521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4971 __ Store(value, MemOperand(object, offset), representation); | 4970 __ Store(value, MemOperand(object, offset), representation); |
4972 return; | 4971 return; |
4973 } | 4972 } |
4974 | 4973 |
4975 __ AssertNotSmi(object); | 4974 __ AssertNotSmi(object); |
4976 | 4975 |
4977 if (!FLAG_unbox_double_fields && representation.IsDouble()) { | 4976 if (!FLAG_unbox_double_fields && representation.IsDouble()) { |
4978 DCHECK(access.IsInobject()); | 4977 DCHECK(access.IsInobject()); |
4979 DCHECK(!instr->hydrogen()->has_transition()); | 4978 DCHECK(!instr->hydrogen()->has_transition()); |
4980 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); | 4979 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); |
4981 FPRegister value = ToDoubleRegister(instr->value()); | 4980 VRegister value = ToDoubleRegister(instr->value()); |
4982 __ Str(value, FieldMemOperand(object, offset)); | 4981 __ Str(value, FieldMemOperand(object, offset)); |
4983 return; | 4982 return; |
4984 } | 4983 } |
4985 | 4984 |
4986 DCHECK(!representation.IsSmi() || | 4985 DCHECK(!representation.IsSmi() || |
4987 !instr->value()->IsConstantOperand() || | 4986 !instr->value()->IsConstantOperand() || |
4988 IsInteger32Constant(LConstantOperand::cast(instr->value()))); | 4987 IsInteger32Constant(LConstantOperand::cast(instr->value()))); |
4989 | 4988 |
4990 if (instr->hydrogen()->has_transition()) { | 4989 if (instr->hydrogen()->has_transition()) { |
4991 Handle<Map> transition = instr->hydrogen()->transition_map(); | 4990 Handle<Map> transition = instr->hydrogen()->transition_map(); |
(...skipping 17 matching lines...) Expand all Loading... |
5009 if (access.IsInobject()) { | 5008 if (access.IsInobject()) { |
5010 destination = object; | 5009 destination = object; |
5011 } else { | 5010 } else { |
5012 Register temp0 = ToRegister(instr->temp0()); | 5011 Register temp0 = ToRegister(instr->temp0()); |
5013 __ Ldr(temp0, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 5012 __ Ldr(temp0, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
5014 destination = temp0; | 5013 destination = temp0; |
5015 } | 5014 } |
5016 | 5015 |
5017 if (FLAG_unbox_double_fields && representation.IsDouble()) { | 5016 if (FLAG_unbox_double_fields && representation.IsDouble()) { |
5018 DCHECK(access.IsInobject()); | 5017 DCHECK(access.IsInobject()); |
5019 FPRegister value = ToDoubleRegister(instr->value()); | 5018 VRegister value = ToDoubleRegister(instr->value()); |
5020 __ Str(value, FieldMemOperand(object, offset)); | 5019 __ Str(value, FieldMemOperand(object, offset)); |
5021 } else if (representation.IsSmi() && | 5020 } else if (representation.IsSmi() && |
5022 instr->hydrogen()->value()->representation().IsInteger32()) { | 5021 instr->hydrogen()->value()->representation().IsInteger32()) { |
5023 DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY); | 5022 DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY); |
5024 #ifdef DEBUG | 5023 #ifdef DEBUG |
5025 Register temp0 = ToRegister(instr->temp0()); | 5024 Register temp0 = ToRegister(instr->temp0()); |
5026 __ Ldr(temp0, FieldMemOperand(destination, offset)); | 5025 __ Ldr(temp0, FieldMemOperand(destination, offset)); |
5027 __ AssertSmi(temp0); | 5026 __ AssertSmi(temp0); |
5028 // If destination aliased temp0, restore it to the address calculated | 5027 // If destination aliased temp0, restore it to the address calculated |
5029 // earlier. | 5028 // earlier. |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5583 // Index is equal to negated out of object property index plus 1. | 5582 // Index is equal to negated out of object property index plus 1. |
5584 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); | 5583 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
5585 __ Ldr(result, FieldMemOperand(result, | 5584 __ Ldr(result, FieldMemOperand(result, |
5586 FixedArray::kHeaderSize - kPointerSize)); | 5585 FixedArray::kHeaderSize - kPointerSize)); |
5587 __ Bind(deferred->exit()); | 5586 __ Bind(deferred->exit()); |
5588 __ Bind(&done); | 5587 __ Bind(&done); |
5589 } | 5588 } |
5590 | 5589 |
5591 } // namespace internal | 5590 } // namespace internal |
5592 } // namespace v8 | 5591 } // namespace v8 |
OLD | NEW |