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 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1126 // references the end of the double registers and not the end of the stack | 1126 // references the end of the double registers and not the end of the stack |
1127 // slots. | 1127 // slots. |
1128 // In both of the cases above, we _could_ add the tracking information | 1128 // In both of the cases above, we _could_ add the tracking information |
1129 // required so that we can use jssp here, but in practice it isn't worth it. | 1129 // required so that we can use jssp here, but in practice it isn't worth it. |
1130 if ((stack_mode == kCanUseStackPointer) && | 1130 if ((stack_mode == kCanUseStackPointer) && |
1131 !info()->saves_caller_doubles()) { | 1131 !info()->saves_caller_doubles()) { |
1132 int jssp_offset_to_fp = | 1132 int jssp_offset_to_fp = |
1133 (pushed_arguments_ + GetTotalFrameSlotCount()) * kPointerSize - | 1133 (pushed_arguments_ + GetTotalFrameSlotCount()) * kPointerSize - |
1134 StandardFrameConstants::kFixedFrameSizeAboveFp; | 1134 StandardFrameConstants::kFixedFrameSizeAboveFp; |
1135 int jssp_offset = fp_offset + jssp_offset_to_fp; | 1135 int jssp_offset = fp_offset + jssp_offset_to_fp; |
1136 if (masm()->IsImmLSScaled(jssp_offset, LSDoubleWord)) { | 1136 if (masm()->IsImmLSScaled(jssp_offset, kPointerSizeLog2)) { |
1137 return MemOperand(masm()->StackPointer(), jssp_offset); | 1137 return MemOperand(masm()->StackPointer(), jssp_offset); |
1138 } | 1138 } |
1139 } | 1139 } |
1140 return MemOperand(fp, fp_offset); | 1140 return MemOperand(fp, fp_offset); |
1141 } else { | 1141 } else { |
1142 // Retrieve parameter without eager stack-frame relative to the | 1142 // Retrieve parameter without eager stack-frame relative to the |
1143 // stack-pointer. | 1143 // stack-pointer. |
1144 return MemOperand(masm()->StackPointer(), | 1144 return MemOperand(masm()->StackPointer(), |
1145 ArgumentsOffsetWithoutFrame(op->index())); | 1145 ArgumentsOffsetWithoutFrame(op->index())); |
1146 } | 1146 } |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1265 template<class InstrType> | 1265 template<class InstrType> |
1266 void LCodeGen::EmitTestAndBranch(InstrType instr, | 1266 void LCodeGen::EmitTestAndBranch(InstrType instr, |
1267 Condition condition, | 1267 Condition condition, |
1268 const Register& value, | 1268 const Register& value, |
1269 uint64_t mask) { | 1269 uint64_t mask) { |
1270 DCHECK((condition != al) && (condition != nv)); | 1270 DCHECK((condition != al) && (condition != nv)); |
1271 TestAndBranch branch(this, condition, value, mask); | 1271 TestAndBranch branch(this, condition, value, mask); |
1272 EmitBranchGeneric(instr, branch); | 1272 EmitBranchGeneric(instr, branch); |
1273 } | 1273 } |
1274 | 1274 |
1275 | 1275 template <class InstrType> |
1276 template<class InstrType> | |
1277 void LCodeGen::EmitBranchIfNonZeroNumber(InstrType instr, | 1276 void LCodeGen::EmitBranchIfNonZeroNumber(InstrType instr, |
1278 const FPRegister& value, | 1277 const VRegister& value, |
1279 const FPRegister& scratch) { | 1278 const VRegister& scratch) { |
1280 BranchIfNonZeroNumber branch(this, value, scratch); | 1279 BranchIfNonZeroNumber branch(this, value, scratch); |
1281 EmitBranchGeneric(instr, branch); | 1280 EmitBranchGeneric(instr, branch); |
1282 } | 1281 } |
1283 | 1282 |
1284 | 1283 |
1285 template<class InstrType> | 1284 template<class InstrType> |
1286 void LCodeGen::EmitBranchIfHeapNumber(InstrType instr, | 1285 void LCodeGen::EmitBranchIfHeapNumber(InstrType instr, |
1287 const Register& value) { | 1286 const Register& value) { |
1288 BranchIfHeapNumber branch(this, value); | 1287 BranchIfHeapNumber branch(this, value); |
1289 EmitBranchGeneric(instr, branch); | 1288 EmitBranchGeneric(instr, branch); |
(...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2270 // The name in the constructor is internalized because of the way the context | 2269 // The name in the constructor is internalized because of the way the context |
2271 // is booted. This routine isn't expected to work for random API-created | 2270 // is booted. This routine isn't expected to work for random API-created |
2272 // classes and it doesn't have to because you can't access it with natives | 2271 // classes and it doesn't have to because you can't access it with natives |
2273 // syntax. Since both sides are internalized it is sufficient to use an | 2272 // syntax. Since both sides are internalized it is sufficient to use an |
2274 // identity comparison. | 2273 // identity comparison. |
2275 EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); | 2274 EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); |
2276 } | 2275 } |
2277 | 2276 |
2278 void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) { | 2277 void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) { |
2279 DCHECK(instr->hydrogen()->representation().IsDouble()); | 2278 DCHECK(instr->hydrogen()->representation().IsDouble()); |
2280 FPRegister object = ToDoubleRegister(instr->object()); | 2279 VRegister object = ToDoubleRegister(instr->object()); |
2281 Register temp = ToRegister(instr->temp()); | 2280 Register temp = ToRegister(instr->temp()); |
2282 | 2281 |
2283 // If we don't have a NaN, we don't have the hole, so branch now to avoid the | 2282 // If we don't have a NaN, we don't have the hole, so branch now to avoid the |
2284 // (relatively expensive) hole-NaN check. | 2283 // (relatively expensive) hole-NaN check. |
2285 __ Fcmp(object, object); | 2284 __ Fcmp(object, object); |
2286 __ B(vc, instr->FalseLabel(chunk_)); | 2285 __ B(vc, instr->FalseLabel(chunk_)); |
2287 | 2286 |
2288 // We have a NaN, but is it the hole? | 2287 // We have a NaN, but is it the hole? |
2289 __ Fmov(temp, object); | 2288 __ Fmov(temp, object); |
2290 EmitCompareAndBranch(instr, eq, temp, kHoleNanInt64); | 2289 EmitCompareAndBranch(instr, eq, temp, kHoleNanInt64); |
(...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3267 Register object = ToRegister(instr->object()); | 3266 Register object = ToRegister(instr->object()); |
3268 | 3267 |
3269 if (access.IsExternalMemory()) { | 3268 if (access.IsExternalMemory()) { |
3270 Register result = ToRegister(instr->result()); | 3269 Register result = ToRegister(instr->result()); |
3271 __ Load(result, MemOperand(object, offset), access.representation()); | 3270 __ Load(result, MemOperand(object, offset), access.representation()); |
3272 return; | 3271 return; |
3273 } | 3272 } |
3274 | 3273 |
3275 if (instr->hydrogen()->representation().IsDouble()) { | 3274 if (instr->hydrogen()->representation().IsDouble()) { |
3276 DCHECK(access.IsInobject()); | 3275 DCHECK(access.IsInobject()); |
3277 FPRegister result = ToDoubleRegister(instr->result()); | 3276 VRegister result = ToDoubleRegister(instr->result()); |
3278 __ Ldr(result, FieldMemOperand(object, offset)); | 3277 __ Ldr(result, FieldMemOperand(object, offset)); |
3279 return; | 3278 return; |
3280 } | 3279 } |
3281 | 3280 |
3282 Register result = ToRegister(instr->result()); | 3281 Register result = ToRegister(instr->result()); |
3283 Register source; | 3282 Register source; |
3284 if (access.IsInobject()) { | 3283 if (access.IsInobject()) { |
3285 source = object; | 3284 source = object; |
3286 } else { | 3285 } else { |
3287 // Load the properties array, using result as a scratch register. | 3286 // Load the properties array, using result as a scratch register. |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3427 // never get set by the negation. This is therefore the same as the Integer32 | 3426 // never get set by the negation. This is therefore the same as the Integer32 |
3428 // case in DoMathAbs, except that it operates on 64-bit values. | 3427 // case in DoMathAbs, except that it operates on 64-bit values. |
3429 STATIC_ASSERT((kSmiValueSize == 32) && (kSmiShift == 32) && (kSmiTag == 0)); | 3428 STATIC_ASSERT((kSmiValueSize == 32) && (kSmiShift == 32) && (kSmiTag == 0)); |
3430 | 3429 |
3431 __ JumpIfNotSmi(input, deferred->entry()); | 3430 __ JumpIfNotSmi(input, deferred->entry()); |
3432 | 3431 |
3433 __ Abs(result, input, NULL, &done); | 3432 __ Abs(result, input, NULL, &done); |
3434 | 3433 |
3435 // The result is the magnitude (abs) of the smallest value a smi can | 3434 // The result is the magnitude (abs) of the smallest value a smi can |
3436 // represent, encoded as a double. | 3435 // represent, encoded as a double. |
3437 __ Mov(result_bits, double_to_rawbits(0x80000000)); | 3436 __ Mov(result_bits, bit_cast<uint64_t>(static_cast<double>(0x80000000))); |
3438 __ B(deferred->allocation_entry()); | 3437 __ B(deferred->allocation_entry()); |
3439 | 3438 |
3440 __ Bind(deferred->exit()); | 3439 __ Bind(deferred->exit()); |
3441 __ Str(result_bits, FieldMemOperand(result, HeapNumber::kValueOffset)); | 3440 __ Str(result_bits, FieldMemOperand(result, HeapNumber::kValueOffset)); |
3442 | 3441 |
3443 __ Bind(&done); | 3442 __ Bind(&done); |
3444 } | 3443 } |
3445 | 3444 |
3446 void LCodeGen::DoMathCos(LMathCos* instr) { | 3445 void LCodeGen::DoMathCos(LMathCos* instr) { |
3447 DCHECK(instr->IsMarkedAsCall()); | 3446 DCHECK(instr->IsMarkedAsCall()); |
(...skipping 1521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4969 __ Store(value, MemOperand(object, offset), representation); | 4968 __ Store(value, MemOperand(object, offset), representation); |
4970 return; | 4969 return; |
4971 } | 4970 } |
4972 | 4971 |
4973 __ AssertNotSmi(object); | 4972 __ AssertNotSmi(object); |
4974 | 4973 |
4975 if (!FLAG_unbox_double_fields && representation.IsDouble()) { | 4974 if (!FLAG_unbox_double_fields && representation.IsDouble()) { |
4976 DCHECK(access.IsInobject()); | 4975 DCHECK(access.IsInobject()); |
4977 DCHECK(!instr->hydrogen()->has_transition()); | 4976 DCHECK(!instr->hydrogen()->has_transition()); |
4978 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); | 4977 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); |
4979 FPRegister value = ToDoubleRegister(instr->value()); | 4978 VRegister value = ToDoubleRegister(instr->value()); |
4980 __ Str(value, FieldMemOperand(object, offset)); | 4979 __ Str(value, FieldMemOperand(object, offset)); |
4981 return; | 4980 return; |
4982 } | 4981 } |
4983 | 4982 |
4984 DCHECK(!representation.IsSmi() || | 4983 DCHECK(!representation.IsSmi() || |
4985 !instr->value()->IsConstantOperand() || | 4984 !instr->value()->IsConstantOperand() || |
4986 IsInteger32Constant(LConstantOperand::cast(instr->value()))); | 4985 IsInteger32Constant(LConstantOperand::cast(instr->value()))); |
4987 | 4986 |
4988 if (instr->hydrogen()->has_transition()) { | 4987 if (instr->hydrogen()->has_transition()) { |
4989 Handle<Map> transition = instr->hydrogen()->transition_map(); | 4988 Handle<Map> transition = instr->hydrogen()->transition_map(); |
(...skipping 17 matching lines...) Expand all Loading... |
5007 if (access.IsInobject()) { | 5006 if (access.IsInobject()) { |
5008 destination = object; | 5007 destination = object; |
5009 } else { | 5008 } else { |
5010 Register temp0 = ToRegister(instr->temp0()); | 5009 Register temp0 = ToRegister(instr->temp0()); |
5011 __ Ldr(temp0, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 5010 __ Ldr(temp0, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
5012 destination = temp0; | 5011 destination = temp0; |
5013 } | 5012 } |
5014 | 5013 |
5015 if (FLAG_unbox_double_fields && representation.IsDouble()) { | 5014 if (FLAG_unbox_double_fields && representation.IsDouble()) { |
5016 DCHECK(access.IsInobject()); | 5015 DCHECK(access.IsInobject()); |
5017 FPRegister value = ToDoubleRegister(instr->value()); | 5016 VRegister value = ToDoubleRegister(instr->value()); |
5018 __ Str(value, FieldMemOperand(object, offset)); | 5017 __ Str(value, FieldMemOperand(object, offset)); |
5019 } else if (representation.IsSmi() && | 5018 } else if (representation.IsSmi() && |
5020 instr->hydrogen()->value()->representation().IsInteger32()) { | 5019 instr->hydrogen()->value()->representation().IsInteger32()) { |
5021 DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY); | 5020 DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY); |
5022 #ifdef DEBUG | 5021 #ifdef DEBUG |
5023 Register temp0 = ToRegister(instr->temp0()); | 5022 Register temp0 = ToRegister(instr->temp0()); |
5024 __ Ldr(temp0, FieldMemOperand(destination, offset)); | 5023 __ Ldr(temp0, FieldMemOperand(destination, offset)); |
5025 __ AssertSmi(temp0); | 5024 __ AssertSmi(temp0); |
5026 // If destination aliased temp0, restore it to the address calculated | 5025 // If destination aliased temp0, restore it to the address calculated |
5027 // earlier. | 5026 // earlier. |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5581 // Index is equal to negated out of object property index plus 1. | 5580 // Index is equal to negated out of object property index plus 1. |
5582 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); | 5581 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
5583 __ Ldr(result, FieldMemOperand(result, | 5582 __ Ldr(result, FieldMemOperand(result, |
5584 FixedArray::kHeaderSize - kPointerSize)); | 5583 FixedArray::kHeaderSize - kPointerSize)); |
5585 __ Bind(deferred->exit()); | 5584 __ Bind(deferred->exit()); |
5586 __ Bind(&done); | 5585 __ Bind(&done); |
5587 } | 5586 } |
5588 | 5587 |
5589 } // namespace internal | 5588 } // namespace internal |
5590 } // namespace v8 | 5589 } // namespace v8 |
OLD | NEW |