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