| Index: src/arm/code-stubs-arm.cc
|
| diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
|
| index f883c4f3a4f9fd6c034696c2ee2110f732bc51ee..0aba7c1d26a7b5ac91e44424c3ebf2028e3d96f7 100644
|
| --- a/src/arm/code-stubs-arm.cc
|
| +++ b/src/arm/code-stubs-arm.cc
|
| @@ -145,7 +145,6 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
| Label* lhs_not_nan,
|
| Label* slow,
|
| bool strict);
|
| -static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond);
|
| static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
|
| Register lhs,
|
| Register rhs);
|
| @@ -515,30 +514,15 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
|
| FloatingPointHelper::Destination destination,
|
| Register scratch1,
|
| Register scratch2) {
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
|
| - __ vmov(d7.high(), scratch1);
|
| - __ vcvt_f64_s32(d7, d7.high());
|
| - __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
|
| - __ vmov(d6.high(), scratch1);
|
| - __ vcvt_f64_s32(d6, d6.high());
|
| - if (destination == kCoreRegisters) {
|
| - __ vmov(r2, r3, d7);
|
| - __ vmov(r0, r1, d6);
|
| - }
|
| - } else {
|
| - ASSERT(destination == kCoreRegisters);
|
| - // Write Smi from r0 to r3 and r2 in double format.
|
| - __ mov(scratch1, Operand(r0));
|
| - ConvertToDoubleStub stub1(r3, r2, scratch1, scratch2);
|
| - __ push(lr);
|
| - __ Call(stub1.GetCode(masm->isolate()));
|
| - // Write Smi from r1 to r1 and r0 in double format.
|
| - __ mov(scratch1, Operand(r1));
|
| - ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2);
|
| - __ Call(stub2.GetCode(masm->isolate()));
|
| - __ pop(lr);
|
| + __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
|
| + __ vmov(d7.high(), scratch1);
|
| + __ vcvt_f64_s32(d7, d7.high());
|
| + __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
|
| + __ vmov(d6.high(), scratch1);
|
| + __ vcvt_f64_s32(d6, d6.high());
|
| + if (destination == kCoreRegisters) {
|
| + __ vmov(r2, r3, d7);
|
| + __ vmov(r0, r1, d6);
|
| }
|
| }
|
|
|
| @@ -565,9 +549,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
|
| __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
|
|
|
| // Handle loading a double from a heap number.
|
| - if (CpuFeatures::IsSupported(VFP2) &&
|
| - destination == kVFPRegisters) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| + if (destination == kVFPRegisters) {
|
| // Load the double from tagged HeapNumber to double register.
|
| __ sub(scratch1, object, Operand(kHeapObjectTag));
|
| __ vldr(dst, scratch1, HeapNumber::kValueOffset);
|
| @@ -580,23 +562,12 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
|
|
|
| // Handle loading a double from a smi.
|
| __ bind(&is_smi);
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - // Convert smi to double using VFP instructions.
|
| - __ vmov(dst.high(), scratch1);
|
| - __ vcvt_f64_s32(dst, dst.high());
|
| - if (destination == kCoreRegisters) {
|
| - // Load the converted smi to dst1 and dst2 in double format.
|
| - __ vmov(dst1, dst2, dst);
|
| - }
|
| - } else {
|
| - ASSERT(destination == kCoreRegisters);
|
| - // Write smi to dst1 and dst2 double format.
|
| - __ mov(scratch1, Operand(object));
|
| - ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
|
| - __ push(lr);
|
| - __ Call(stub.GetCode(masm->isolate()));
|
| - __ pop(lr);
|
| + // Convert smi to double using VFP instructions.
|
| + __ vmov(dst.high(), scratch1);
|
| + __ vcvt_f64_s32(dst, dst.high());
|
| + if (destination == kCoreRegisters) {
|
| + // Load the converted smi to dst1 and dst2 in double format.
|
| + __ vmov(dst1, dst2, dst);
|
| }
|
|
|
| __ bind(&done);
|
| @@ -643,62 +614,10 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm,
|
|
|
| Label done;
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ vmov(single_scratch, int_scratch);
|
| - __ vcvt_f64_s32(double_dst, single_scratch);
|
| - if (destination == kCoreRegisters) {
|
| - __ vmov(dst_mantissa, dst_exponent, double_dst);
|
| - }
|
| - } else {
|
| - Label fewer_than_20_useful_bits;
|
| - // Expected output:
|
| - // | dst_exponent | dst_mantissa |
|
| - // | s | exp | mantissa |
|
| -
|
| - // Check for zero.
|
| - __ cmp(int_scratch, Operand::Zero());
|
| - __ mov(dst_exponent, int_scratch);
|
| - __ mov(dst_mantissa, int_scratch);
|
| - __ b(eq, &done);
|
| -
|
| - // Preload the sign of the value.
|
| - __ and_(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask), SetCC);
|
| - // Get the absolute value of the object (as an unsigned integer).
|
| - __ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi);
|
| -
|
| - // Get mantissa[51:20].
|
| -
|
| - // Get the position of the first set bit.
|
| - __ CountLeadingZeros(dst_mantissa, int_scratch, scratch2);
|
| - __ rsb(dst_mantissa, dst_mantissa, Operand(31));
|
| -
|
| - // Set the exponent.
|
| - __ add(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
|
| - __ Bfi(dst_exponent, scratch2, scratch2,
|
| - HeapNumber::kExponentShift, HeapNumber::kExponentBits);
|
| -
|
| - // Clear the first non null bit.
|
| - __ mov(scratch2, Operand(1));
|
| - __ bic(int_scratch, int_scratch, Operand(scratch2, LSL, dst_mantissa));
|
| -
|
| - __ cmp(dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
|
| - // Get the number of bits to set in the lower part of the mantissa.
|
| - __ sub(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord),
|
| - SetCC);
|
| - __ b(mi, &fewer_than_20_useful_bits);
|
| - // Set the higher 20 bits of the mantissa.
|
| - __ orr(dst_exponent, dst_exponent, Operand(int_scratch, LSR, scratch2));
|
| - __ rsb(scratch2, scratch2, Operand(32));
|
| - __ mov(dst_mantissa, Operand(int_scratch, LSL, scratch2));
|
| - __ b(&done);
|
| -
|
| - __ bind(&fewer_than_20_useful_bits);
|
| - __ rsb(scratch2, dst_mantissa, Operand(HeapNumber::kMantissaBitsInTopWord));
|
| - __ mov(scratch2, Operand(int_scratch, LSL, scratch2));
|
| - __ orr(dst_exponent, dst_exponent, scratch2);
|
| - // Set dst1 to 0.
|
| - __ mov(dst_mantissa, Operand::Zero());
|
| + __ vmov(single_scratch, int_scratch);
|
| + __ vcvt_f64_s32(double_dst, single_scratch);
|
| + if (destination == kCoreRegisters) {
|
| + __ vmov(dst_mantissa, dst_exponent, double_dst);
|
| }
|
| __ bind(&done);
|
| }
|
| @@ -737,65 +656,17 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm,
|
| __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32);
|
|
|
| // Load the number.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - // Load the double value.
|
| - __ sub(scratch1, object, Operand(kHeapObjectTag));
|
| - __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
|
| -
|
| - __ TestDoubleIsInt32(double_dst, double_scratch);
|
| - // Jump to not_int32 if the operation did not succeed.
|
| - __ b(ne, not_int32);
|
| + // Load the double value.
|
| + __ sub(scratch1, object, Operand(kHeapObjectTag));
|
| + __ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
|
|
|
| - if (destination == kCoreRegisters) {
|
| - __ vmov(dst_mantissa, dst_exponent, double_dst);
|
| - }
|
| -
|
| - } else {
|
| - ASSERT(!scratch1.is(object) && !scratch2.is(object));
|
| - // Load the double value in the destination registers.
|
| - bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
|
| - if (save_registers) {
|
| - // Save both output registers, because the other one probably holds
|
| - // an important value too.
|
| - __ Push(dst_exponent, dst_mantissa);
|
| - }
|
| - __ Ldrd(dst_mantissa, dst_exponent,
|
| - FieldMemOperand(object, HeapNumber::kValueOffset));
|
| -
|
| - // Check for 0 and -0.
|
| - Label zero;
|
| - __ bic(scratch1, dst_exponent, Operand(HeapNumber::kSignMask));
|
| - __ orr(scratch1, scratch1, Operand(dst_mantissa));
|
| - __ cmp(scratch1, Operand::Zero());
|
| - __ b(eq, &zero);
|
| -
|
| - // Check that the value can be exactly represented by a 32-bit integer.
|
| - // Jump to not_int32 if that's not the case.
|
| - Label restore_input_and_miss;
|
| - DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
|
| - &restore_input_and_miss);
|
| -
|
| - // dst_* were trashed. Reload the double value.
|
| - if (save_registers) {
|
| - __ Pop(dst_exponent, dst_mantissa);
|
| - }
|
| - __ Ldrd(dst_mantissa, dst_exponent,
|
| - FieldMemOperand(object, HeapNumber::kValueOffset));
|
| - __ b(&done);
|
| -
|
| - __ bind(&restore_input_and_miss);
|
| - if (save_registers) {
|
| - __ Pop(dst_exponent, dst_mantissa);
|
| - }
|
| - __ b(not_int32);
|
| + __ TestDoubleIsInt32(double_dst, double_scratch);
|
| + // Jump to not_int32 if the operation did not succeed.
|
| + __ b(ne, not_int32);
|
|
|
| - __ bind(&zero);
|
| - if (save_registers) {
|
| - __ Drop(2);
|
| - }
|
| + if (destination == kCoreRegisters) {
|
| + __ vmov(dst_mantissa, dst_exponent, double_dst);
|
| }
|
| -
|
| __ bind(&done);
|
| }
|
|
|
| @@ -828,43 +699,13 @@ void FloatingPointHelper::LoadNumberAsInt32(MacroAssembler* masm,
|
|
|
| // Object is a heap number.
|
| // Convert the floating point value to a 32-bit integer.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| -
|
| - // Load the double value.
|
| - __ sub(scratch1, object, Operand(kHeapObjectTag));
|
| - __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
|
| + // Load the double value.
|
| + __ sub(scratch1, object, Operand(kHeapObjectTag));
|
| + __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
|
|
|
| - __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
|
| - // Jump to not_int32 if the operation did not succeed.
|
| - __ b(ne, not_int32);
|
| - } else {
|
| - // Load the double value in the destination registers.
|
| - __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
|
| - __ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
|
| -
|
| - // Check for 0 and -0.
|
| - __ bic(dst, scratch1, Operand(HeapNumber::kSignMask));
|
| - __ orr(dst, scratch2, Operand(dst));
|
| - __ cmp(dst, Operand::Zero());
|
| - __ b(eq, &done);
|
| -
|
| - DoubleIs32BitInteger(masm, scratch1, scratch2, dst, scratch3, not_int32);
|
| -
|
| - // Registers state after DoubleIs32BitInteger.
|
| - // dst: mantissa[51:20].
|
| - // scratch2: 1
|
| -
|
| - // Shift back the higher bits of the mantissa.
|
| - __ mov(dst, Operand(dst, LSR, scratch3));
|
| - // Set the implicit first bit.
|
| - __ rsb(scratch3, scratch3, Operand(32));
|
| - __ orr(dst, dst, Operand(scratch2, LSL, scratch3));
|
| - // Set the sign.
|
| - __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
|
| - __ tst(scratch1, Operand(HeapNumber::kSignMask));
|
| - __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
|
| - }
|
| + __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
|
| + // Jump to not_int32 if the operation did not succeed.
|
| + __ b(ne, not_int32);
|
| __ b(&done);
|
|
|
| __ bind(&maybe_undefined);
|
| @@ -958,7 +799,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
|
| __ push(lr);
|
| __ PrepareCallCFunction(0, 2, scratch);
|
| if (masm->use_eabi_hardfloat()) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| __ vmov(d0, r0, r1);
|
| __ vmov(d1, r2, r3);
|
| }
|
| @@ -970,7 +810,6 @@ void FloatingPointHelper::CallCCodeForDoubleOperation(
|
| // Store answer in the overwritable heap number. Double returned in
|
| // registers r0 and r1 or in d0.
|
| if (masm->use_eabi_hardfloat()) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| __ vstr(d0,
|
| FieldMemOperand(heap_number_result, HeapNumber::kValueOffset));
|
| } else {
|
| @@ -1183,23 +1022,11 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
| }
|
|
|
| // Lhs is a smi, rhs is a number.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - // Convert lhs to a double in d7.
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
|
| - // Load the double from rhs, tagged HeapNumber r0, to d6.
|
| - __ sub(r7, rhs, Operand(kHeapObjectTag));
|
| - __ vldr(d6, r7, HeapNumber::kValueOffset);
|
| - } else {
|
| - __ push(lr);
|
| - // Convert lhs to a double in r2, r3.
|
| - __ mov(r7, Operand(lhs));
|
| - ConvertToDoubleStub stub1(r3, r2, r7, r6);
|
| - __ Call(stub1.GetCode(masm->isolate()));
|
| - // Load rhs to a double in r0, r1.
|
| - __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
|
| - __ pop(lr);
|
| - }
|
| + // Convert lhs to a double in d7.
|
| + __ SmiToDoubleVFPRegister(lhs, d7, r7, s15);
|
| + // Load the double from rhs, tagged HeapNumber r0, to d6.
|
| + __ sub(r7, rhs, Operand(kHeapObjectTag));
|
| + __ vldr(d6, r7, HeapNumber::kValueOffset);
|
|
|
| // We now have both loaded as doubles but we can skip the lhs nan check
|
| // since it's a smi.
|
| @@ -1223,23 +1050,11 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
| }
|
|
|
| // Rhs is a smi, lhs is a heap number.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - // Load the double from lhs, tagged HeapNumber r1, to d7.
|
| - __ sub(r7, lhs, Operand(kHeapObjectTag));
|
| - __ vldr(d7, r7, HeapNumber::kValueOffset);
|
| - // Convert rhs to a double in d6 .
|
| - __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
|
| - } else {
|
| - __ push(lr);
|
| - // Load lhs to a double in r2, r3.
|
| - __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
|
| - // Convert rhs to a double in r0, r1.
|
| - __ mov(r7, Operand(rhs));
|
| - ConvertToDoubleStub stub2(r1, r0, r7, r6);
|
| - __ Call(stub2.GetCode(masm->isolate()));
|
| - __ pop(lr);
|
| - }
|
| + // Load the double from lhs, tagged HeapNumber r1, to d7.
|
| + __ sub(r7, lhs, Operand(kHeapObjectTag));
|
| + __ vldr(d7, r7, HeapNumber::kValueOffset);
|
| + // Convert rhs to a double in d6 .
|
| + __ SmiToDoubleVFPRegister(rhs, d6, r7, s13);
|
| // Fall through to both_loaded_as_doubles.
|
| }
|
|
|
| @@ -1296,60 +1111,6 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) {
|
|
|
|
|
| // See comment at call site.
|
| -static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm,
|
| - Condition cond) {
|
| - bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
|
| - Register rhs_exponent = exp_first ? r0 : r1;
|
| - Register lhs_exponent = exp_first ? r2 : r3;
|
| - Register rhs_mantissa = exp_first ? r1 : r0;
|
| - Register lhs_mantissa = exp_first ? r3 : r2;
|
| -
|
| - // r0, r1, r2, r3 have the two doubles. Neither is a NaN.
|
| - if (cond == eq) {
|
| - // Doubles are not equal unless they have the same bit pattern.
|
| - // Exception: 0 and -0.
|
| - __ cmp(rhs_mantissa, Operand(lhs_mantissa));
|
| - __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne);
|
| - // Return non-zero if the numbers are unequal.
|
| - __ Ret(ne);
|
| -
|
| - __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC);
|
| - // If exponents are equal then return 0.
|
| - __ Ret(eq);
|
| -
|
| - // Exponents are unequal. The only way we can return that the numbers
|
| - // are equal is if one is -0 and the other is 0. We already dealt
|
| - // with the case where both are -0 or both are 0.
|
| - // We start by seeing if the mantissas (that are equal) or the bottom
|
| - // 31 bits of the rhs exponent are non-zero. If so we return not
|
| - // equal.
|
| - __ orr(r4, lhs_mantissa, Operand(lhs_exponent, LSL, kSmiTagSize), SetCC);
|
| - __ mov(r0, Operand(r4), LeaveCC, ne);
|
| - __ Ret(ne);
|
| - // Now they are equal if and only if the lhs exponent is zero in its
|
| - // low 31 bits.
|
| - __ mov(r0, Operand(rhs_exponent, LSL, kSmiTagSize));
|
| - __ Ret();
|
| - } else {
|
| - // Call a native function to do a comparison between two non-NaNs.
|
| - // Call C routine that may not cause GC or other trouble.
|
| - __ push(lr);
|
| - __ PrepareCallCFunction(0, 2, r5);
|
| - if (masm->use_eabi_hardfloat()) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ vmov(d0, r0, r1);
|
| - __ vmov(d1, r2, r3);
|
| - }
|
| -
|
| - AllowExternalCallThatCantCauseGC scope(masm);
|
| - __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()),
|
| - 0, 2);
|
| - __ pop(pc); // Return.
|
| - }
|
| -}
|
| -
|
| -
|
| -// See comment at call site.
|
| static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
|
| Register lhs,
|
| Register rhs) {
|
| @@ -1412,16 +1173,10 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
|
|
|
| // Both are heap numbers. Load them up then jump to the code we have
|
| // for that.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ sub(r7, rhs, Operand(kHeapObjectTag));
|
| - __ vldr(d6, r7, HeapNumber::kValueOffset);
|
| - __ sub(r7, lhs, Operand(kHeapObjectTag));
|
| - __ vldr(d7, r7, HeapNumber::kValueOffset);
|
| - } else {
|
| - __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset));
|
| - __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset));
|
| - }
|
| + __ sub(r7, rhs, Operand(kHeapObjectTag));
|
| + __ vldr(d6, r7, HeapNumber::kValueOffset);
|
| + __ sub(r7, lhs, Operand(kHeapObjectTag));
|
| + __ vldr(d7, r7, HeapNumber::kValueOffset);
|
| __ jmp(both_loaded_as_doubles);
|
| }
|
|
|
| @@ -1502,42 +1257,37 @@ void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
|
| Label load_result_from_cache;
|
| if (!object_is_smi) {
|
| __ JumpIfSmi(object, &is_smi);
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ CheckMap(object,
|
| - scratch1,
|
| - Heap::kHeapNumberMapRootIndex,
|
| - not_found,
|
| - DONT_DO_SMI_CHECK);
|
| -
|
| - STATIC_ASSERT(8 == kDoubleSize);
|
| - __ add(scratch1,
|
| - object,
|
| - Operand(HeapNumber::kValueOffset - kHeapObjectTag));
|
| - __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
|
| - __ eor(scratch1, scratch1, Operand(scratch2));
|
| - __ and_(scratch1, scratch1, Operand(mask));
|
| -
|
| - // Calculate address of entry in string cache: each entry consists
|
| - // of two pointer sized fields.
|
| - __ add(scratch1,
|
| - number_string_cache,
|
| - Operand(scratch1, LSL, kPointerSizeLog2 + 1));
|
| -
|
| - Register probe = mask;
|
| - __ ldr(probe,
|
| - FieldMemOperand(scratch1, FixedArray::kHeaderSize));
|
| - __ JumpIfSmi(probe, not_found);
|
| - __ sub(scratch2, object, Operand(kHeapObjectTag));
|
| - __ vldr(d0, scratch2, HeapNumber::kValueOffset);
|
| - __ sub(probe, probe, Operand(kHeapObjectTag));
|
| - __ vldr(d1, probe, HeapNumber::kValueOffset);
|
| - __ VFPCompareAndSetFlags(d0, d1);
|
| - __ b(ne, not_found); // The cache did not contain this value.
|
| - __ b(&load_result_from_cache);
|
| - } else {
|
| - __ b(not_found);
|
| - }
|
| + __ CheckMap(object,
|
| + scratch1,
|
| + Heap::kHeapNumberMapRootIndex,
|
| + not_found,
|
| + DONT_DO_SMI_CHECK);
|
| +
|
| + STATIC_ASSERT(8 == kDoubleSize);
|
| + __ add(scratch1,
|
| + object,
|
| + Operand(HeapNumber::kValueOffset - kHeapObjectTag));
|
| + __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit());
|
| + __ eor(scratch1, scratch1, Operand(scratch2));
|
| + __ and_(scratch1, scratch1, Operand(mask));
|
| +
|
| + // Calculate address of entry in string cache: each entry consists
|
| + // of two pointer sized fields.
|
| + __ add(scratch1,
|
| + number_string_cache,
|
| + Operand(scratch1, LSL, kPointerSizeLog2 + 1));
|
| +
|
| + Register probe = mask;
|
| + __ ldr(probe,
|
| + FieldMemOperand(scratch1, FixedArray::kHeaderSize));
|
| + __ JumpIfSmi(probe, not_found);
|
| + __ sub(scratch2, object, Operand(kHeapObjectTag));
|
| + __ vldr(d0, scratch2, HeapNumber::kValueOffset);
|
| + __ sub(probe, probe, Operand(kHeapObjectTag));
|
| + __ vldr(d1, probe, HeapNumber::kValueOffset);
|
| + __ VFPCompareAndSetFlags(d0, d1);
|
| + __ b(ne, not_found); // The cache did not contain this value.
|
| + __ b(&load_result_from_cache);
|
| }
|
|
|
| __ bind(&is_smi);
|
| @@ -1652,37 +1402,27 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
|
| // The arguments have been converted to doubles and stored in d6 and d7, if
|
| // VFP3 is supported, or in r0, r1, r2, and r3.
|
| Isolate* isolate = masm->isolate();
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - __ bind(&lhs_not_nan);
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - Label no_nan;
|
| - // ARMv7 VFP3 instructions to implement double precision comparison.
|
| - __ VFPCompareAndSetFlags(d7, d6);
|
| - Label nan;
|
| - __ b(vs, &nan);
|
| - __ mov(r0, Operand(EQUAL), LeaveCC, eq);
|
| - __ mov(r0, Operand(LESS), LeaveCC, lt);
|
| - __ mov(r0, Operand(GREATER), LeaveCC, gt);
|
| - __ Ret();
|
| + __ bind(&lhs_not_nan);
|
| + Label no_nan;
|
| + // ARMv7 VFP3 instructions to implement double precision comparison.
|
| + __ VFPCompareAndSetFlags(d7, d6);
|
| + Label nan;
|
| + __ b(vs, &nan);
|
| + __ mov(r0, Operand(EQUAL), LeaveCC, eq);
|
| + __ mov(r0, Operand(LESS), LeaveCC, lt);
|
| + __ mov(r0, Operand(GREATER), LeaveCC, gt);
|
| + __ Ret();
|
|
|
| - __ bind(&nan);
|
| - // If one of the sides was a NaN then the v flag is set. Load r0 with
|
| - // whatever it takes to make the comparison fail, since comparisons with NaN
|
| - // always fail.
|
| - if (cc == lt || cc == le) {
|
| - __ mov(r0, Operand(GREATER));
|
| - } else {
|
| - __ mov(r0, Operand(LESS));
|
| - }
|
| - __ Ret();
|
| + __ bind(&nan);
|
| + // If one of the sides was a NaN then the v flag is set. Load r0 with
|
| + // whatever it takes to make the comparison fail, since comparisons with NaN
|
| + // always fail.
|
| + if (cc == lt || cc == le) {
|
| + __ mov(r0, Operand(GREATER));
|
| } else {
|
| - // Checks for NaN in the doubles we have loaded. Can return the answer or
|
| - // fall through if neither is a NaN. Also binds lhs_not_nan.
|
| - EmitNanCheck(masm, &lhs_not_nan, cc);
|
| - // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the
|
| - // answer. Never falls through.
|
| - EmitTwoNonNanDoubleComparison(masm, cc);
|
| + __ mov(r0, Operand(LESS));
|
| }
|
| + __ Ret();
|
|
|
| __ bind(¬_smis);
|
| // At this point we know we are dealing with two different objects,
|
| @@ -1779,7 +1519,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
| // we cannot call anything that could cause a GC from this stub.
|
| Label patch;
|
| const Register map = r9.is(tos_) ? r7 : r9;
|
| - const Register temp = map;
|
|
|
| // undefined -> false.
|
| CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
|
| @@ -1822,9 +1561,9 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
|
|
| if (types_.Contains(STRING)) {
|
| // String value -> false iff empty.
|
| - __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
|
| - __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
|
| - __ Ret(lt); // the string length is OK as the return value
|
| + __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
|
| + __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
|
| + __ Ret(lt); // the string length is OK as the return value
|
| }
|
|
|
| if (types_.Contains(HEAP_NUMBER)) {
|
| @@ -1833,55 +1572,13 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
|
| __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
|
| __ b(ne, ¬_heap_number);
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| -
|
| - __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
|
| - __ VFPCompareAndSetFlags(d1, 0.0);
|
| - // "tos_" is a register, and contains a non zero value by default.
|
| - // Hence we only need to overwrite "tos_" with zero to return false for
|
| - // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
|
| - __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
|
| - __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
|
| - } else {
|
| - Label done, not_nan, not_zero;
|
| - __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
|
| - // -0 maps to false:
|
| - __ bic(
|
| - temp, temp, Operand(HeapNumber::kSignMask, RelocInfo::NONE32), SetCC);
|
| - __ b(ne, ¬_zero);
|
| - // If exponent word is zero then the answer depends on the mantissa word.
|
| - __ ldr(tos_, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
|
| - __ jmp(&done);
|
| -
|
| - // Check for NaN.
|
| - __ bind(¬_zero);
|
| - // We already zeroed the sign bit, now shift out the mantissa so we only
|
| - // have the exponent left.
|
| - __ mov(temp, Operand(temp, LSR, HeapNumber::kMantissaBitsInTopWord));
|
| - unsigned int shifted_exponent_mask =
|
| - HeapNumber::kExponentMask >> HeapNumber::kMantissaBitsInTopWord;
|
| - __ cmp(temp, Operand(shifted_exponent_mask, RelocInfo::NONE32));
|
| - __ b(ne, ¬_nan); // If exponent is not 0x7ff then it can't be a NaN.
|
| -
|
| - // Reload exponent word.
|
| - __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kExponentOffset));
|
| - __ tst(temp, Operand(HeapNumber::kMantissaMask, RelocInfo::NONE32));
|
| - // If mantissa is not zero then we have a NaN, so return 0.
|
| - __ mov(tos_, Operand::Zero(), LeaveCC, ne);
|
| - __ b(ne, &done);
|
| -
|
| - // Load mantissa word.
|
| - __ ldr(temp, FieldMemOperand(tos_, HeapNumber::kMantissaOffset));
|
| - __ cmp(temp, Operand::Zero());
|
| - // If mantissa is not zero then we have a NaN, so return 0.
|
| - __ mov(tos_, Operand::Zero(), LeaveCC, ne);
|
| - __ b(ne, &done);
|
| -
|
| - __ bind(¬_nan);
|
| - __ mov(tos_, Operand(1, RelocInfo::NONE32));
|
| - __ bind(&done);
|
| - }
|
| + __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
|
| + __ VFPCompareAndSetFlags(d1, 0.0);
|
| + // "tos_" is a register, and contains a non zero value by default.
|
| + // Hence we only need to overwrite "tos_" with zero to return false for
|
| + // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
|
| + __ mov(tos_, Operand::Zero(), LeaveCC, eq); // for FP_ZERO
|
| + __ mov(tos_, Operand::Zero(), LeaveCC, vs); // for FP_NAN
|
| __ Ret();
|
| __ bind(¬_heap_number);
|
| }
|
| @@ -1934,7 +1631,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
|
| const Register scratch = r1;
|
|
|
| if (save_doubles_ == kSaveFPRegs) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| // Check CPU flags for number of registers, setting the Z condition flag.
|
| __ CheckFor32DRegs(scratch);
|
|
|
| @@ -1954,8 +1650,6 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
|
| ExternalReference::store_buffer_overflow_function(masm->isolate()),
|
| argument_count);
|
| if (save_doubles_ == kSaveFPRegs) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| -
|
| // Check CPU flags for number of registers, setting the Z condition flag.
|
| __ CheckFor32DRegs(scratch);
|
|
|
| @@ -2180,19 +1874,10 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
|
| __ bind(&heapnumber_allocated);
|
| }
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - // Convert the int32 in r1 to the heap number in r0. r2 is corrupted.
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ vmov(s0, r1);
|
| - __ vcvt_f64_s32(d0, s0);
|
| - __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
|
| - __ Ret();
|
| - } else {
|
| - // WriteInt32ToHeapNumberStub does not trigger GC, so we do not
|
| - // have to set up a frame.
|
| - WriteInt32ToHeapNumberStub stub(r1, r0, r2);
|
| - __ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
|
| - }
|
| + __ vmov(s0, r1);
|
| + __ vcvt_f64_s32(d0, s0);
|
| + __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
|
| + __ Ret();
|
| }
|
|
|
|
|
| @@ -2248,7 +1933,7 @@ void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
|
|
|
|
|
| void BinaryOpStub::Initialize() {
|
| - platform_specific_bit_ = CpuFeatures::IsSupported(VFP2);
|
| + platform_specific_bit_ = true; // VFP2 is a base requirement for V8
|
| }
|
|
|
|
|
| @@ -2527,7 +2212,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
| // Load left and right operands into d6 and d7 or r0/r1 and r2/r3
|
| // depending on whether VFP3 is available or not.
|
| FloatingPointHelper::Destination destination =
|
| - CpuFeatures::IsSupported(VFP2) &&
|
| op != Token::MOD ?
|
| FloatingPointHelper::kVFPRegisters :
|
| FloatingPointHelper::kCoreRegisters;
|
| @@ -2571,7 +2255,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
| // Using VFP registers:
|
| // d6: Left value
|
| // d7: Right value
|
| - CpuFeatureScope scope(masm, VFP2);
|
| switch (op) {
|
| case Token::ADD:
|
| __ vadd(d5, d6, d7);
|
| @@ -2662,11 +2345,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
| // The code below for writing into heap numbers isn't capable of
|
| // writing the register as an unsigned int so we go to slow case if we
|
| // hit this case.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - __ b(mi, &result_not_a_smi);
|
| - } else {
|
| - __ b(mi, not_numbers);
|
| - }
|
| + __ b(mi, &result_not_a_smi);
|
| break;
|
| case Token::SHL:
|
| // Use only the 5 least significant bits of the shift count.
|
| @@ -2702,25 +2381,17 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
| // result.
|
| __ mov(r0, Operand(r5));
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
|
| - // mentioned above SHR needs to always produce a positive result.
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - __ vmov(s0, r2);
|
| - if (op == Token::SHR) {
|
| - __ vcvt_f64_u32(d0, s0);
|
| - } else {
|
| - __ vcvt_f64_s32(d0, s0);
|
| - }
|
| - __ sub(r3, r0, Operand(kHeapObjectTag));
|
| - __ vstr(d0, r3, HeapNumber::kValueOffset);
|
| - __ Ret();
|
| + // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
|
| + // mentioned above SHR needs to always produce a positive result.
|
| + __ vmov(s0, r2);
|
| + if (op == Token::SHR) {
|
| + __ vcvt_f64_u32(d0, s0);
|
| } else {
|
| - // Tail call that writes the int32 in r2 to the heap number in r0, using
|
| - // r3 as scratch. r0 is preserved and returned.
|
| - WriteInt32ToHeapNumberStub stub(r2, r0, r3);
|
| - __ TailCallStub(&stub);
|
| + __ vcvt_f64_s32(d0, s0);
|
| }
|
| + __ sub(r3, r0, Operand(kHeapObjectTag));
|
| + __ vstr(d0, r3, HeapNumber::kValueOffset);
|
| + __ Ret();
|
| break;
|
| }
|
| default:
|
| @@ -2866,8 +2537,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
| // Load both operands and check that they are 32-bit integer.
|
| // Jump to type transition if they are not. The registers r0 and r1 (right
|
| // and left) are preserved for the runtime call.
|
| - FloatingPointHelper::Destination destination =
|
| - (CpuFeatures::IsSupported(VFP2) && op_ != Token::MOD)
|
| + FloatingPointHelper::Destination destination = (op_ != Token::MOD)
|
| ? FloatingPointHelper::kVFPRegisters
|
| : FloatingPointHelper::kCoreRegisters;
|
|
|
| @@ -2897,7 +2567,6 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
| &transition);
|
|
|
| if (destination == FloatingPointHelper::kVFPRegisters) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| Label return_heap_number;
|
| switch (op_) {
|
| case Token::ADD:
|
| @@ -3065,17 +2734,9 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
| // We only get a negative result if the shift value (r2) is 0.
|
| // This result cannot be respresented as a signed 32-bit integer, try
|
| // to return a heap number if we can.
|
| - // The non vfp2 code does not support this special case, so jump to
|
| - // runtime if we don't support it.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - __ b(mi, (result_type_ <= BinaryOpIC::INT32)
|
| - ? &transition
|
| - : &return_heap_number);
|
| - } else {
|
| - __ b(mi, (result_type_ <= BinaryOpIC::INT32)
|
| - ? &transition
|
| - : &call_runtime);
|
| - }
|
| + __ b(mi, (result_type_ <= BinaryOpIC::INT32)
|
| + ? &transition
|
| + : &return_heap_number);
|
| break;
|
| case Token::SHL:
|
| __ and_(r2, r2, Operand(0x1f));
|
| @@ -3103,31 +2764,22 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
|
| &call_runtime,
|
| mode_);
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - if (op_ != Token::SHR) {
|
| - // Convert the result to a floating point value.
|
| - __ vmov(double_scratch.low(), r2);
|
| - __ vcvt_f64_s32(double_scratch, double_scratch.low());
|
| - } else {
|
| - // The result must be interpreted as an unsigned 32-bit integer.
|
| - __ vmov(double_scratch.low(), r2);
|
| - __ vcvt_f64_u32(double_scratch, double_scratch.low());
|
| - }
|
| -
|
| - // Store the result.
|
| - __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
|
| - __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
|
| - __ mov(r0, heap_number_result);
|
| - __ Ret();
|
| + if (op_ != Token::SHR) {
|
| + // Convert the result to a floating point value.
|
| + __ vmov(double_scratch.low(), r2);
|
| + __ vcvt_f64_s32(double_scratch, double_scratch.low());
|
| } else {
|
| - // Tail call that writes the int32 in r2 to the heap number in r0, using
|
| - // r3 as scratch. r0 is preserved and returned.
|
| - __ mov(r0, r5);
|
| - WriteInt32ToHeapNumberStub stub(r2, r0, r3);
|
| - __ TailCallStub(&stub);
|
| + // The result must be interpreted as an unsigned 32-bit integer.
|
| + __ vmov(double_scratch.low(), r2);
|
| + __ vcvt_f64_u32(double_scratch, double_scratch.low());
|
| }
|
|
|
| + // Store the result.
|
| + __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
|
| + __ vstr(double_scratch, r0, HeapNumber::kValueOffset);
|
| + __ mov(r0, heap_number_result);
|
| + __ Ret();
|
| +
|
| break;
|
| }
|
|
|
| @@ -3306,100 +2958,96 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
| const Register cache_entry = r0;
|
| const bool tagged = (argument_type_ == TAGGED);
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - if (tagged) {
|
| - // Argument is a number and is on stack and in r0.
|
| - // Load argument and check if it is a smi.
|
| - __ JumpIfNotSmi(r0, &input_not_smi);
|
| -
|
| - // Input is a smi. Convert to double and load the low and high words
|
| - // of the double into r2, r3.
|
| - __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
|
| - __ b(&loaded);
|
| -
|
| - __ bind(&input_not_smi);
|
| - // Check if input is a HeapNumber.
|
| - __ CheckMap(r0,
|
| - r1,
|
| - Heap::kHeapNumberMapRootIndex,
|
| - &calculate,
|
| - DONT_DO_SMI_CHECK);
|
| - // Input is a HeapNumber. Load it to a double register and store the
|
| - // low and high words into r2, r3.
|
| - __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
|
| - __ vmov(r2, r3, d0);
|
| - } else {
|
| - // Input is untagged double in d2. Output goes to d2.
|
| - __ vmov(r2, r3, d2);
|
| - }
|
| - __ bind(&loaded);
|
| - // r2 = low 32 bits of double value
|
| - // r3 = high 32 bits of double value
|
| - // Compute hash (the shifts are arithmetic):
|
| - // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
|
| - __ eor(r1, r2, Operand(r3));
|
| - __ eor(r1, r1, Operand(r1, ASR, 16));
|
| - __ eor(r1, r1, Operand(r1, ASR, 8));
|
| - ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
|
| - __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
|
| -
|
| - // r2 = low 32 bits of double value.
|
| - // r3 = high 32 bits of double value.
|
| - // r1 = TranscendentalCache::hash(double value).
|
| - Isolate* isolate = masm->isolate();
|
| - ExternalReference cache_array =
|
| - ExternalReference::transcendental_cache_array_address(isolate);
|
| - __ mov(cache_entry, Operand(cache_array));
|
| - // cache_entry points to cache array.
|
| - int cache_array_index
|
| - = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
|
| - __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
|
| - // r0 points to the cache for the type type_.
|
| - // If NULL, the cache hasn't been initialized yet, so go through runtime.
|
| - __ cmp(cache_entry, Operand::Zero());
|
| - __ b(eq, &invalid_cache);
|
| + if (tagged) {
|
| + // Argument is a number and is on stack and in r0.
|
| + // Load argument and check if it is a smi.
|
| + __ JumpIfNotSmi(r0, &input_not_smi);
|
| +
|
| + // Input is a smi. Convert to double and load the low and high words
|
| + // of the double into r2, r3.
|
| + __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
|
| + __ b(&loaded);
|
| +
|
| + __ bind(&input_not_smi);
|
| + // Check if input is a HeapNumber.
|
| + __ CheckMap(r0,
|
| + r1,
|
| + Heap::kHeapNumberMapRootIndex,
|
| + &calculate,
|
| + DONT_DO_SMI_CHECK);
|
| + // Input is a HeapNumber. Load it to a double register and store the
|
| + // low and high words into r2, r3.
|
| + __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
|
| + __ vmov(r2, r3, d0);
|
| + } else {
|
| + // Input is untagged double in d2. Output goes to d2.
|
| + __ vmov(r2, r3, d2);
|
| + }
|
| + __ bind(&loaded);
|
| + // r2 = low 32 bits of double value
|
| + // r3 = high 32 bits of double value
|
| + // Compute hash (the shifts are arithmetic):
|
| + // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
|
| + __ eor(r1, r2, Operand(r3));
|
| + __ eor(r1, r1, Operand(r1, ASR, 16));
|
| + __ eor(r1, r1, Operand(r1, ASR, 8));
|
| + ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
|
| + __ And(r1, r1, Operand(TranscendentalCache::SubCache::kCacheSize - 1));
|
| +
|
| + // r2 = low 32 bits of double value.
|
| + // r3 = high 32 bits of double value.
|
| + // r1 = TranscendentalCache::hash(double value).
|
| + Isolate* isolate = masm->isolate();
|
| + ExternalReference cache_array =
|
| + ExternalReference::transcendental_cache_array_address(isolate);
|
| + __ mov(cache_entry, Operand(cache_array));
|
| + // cache_entry points to cache array.
|
| + int cache_array_index
|
| + = type_ * sizeof(isolate->transcendental_cache()->caches_[0]);
|
| + __ ldr(cache_entry, MemOperand(cache_entry, cache_array_index));
|
| + // r0 points to the cache for the type type_.
|
| + // If NULL, the cache hasn't been initialized yet, so go through runtime.
|
| + __ cmp(cache_entry, Operand::Zero());
|
| + __ b(eq, &invalid_cache);
|
|
|
| #ifdef DEBUG
|
| - // Check that the layout of cache elements match expectations.
|
| - { TranscendentalCache::SubCache::Element test_elem[2];
|
| - char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
|
| - char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
|
| - char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
|
| - char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
|
| - char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
|
| - CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
|
| - CHECK_EQ(0, elem_in0 - elem_start);
|
| - CHECK_EQ(kIntSize, elem_in1 - elem_start);
|
| - CHECK_EQ(2 * kIntSize, elem_out - elem_start);
|
| - }
|
| + // Check that the layout of cache elements match expectations.
|
| + { TranscendentalCache::SubCache::Element test_elem[2];
|
| + char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
|
| + char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
|
| + char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
|
| + char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
|
| + char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
|
| + CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
|
| + CHECK_EQ(0, elem_in0 - elem_start);
|
| + CHECK_EQ(kIntSize, elem_in1 - elem_start);
|
| + CHECK_EQ(2 * kIntSize, elem_out - elem_start);
|
| + }
|
| #endif
|
|
|
| - // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
|
| - __ add(r1, r1, Operand(r1, LSL, 1));
|
| - __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
|
| - // Check if cache matches: Double value is stored in uint32_t[2] array.
|
| - __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
|
| - __ cmp(r2, r4);
|
| - __ cmp(r3, r5, eq);
|
| - __ b(ne, &calculate);
|
| - // Cache hit. Load result, cleanup and return.
|
| - Counters* counters = masm->isolate()->counters();
|
| - __ IncrementCounter(
|
| - counters->transcendental_cache_hit(), 1, scratch0, scratch1);
|
| - if (tagged) {
|
| - // Pop input value from stack and load result into r0.
|
| - __ pop();
|
| - __ mov(r0, Operand(r6));
|
| - } else {
|
| - // Load result into d2.
|
| - __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
|
| - }
|
| - __ Ret();
|
| - } // if (CpuFeatures::IsSupported(VFP3))
|
| + // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
|
| + __ add(r1, r1, Operand(r1, LSL, 1));
|
| + __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
|
| + // Check if cache matches: Double value is stored in uint32_t[2] array.
|
| + __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
|
| + __ cmp(r2, r4);
|
| + __ cmp(r3, r5, eq);
|
| + __ b(ne, &calculate);
|
| + // Cache hit. Load result, cleanup and return.
|
| + Counters* counters = masm->isolate()->counters();
|
| + __ IncrementCounter(
|
| + counters->transcendental_cache_hit(), 1, scratch0, scratch1);
|
| + if (tagged) {
|
| + // Pop input value from stack and load result into r0.
|
| + __ pop();
|
| + __ mov(r0, Operand(r6));
|
| + } else {
|
| + // Load result into d2.
|
| + __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
|
| + }
|
| + __ Ret();
|
|
|
| __ bind(&calculate);
|
| - Counters* counters = masm->isolate()->counters();
|
| __ IncrementCounter(
|
| counters->transcendental_cache_miss(), 1, scratch0, scratch1);
|
| if (tagged) {
|
| @@ -3408,9 +3056,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
| ExternalReference(RuntimeFunction(), masm->isolate());
|
| __ TailCallExternalReference(runtime_function, 1, 1);
|
| } else {
|
| - ASSERT(CpuFeatures::IsSupported(VFP2));
|
| - CpuFeatureScope scope(masm, VFP2);
|
| -
|
| Label no_update;
|
| Label skip_cache;
|
|
|
| @@ -3470,7 +3115,6 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
|
|
| void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
|
| Register scratch) {
|
| - ASSERT(masm->IsEnabled(VFP2));
|
| Isolate* isolate = masm->isolate();
|
|
|
| __ push(lr);
|
| @@ -3531,7 +3175,6 @@ void InterruptStub::Generate(MacroAssembler* masm) {
|
|
|
|
|
| void MathPowStub::Generate(MacroAssembler* masm) {
|
| - CpuFeatureScope vfp2_scope(masm, VFP2);
|
| const Register base = r1;
|
| const Register exponent = r2;
|
| const Register heapnumbermap = r5;
|
| @@ -3750,9 +3393,7 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
|
|
|
|
|
| void CodeStub::GenerateFPStubs(Isolate* isolate) {
|
| - SaveFPRegsMode mode = CpuFeatures::IsSupported(VFP2)
|
| - ? kSaveFPRegs
|
| - : kDontSaveFPRegs;
|
| + SaveFPRegsMode mode = kSaveFPRegs;
|
| CEntryStub save_doubles(1, mode);
|
| StoreBufferOverflowStub stub(mode);
|
| // These stubs might already be in the snapshot, detect that and don't
|
| @@ -4014,13 +3655,10 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
|
| // Save callee-saved registers (incl. cp and fp), sp, and lr
|
| __ stm(db_w, sp, kCalleeSaved | lr.bit());
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - // Save callee-saved vfp registers.
|
| - __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
|
| - // Set up the reserved register for 0.0.
|
| - __ vmov(kDoubleRegZero, 0.0);
|
| - }
|
| + // Save callee-saved vfp registers.
|
| + __ vstm(db_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
|
| + // Set up the reserved register for 0.0.
|
| + __ vmov(kDoubleRegZero, 0.0);
|
|
|
| // Get address of argv, see stm above.
|
| // r0: code entry
|
| @@ -4030,9 +3668,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
|
|
|
| // Set up argv in r4.
|
| int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
|
| - }
|
| + offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
|
| __ ldr(r4, MemOperand(sp, offset_to_argv));
|
|
|
| // Push a frame with special values setup to mark it as an entry frame.
|
| @@ -4168,11 +3804,8 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
|
| }
|
| #endif
|
|
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| - // Restore callee-saved vfp registers.
|
| - __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
|
| - }
|
| + // Restore callee-saved vfp registers.
|
| + __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg);
|
|
|
| __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
|
| }
|
| @@ -6877,50 +6510,46 @@ void ICCompareStub::GenerateNumbers(MacroAssembler* masm) {
|
| }
|
|
|
| // Inlining the double comparison and falling back to the general compare
|
| - // stub if NaN is involved or VFP2 is unsupported.
|
| - if (CpuFeatures::IsSupported(VFP2)) {
|
| - CpuFeatureScope scope(masm, VFP2);
|
| -
|
| - // Load left and right operand.
|
| - Label done, left, left_smi, right_smi;
|
| - __ JumpIfSmi(r0, &right_smi);
|
| - __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
|
| - DONT_DO_SMI_CHECK);
|
| - __ sub(r2, r0, Operand(kHeapObjectTag));
|
| - __ vldr(d1, r2, HeapNumber::kValueOffset);
|
| - __ b(&left);
|
| - __ bind(&right_smi);
|
| - __ SmiUntag(r2, r0); // Can't clobber r0 yet.
|
| - SwVfpRegister single_scratch = d2.low();
|
| - __ vmov(single_scratch, r2);
|
| - __ vcvt_f64_s32(d1, single_scratch);
|
| -
|
| - __ bind(&left);
|
| - __ JumpIfSmi(r1, &left_smi);
|
| - __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
|
| - DONT_DO_SMI_CHECK);
|
| - __ sub(r2, r1, Operand(kHeapObjectTag));
|
| - __ vldr(d0, r2, HeapNumber::kValueOffset);
|
| - __ b(&done);
|
| - __ bind(&left_smi);
|
| - __ SmiUntag(r2, r1); // Can't clobber r1 yet.
|
| - single_scratch = d3.low();
|
| - __ vmov(single_scratch, r2);
|
| - __ vcvt_f64_s32(d0, single_scratch);
|
| + // stub if NaN is involved.
|
| + // Load left and right operand.
|
| + Label done, left, left_smi, right_smi;
|
| + __ JumpIfSmi(r0, &right_smi);
|
| + __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
|
| + DONT_DO_SMI_CHECK);
|
| + __ sub(r2, r0, Operand(kHeapObjectTag));
|
| + __ vldr(d1, r2, HeapNumber::kValueOffset);
|
| + __ b(&left);
|
| + __ bind(&right_smi);
|
| + __ SmiUntag(r2, r0); // Can't clobber r0 yet.
|
| + SwVfpRegister single_scratch = d2.low();
|
| + __ vmov(single_scratch, r2);
|
| + __ vcvt_f64_s32(d1, single_scratch);
|
| +
|
| + __ bind(&left);
|
| + __ JumpIfSmi(r1, &left_smi);
|
| + __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
|
| + DONT_DO_SMI_CHECK);
|
| + __ sub(r2, r1, Operand(kHeapObjectTag));
|
| + __ vldr(d0, r2, HeapNumber::kValueOffset);
|
| + __ b(&done);
|
| + __ bind(&left_smi);
|
| + __ SmiUntag(r2, r1); // Can't clobber r1 yet.
|
| + single_scratch = d3.low();
|
| + __ vmov(single_scratch, r2);
|
| + __ vcvt_f64_s32(d0, single_scratch);
|
|
|
| - __ bind(&done);
|
| - // Compare operands.
|
| - __ VFPCompareAndSetFlags(d0, d1);
|
| + __ bind(&done);
|
| + // Compare operands.
|
| + __ VFPCompareAndSetFlags(d0, d1);
|
|
|
| - // Don't base result on status bits when a NaN is involved.
|
| - __ b(vs, &unordered);
|
| + // Don't base result on status bits when a NaN is involved.
|
| + __ b(vs, &unordered);
|
|
|
| - // Return a result of -1, 0, or 1, based on status bits.
|
| - __ mov(r0, Operand(EQUAL), LeaveCC, eq);
|
| - __ mov(r0, Operand(LESS), LeaveCC, lt);
|
| - __ mov(r0, Operand(GREATER), LeaveCC, gt);
|
| - __ Ret();
|
| - }
|
| + // Return a result of -1, 0, or 1, based on status bits.
|
| + __ mov(r0, Operand(EQUAL), LeaveCC, eq);
|
| + __ mov(r0, Operand(LESS), LeaveCC, lt);
|
| + __ mov(r0, Operand(GREATER), LeaveCC, gt);
|
| + __ Ret();
|
|
|
| __ bind(&unordered);
|
| __ bind(&generic_stub);
|
| @@ -7552,7 +7181,7 @@ void RecordWriteStub::GenerateFixedRegStubsAheadOfTime(Isolate* isolate) {
|
|
|
|
|
| bool CodeStub::CanUseFPRegisters() {
|
| - return CpuFeatures::IsSupported(VFP2);
|
| + return true; // VFP2 is a base requirement for V8
|
| }
|
|
|
|
|
|
|