__ sub(scratch1, object, Operand(kHeapObjectTag));
__ vldr(double_dst, scratch1, HeapNumber::kValueOffset);
- __ EmitVFPTruncate(kRoundToZero,
- scratch1,
- double_dst,
- scratch2,
- double_scratch,
- kCheckForInexactConversion);
-
+ __ TestDoubleIsInt32(double_dst, double_scratch);
// Jump to not_int32 if the operation did not succeed.
__ b(ne, not_int32);
__ sub(scratch1, object, Operand(kHeapObjectTag));
__ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
- __ EmitVFPTruncate(kRoundToZero,
- dst,
- double_scratch0,
- scratch1,
- double_scratch1,
- kCheckForInexactConversion);
-
+ __ TryDoubleToInt32Exact(dst, double_scratch0, double_scratch1);
// Jump to not_int32 if the operation did not succeed.
__ b(ne, not_int32);
} else {
// Otherwise return a heap number if allowed, or jump to type
// transition.
- __ EmitVFPTruncate(kRoundToZero,
- scratch1,
- d5,
- scratch2,
- d8);
-
if (result_type_ <= BinaryOpIC::INT32) {
+ __ TryDoubleToInt32Exact(scratch1, d5, d8);
// If the ne condition is set, result does
// not fit in a 32-bit integer.
__ b(ne, &transition);
+ } else {
+ __ vcvt_s32_f64(s8, d5);
+ __ vmov(scratch1, s8);
}
// Check if the result fits in a smi.
CpuFeatureScope scope(masm(), VFP2);
DwVfpRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
- Register scratch = scratch0();
+ Register input_high = scratch0();
+ Label done, exact;
- __ EmitVFPTruncate(kRoundToMinusInf,
- result,
- input,
- scratch,
- double_scratch0());
- DeoptimizeIf(ne, instr->environment());
+ __ vmov(input_high, input.high());
+ __ TryInt32Floor(result, input, input_high, double_scratch0(), &done, &exact);
+ DeoptimizeIf(al, instr->environment());
+ __ bind(&exact);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
- Label done;
__ cmp(result, Operand::Zero());
__ b(ne, &done);
- __ vmov(scratch, input.high());
- __ tst(scratch, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
- __ bind(&done);
+ __ cmp(input_high, Operand::Zero());
+ DeoptimizeIf(mi, instr->environment());
}
+ __ bind(&done);
}
DwVfpRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp());
- Register scratch = scratch0();
- Label done, check_sign_on_zero;
-
- // Extract exponent bits.
- __ vmov(result, input.high());
- __ ubfx(scratch,
- result,
- HeapNumber::kExponentShift,
- HeapNumber::kExponentBits);
-
- // If the number is in ]-0.5, +0.5[, the result is +/- 0.
- __ cmp(scratch, Operand(HeapNumber::kExponentBias - 2));
- __ mov(result, Operand::Zero(), LeaveCC, le);
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- __ b(le, &check_sign_on_zero);
- } else {
- __ b(le, &done);
- }
-
- // The following conversion will not work with numbers
- // outside of ]-2^32, 2^32[.
- __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32));
- DeoptimizeIf(ge, instr->environment());
-
- __ Vmov(double_scratch0(), 0.5, scratch);
- __ vadd(double_scratch0(), input, double_scratch0());
-
- // Save the original sign for later comparison.
- __ and_(scratch, result, Operand(HeapNumber::kSignMask));
-
- // Check sign of the result: if the sign changed, the input
- // value was in ]0.5, 0[ and the result should be -0.
- __ vmov(result, double_scratch0().high());
- __ eor(result, result, Operand(scratch), SetCC);
+ DwVfpRegister input_plus_dot_five = double_scratch1;
+ Register input_high = scratch0();
+ DwVfpRegister dot_five = double_scratch0();
+ Label convert, done;
+
+ __ Vmov(dot_five, 0.5, scratch0());
+ __ vabs(double_scratch1, input);
+ __ VFPCompareAndSetFlags(double_scratch1, dot_five);
+ // If input is in [-0.5, -0], the result is -0.
+ // If input is in [+0, +0.5[, the result is +0.
+ // If the input is +0.5, the result is 1.
+ __ b(hi, &convert); // Out of [-0.5, +0.5].
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- DeoptimizeIf(mi, instr->environment());
- } else {
- __ mov(result, Operand::Zero(), LeaveCC, mi);
- __ b(mi, &done);
- }
-
- __ EmitVFPTruncate(kRoundToMinusInf,
- result,
- double_scratch0(),
- scratch,
- double_scratch1);
- DeoptimizeIf(ne, instr->environment());
+ __ vmov(input_high, input.high());
+ __ cmp(input_high, Operand::Zero());
+ DeoptimizeIf(mi, instr->environment()); // [-0.5, -0].
+ }
+ __ VFPCompareAndSetFlags(input, dot_five);
+ __ mov(result, Operand(1), LeaveCC, eq); // +0.5.
+ // Remaining cases: [+0, +0.5[ or [-0.5, +0.5[, depending on
+ // flag kBailoutOnMinusZero.
+ __ mov(result, Operand::Zero(), LeaveCC, ne);
+ __ b(&done);
- if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
- // Test for -0.
- __ cmp(result, Operand::Zero());
- __ b(ne, &done);
- __ bind(&check_sign_on_zero);
- __ vmov(scratch, input.high());
- __ tst(scratch, Operand(HeapNumber::kSignMask));
- DeoptimizeIf(ne, instr->environment());
- }
+ __ bind(&convert);
+ __ vadd(input_plus_dot_five, input, dot_five);
+ __ vmov(input_high, input_plus_dot_five.high());
+ // Reuse dot_five (double_scratch0) as we no longer need this value.
+ __ TryInt32Floor(result, input_plus_dot_five, input_high, double_scratch0(),
+ &done, &done);
+ DeoptimizeIf(al, instr->environment());
__ bind(&done);
}
__ sub(ip, input_reg, Operand(kHeapObjectTag));
__ vldr(double_scratch, ip, HeapNumber::kValueOffset);
- __ EmitVFPTruncate(kRoundToZero,
- input_reg,
- double_scratch,
- scratch1,
- double_scratch2,
- kCheckForInexactConversion);
+ __ TryDoubleToInt32Exact(input_reg, double_scratch, double_scratch2);
DeoptimizeIf(ne, instr->environment());
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
scratch2,
scratch3);
} else {
- __ EmitVFPTruncate(kRoundToMinusInf,
- result_reg,
- double_input,
- scratch1,
- double_scratch,
- kCheckForInexactConversion);
-
- // Deoptimize if we had a vfp invalid exception,
- // including inexact operation.
+ __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
+ // Deoptimize if the input wasn't a int32 (inside a double).
DeoptimizeIf(ne, instr->environment());
}
__ bind(&done);
}
-void MacroAssembler::TryFastDoubleToInt32(Register result,
- DwVfpRegister double_input,
- DwVfpRegister double_scratch,
- Label* done) {
+void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input,
+ DwVfpRegister double_scratch) {
ASSERT(!double_input.is(double_scratch));
+ ASSERT(CpuFeatures::IsSupported(VFP2));
+ CpuFeatureScope scope(this, VFP2);
vcvt_s32_f64(double_scratch.low(), double_input);
- vmov(result, double_scratch.low());
vcvt_f64_s32(double_scratch, double_scratch.low());
VFPCompareAndSetFlags(double_input, double_scratch);
- b(eq, done);
}
-void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode,
- Register result,
- DwVfpRegister double_input,
- Register scratch,
- DwVfpRegister double_scratch,
- CheckForInexactConversion check_inexact) {
- ASSERT(!result.is(scratch));
+void MacroAssembler::TryDoubleToInt32Exact(Register result,
+ DwVfpRegister double_input,
+ DwVfpRegister double_scratch) {
ASSERT(!double_input.is(double_scratch));
-
ASSERT(CpuFeatures::IsSupported(VFP2));
CpuFeatureScope scope(this, VFP2);
- Register prev_fpscr = result;
- Label done;
-
- // Test for values that can be exactly represented as a signed 32-bit integer.
- TryFastDoubleToInt32(result, double_input, double_scratch, &done);
-
- // Convert to integer, respecting rounding mode.
- int32_t check_inexact_conversion =
- (check_inexact == kCheckForInexactConversion) ? kVFPInexactExceptionBit : 0;
-
- // Set custom FPCSR:
- // - Set rounding mode.
- // - Clear vfp cumulative exception flags.
- // - Make sure Flush-to-zero mode control bit is unset.
- vmrs(prev_fpscr);
- bic(scratch,
- prev_fpscr,
- Operand(kVFPExceptionMask |
- check_inexact_conversion |
- kVFPRoundingModeMask |
- kVFPFlushToZeroMask));
- // 'Round To Nearest' is encoded by 0b00 so no bits need to be set.
- if (rounding_mode != kRoundToNearest) {
- orr(scratch, scratch, Operand(rounding_mode));
- }
- vmsr(scratch);
-
- // Convert the argument to an integer.
- vcvt_s32_f64(double_scratch.low(),
- double_input,
- (rounding_mode == kRoundToZero) ? kDefaultRoundToZero
- : kFPSCRRounding);
- // Retrieve FPSCR.
- vmrs(scratch);
- // Restore FPSCR.
- vmsr(prev_fpscr);
- // Move the converted value into the result register.
+ vcvt_s32_f64(double_scratch.low(), double_input);
vmov(result, double_scratch.low());
- // Check for vfp exceptions.
- tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion));
+ vcvt_f64_s32(double_scratch, double_scratch.low());
+ VFPCompareAndSetFlags(double_input, double_scratch);
+}
- bind(&done);
+
+void MacroAssembler::TryInt32Floor(Register result,
+ DwVfpRegister double_input,
+ Register input_high,
+ DwVfpRegister double_scratch,
+ Label* done,
+ Label* exact) {
+ ASSERT(!result.is(input_high));
+ ASSERT(!double_input.is(double_scratch));
+ ASSERT(CpuFeatures::IsSupported(VFP2));
+ CpuFeatureScope scope(this, VFP2);
+ Label negative, exception;
+
+ // Test for NaN and infinities.
+ Sbfx(result, input_high,
+ HeapNumber::kExponentShift, HeapNumber::kExponentBits);
+ cmp(result, Operand(-1));
+ b(eq, &exception);
+ // Test for values that can be exactly represented as a
+ // signed 32-bit integer.
+ TryDoubleToInt32Exact(result, double_input, double_scratch);
+ // If exact, return (result already fetched).
+ b(eq, exact);
+ cmp(input_high, Operand::Zero());
+ b(mi, &negative);
+
+ // Input is in ]+0, +inf[.
+ // If result equals 0x7fffffff input was out of range or
+ // in ]0x7fffffff, 0x80000000[. We ignore this last case which
+ // could fits into an int32, that means we always think input was
+ // out of range and always go to exception.
+ // If result < 0x7fffffff, go to done, result fetched.
+ cmn(result, Operand(1));
+ b(mi, &exception);
+ b(done);
+
+ // Input is in ]-inf, -0[.
+ // If x is a non integer negative number,
+ // floor(x) <=> round_to_zero(x) - 1.
+ bind(&negative);
+ sub(result, result, Operand(1), SetCC);
+ // If result is still negative, go to done, result fetched.
+ // Else, we had an overflow and we fall through exception.
+ b(mi, done);
+ bind(&exception);
}
Label done;
// Test if the value can be exactly represented as a signed integer.
- vcvt_s32_f64(double_scratch.low(), double_input);
- vmov(result, double_scratch.low());
- vcvt_f64_s32(double_scratch, double_scratch.low());
- // Note: this comparison is cheaper than reading the FPSCR exception bits.
- VFPCompareAndSetFlags(double_input, double_scratch);
+ TryDoubleToInt32Exact(result, double_input, double_scratch);
b(eq, &done);
// Check the exception flags. If they are not set, we are done.
// If they are set, it could be because of the conversion above, or because
// they were set before this code.
vmrs(scratch);
- tst(scratch, Operand(kVFPOverflowExceptionBit |
- kVFPUnderflowExceptionBit |
- kVFPInvalidOpExceptionBit));
+ tst(scratch, Operand(kVFPInvalidOpExceptionBit));
b(eq, &done);
// Clear cumulative exception flags.
- bic(scratch, scratch, Operand(kVFPExceptionMask));
+ bic(scratch, scratch, Operand(kVFPInvalidOpExceptionBit));
vmsr(scratch);
// Try a conversion to a signed integer.
vcvt_s32_f64(double_scratch.low(), double_input);
// Retrieve the FPSCR.
vmrs(scratch);
- // Check for overflow and NaNs.
- tst(scratch, Operand(kVFPOverflowExceptionBit |
- kVFPUnderflowExceptionBit |
- kVFPInvalidOpExceptionBit));
+ // Check for invalid conversions (out of range and NaNs).
+ tst(scratch, Operand(kVFPInvalidOpExceptionBit));
// If we had no exceptions we are done.
b(eq, &done);
DwVfpRegister double_scratch,
Label *not_int32);
- // Try to convert a double to a signed 32-bit integer. If the double value
- // can be exactly represented as an integer, the code jumps to 'done' and
- // 'result' contains the integer value. Otherwise, the code falls through.
- void TryFastDoubleToInt32(Register result,
- DwVfpRegister double_input,
- DwVfpRegister double_scratch,
- Label* done);
-
- // Truncates a double using a specific rounding mode, and writes the value
- // to the result register.
- // Clears the z flag (ne condition) if an overflow occurs.
- // If kCheckForInexactConversion is passed, the z flag is also cleared if the
- // conversion was inexact, i.e. if the double value could not be converted
- // exactly to a 32-bit integer.
- void EmitVFPTruncate(VFPRoundingMode rounding_mode,
- Register result,
- DwVfpRegister double_input,
- Register scratch,
- DwVfpRegister double_scratch,
- CheckForInexactConversion check
- = kDontCheckForInexactConversion);
+ // Check if a double can be exactly represented as a signed 32-bit integer.
+ // Z flag set to one if true.
+ void TestDoubleIsInt32(DwVfpRegister double_input,
+ DwVfpRegister double_scratch);
+
+ // Try to convert a double to a signed 32-bit integer.
+ // Z flag set to one and result assigned if the conversion is exact.
+ void TryDoubleToInt32Exact(Register result,
+ DwVfpRegister double_input,
+ DwVfpRegister double_scratch);
+
+ // Floor a double and writes the value to the result register.
+ // Go to exact if the conversion is exact (to be able to test -0),
+ // fall through calling code if an overflow occurred, else go to done.
+ void TryInt32Floor(Register result,
+ DwVfpRegister double_input,
+ Register input_high,
+ DwVfpRegister double_scratch,
+ Label* done,
+ Label* exact);
// Helper for EmitECMATruncate.
// This will truncate a floating-point value outside of the signed 32bit
__ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK);
- Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return;
-
- // If vfp3 is enabled, we use the fpu rounding with the RM (round towards
- // minus infinity) mode.
+ Label smi_check, just_return;
// Load the HeapNumber value.
// We will need access to the value in the core registers, so we load it
__ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ vmov(d1, r4, r5);
- // Backup FPSCR.
- __ vmrs(r3);
- // Set custom FPCSR:
- // - Set rounding mode to "Round towards Minus Infinity"
- // (i.e. bits [23:22] = 0b10).
- // - Clear vfp cumulative exception flags (bits [3:0]).
- // - Make sure Flush-to-zero mode control bit is unset (bit 22).
- __ bic(r9, r3,
- Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask));
- __ orr(r9, r9, Operand(kRoundToMinusInf));
- __ vmsr(r9);
-
- // Convert the argument to an integer.
- __ vcvt_s32_f64(s0, d1, kFPSCRRounding);
-
- // Use vcvt latency to start checking for special cases.
- // Get the argument exponent and clear the sign bit.
- __ bic(r6, r5, Operand(HeapNumber::kSignMask));
- __ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord));
-
- // Retrieve FPSCR and check for vfp exceptions.
- __ vmrs(r9);
- __ tst(r9, Operand(kVFPExceptionMask));
- __ b(&no_vfp_exception, eq);
-
- // Check for NaN, Infinity, and -Infinity.
+ // Check for NaN, Infinities and -0.
// They are invariant through a Math.Floor call, so just
// return the original argument.
- __ sub(r7, r6, Operand(HeapNumber::kExponentMask
- >> HeapNumber::kMantissaBitsInTopWord), SetCC);
- __ b(&restore_fpscr_and_return, eq);
- // We had an overflow or underflow in the conversion. Check if we
- // have a big exponent.
- __ cmp(r7, Operand(HeapNumber::kMantissaBits));
- // If greater or equal, the argument is already round and in r0.
- __ b(&restore_fpscr_and_return, ge);
- __ b(&wont_fit_smi);
-
- __ bind(&no_vfp_exception);
- // Move the result back to general purpose register r0.
- __ vmov(r0, s0);
- // Check if the result fits into a smi.
+ __ Sbfx(r3, r5, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
+ __ cmp(r3, Operand(-1));
+ __ b(eq, &just_return);
+ __ eor(r3, r5, Operand(0x80000000u));
+ __ orr(r3, r3, r4, SetCC);
+ __ b(eq, &just_return);
+ // Test for values that can be exactly represented as a
+ // signed 32-bit integer.
+ __ TryDoubleToInt32Exact(r0, d1, d2);
+ // If exact, check smi
+ __ b(eq, &smi_check);
+ __ cmp(r5, Operand(0));
+
+ // If input is in ]+0, +inf[, the cmp has cleared overflow and negative
+ // (V=0 and N=0), the two following instructions won't execute and
+ // we fall through smi_check to check if the result can fit into a smi.
+
+ // If input is in ]-inf, -0[, sub one and, go to slow if we have
+ // an overflow. Else we fall through smi check.
+ // Hint: if x is a negative, non integer number,
+ // floor(x) <=> round_to_zero(x) - 1.
+ __ sub(r0, r0, Operand(1), SetCC, mi);
+ __ b(vs, &slow);
+
+ __ bind(&smi_check);
+ // Check if the result can fit into an smi. If we had an overflow,
+ // the result is either 0x80000000 or 0x7FFFFFFF and won't fit into an smi.
__ add(r1, r0, Operand(0x40000000), SetCC);
- __ b(&wont_fit_smi, mi);
+ // If result doesn't fit into an smi, branch to slow.
+ __ b(&slow, mi);
// Tag the result.
- STATIC_ASSERT(kSmiTag == 0);
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
- // Check for -0.
- __ cmp(r0, Operand::Zero());
- __ b(&restore_fpscr_and_return, ne);
- // r5 already holds the HeapNumber exponent.
- __ tst(r5, Operand(HeapNumber::kSignMask));
- // If our HeapNumber is negative it was -0, so load its address and return.
- // Else r0 is loaded with 0, so we can also just return.
- __ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne);
-
- __ bind(&restore_fpscr_and_return);
- // Restore FPSCR and return.
- __ vmsr(r3);
+ __ bind(&just_return);
__ Drop(argc + 1);
__ Ret();
- __ bind(&wont_fit_smi);
- // Restore FPCSR and fall to slow case.
- __ vmsr(r3);
-
__ bind(&slow);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
DONT_DO_SMI_CHECK);
__ sub(ip, key, Operand(kHeapObjectTag));
__ vldr(double_scratch0, ip, HeapNumber::kValueOffset);
- __ EmitVFPTruncate(kRoundToZero,
- scratch0,
- double_scratch0,
- scratch1,
- double_scratch1,
- kCheckForInexactConversion);
+ __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1);
__ b(ne, fail);
__ TrySmiTag(scratch0, fail, scratch1);
__ mov(key, scratch0);