ARM: Optimsisation of ECMA ToInt32.
BUG=none TEST=none Review URL: https://codereview.chromium.org/12567004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13912 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
1a2454d752
commit
1c6d5e4cf4
@ -745,34 +745,21 @@ void FloatingPointHelper::ConvertNumberToInt32(MacroAssembler* masm,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
DwVfpRegister double_scratch,
|
||||
DwVfpRegister double_scratch1,
|
||||
DwVfpRegister double_scratch2,
|
||||
Label* not_number) {
|
||||
Label done;
|
||||
__ AssertRootValue(heap_number_map,
|
||||
Heap::kHeapNumberMapRootIndex,
|
||||
"HeapNumberMap register clobbered.");
|
||||
Label done;
|
||||
Label not_in_int32_range;
|
||||
|
||||
__ UntagAndJumpIfSmi(dst, object, &done);
|
||||
__ ldr(scratch1, FieldMemOperand(object, HeapNumber::kMapOffset));
|
||||
__ cmp(scratch1, heap_number_map);
|
||||
__ b(ne, not_number);
|
||||
__ ConvertToInt32(object,
|
||||
dst,
|
||||
scratch1,
|
||||
scratch2,
|
||||
double_scratch,
|
||||
¬_in_int32_range);
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(¬_in_int32_range);
|
||||
__ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
|
||||
__ ldr(scratch2, FieldMemOperand(object, HeapNumber::kMantissaOffset));
|
||||
|
||||
__ EmitOutOfInt32RangeTruncate(dst,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch3);
|
||||
__ ECMAConvertNumberToInt32(object, dst,
|
||||
scratch1, scratch2, scratch3,
|
||||
double_scratch1, double_scratch2);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
@ -2290,18 +2277,16 @@ void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void UnaryOpStub::GenerateHeapNumberCodeBitNot(
|
||||
MacroAssembler* masm, Label* slow) {
|
||||
Label impossible;
|
||||
|
||||
void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
|
||||
Label* slow) {
|
||||
EmitCheckForHeapNumber(masm, r0, r1, r6, slow);
|
||||
// Convert the heap number is r0 to an untagged integer in r1.
|
||||
__ ConvertToInt32(r0, r1, r2, r3, d0, slow);
|
||||
// Convert the heap number in r0 to an untagged integer in r1.
|
||||
__ ECMAConvertNumberToInt32(r0, r1, r2, r3, r4, d0, d1);
|
||||
|
||||
// Do the bitwise operation and check if the result fits in a smi.
|
||||
Label try_float;
|
||||
__ mvn(r1, Operand(r1));
|
||||
__ add(r2, r1, Operand(0x40000000), SetCC);
|
||||
__ cmn(r1, Operand(0x40000000));
|
||||
__ b(mi, &try_float);
|
||||
|
||||
// Tag the result as a smi and we're done.
|
||||
@ -2312,28 +2297,22 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
|
||||
__ bind(&try_float);
|
||||
if (mode_ == UNARY_NO_OVERWRITE) {
|
||||
Label slow_allocate_heapnumber, heapnumber_allocated;
|
||||
// Allocate a new heap number without zapping r0, which we need if it fails.
|
||||
__ AllocateHeapNumber(r2, r3, r4, r6, &slow_allocate_heapnumber);
|
||||
__ AllocateHeapNumber(r0, r3, r4, r6, &slow_allocate_heapnumber);
|
||||
__ jmp(&heapnumber_allocated);
|
||||
|
||||
__ bind(&slow_allocate_heapnumber);
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
__ push(r0); // Push the heap number, not the untagged int32.
|
||||
// Push the lower bit of the result (left shifted to look like a smi).
|
||||
__ mov(r2, Operand(r1, LSL, 31));
|
||||
// Push the 31 high bits (bit 0 cleared to look like a smi).
|
||||
__ bic(r1, r1, Operand(1));
|
||||
__ Push(r2, r1);
|
||||
__ CallRuntime(Runtime::kNumberAlloc, 0);
|
||||
__ mov(r2, r0); // Move the new heap number into r2.
|
||||
// Get the heap number into r0, now that the new heap number is in r2.
|
||||
__ pop(r0);
|
||||
__ Pop(r2, r1); // Restore the result.
|
||||
__ orr(r1, r1, Operand(r2, LSR, 31));
|
||||
}
|
||||
|
||||
// Convert the heap number in r0 to an untagged integer in r1.
|
||||
// This can't go slow-case because it's the same number we already
|
||||
// converted once again.
|
||||
__ ConvertToInt32(r0, r1, r3, r4, d0, &impossible);
|
||||
__ mvn(r1, Operand(r1));
|
||||
|
||||
__ bind(&heapnumber_allocated);
|
||||
__ mov(r0, r2); // Move newly allocated heap number to r0.
|
||||
}
|
||||
|
||||
if (CpuFeatures::IsSupported(VFP2)) {
|
||||
@ -2341,8 +2320,7 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
|
||||
CpuFeatureScope scope(masm, VFP2);
|
||||
__ vmov(s0, r1);
|
||||
__ vcvt_f64_s32(d0, s0);
|
||||
__ sub(r2, r0, Operand(kHeapObjectTag));
|
||||
__ vstr(d0, r2, HeapNumber::kValueOffset);
|
||||
__ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
|
||||
__ Ret();
|
||||
} else {
|
||||
// WriteInt32ToHeapNumberStub does not trigger GC, so we do not
|
||||
@ -2350,11 +2328,6 @@ void UnaryOpStub::GenerateHeapNumberCodeBitNot(
|
||||
WriteInt32ToHeapNumberStub stub(r1, r0, r2);
|
||||
__ Jump(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
__ bind(&impossible);
|
||||
if (FLAG_debug_code) {
|
||||
__ stop("Incorrect assumption in bit-not stub");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2786,6 +2759,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
||||
scratch2,
|
||||
scratch3,
|
||||
d0,
|
||||
d1,
|
||||
not_numbers);
|
||||
FloatingPointHelper::ConvertNumberToInt32(masm,
|
||||
right,
|
||||
@ -2795,6 +2769,7 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
|
||||
scratch2,
|
||||
scratch3,
|
||||
d0,
|
||||
d1,
|
||||
not_numbers);
|
||||
}
|
||||
|
||||
|
@ -638,7 +638,8 @@ class FloatingPointHelper : public AllStatic {
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
DwVfpRegister double_scratch,
|
||||
DwVfpRegister double_scratch1,
|
||||
DwVfpRegister double_scratch2,
|
||||
Label* not_int32);
|
||||
|
||||
// Converts the integer (untagged smi) in |int_scratch| to a double, storing
|
||||
|
@ -5254,12 +5254,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
|
||||
__ sub(scratch1, input_reg, Operand(kHeapObjectTag));
|
||||
__ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
|
||||
|
||||
__ EmitECMATruncate(input_reg,
|
||||
double_scratch2,
|
||||
double_scratch,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch3);
|
||||
__ ECMAToInt32VFP(input_reg, double_scratch2, double_scratch,
|
||||
scratch1, scratch2, scratch3);
|
||||
|
||||
} else {
|
||||
CpuFeatureScope scope(masm(), VFP3);
|
||||
@ -5357,12 +5353,8 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
|
||||
|
||||
if (instr->truncating()) {
|
||||
Register scratch3 = ToRegister(instr->temp2());
|
||||
__ EmitECMATruncate(result_reg,
|
||||
double_input,
|
||||
double_scratch,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch3);
|
||||
__ ECMAToInt32VFP(result_reg, double_input, double_scratch,
|
||||
scratch1, scratch2, scratch3);
|
||||
} else {
|
||||
__ TryDoubleToInt32Exact(result_reg, double_input, double_scratch);
|
||||
// Deoptimize if the input wasn't a int32 (inside a double).
|
||||
|
@ -2436,105 +2436,6 @@ void MacroAssembler::SmiToDoubleVFPRegister(Register smi,
|
||||
}
|
||||
|
||||
|
||||
// Tries to get a signed int32 out of a double precision floating point heap
|
||||
// number. Rounds towards 0. Branch to 'not_int32' if the double is out of the
|
||||
// 32bits signed integer range.
|
||||
void MacroAssembler::ConvertToInt32(Register source,
|
||||
Register dest,
|
||||
Register scratch,
|
||||
Register scratch2,
|
||||
DwVfpRegister double_scratch,
|
||||
Label *not_int32) {
|
||||
if (CpuFeatures::IsSupported(VFP2)) {
|
||||
CpuFeatureScope scope(this, VFP2);
|
||||
sub(scratch, source, Operand(kHeapObjectTag));
|
||||
vldr(double_scratch, scratch, HeapNumber::kValueOffset);
|
||||
vcvt_s32_f64(double_scratch.low(), double_scratch);
|
||||
vmov(dest, double_scratch.low());
|
||||
// Signed vcvt instruction will saturate to the minimum (0x80000000) or
|
||||
// maximun (0x7fffffff) signed 32bits integer when the double is out of
|
||||
// range. When substracting one, the minimum signed integer becomes the
|
||||
// maximun signed integer.
|
||||
sub(scratch, dest, Operand(1));
|
||||
cmp(scratch, Operand(LONG_MAX - 1));
|
||||
// If equal then dest was LONG_MAX, if greater dest was LONG_MIN.
|
||||
b(ge, not_int32);
|
||||
} else {
|
||||
// This code is faster for doubles that are in the ranges -0x7fffffff to
|
||||
// -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds almost to
|
||||
// the range of signed int32 values that are not Smis. Jumps to the label
|
||||
// 'not_int32' if the double isn't in the range -0x80000000.0 to
|
||||
// 0x80000000.0 (excluding the endpoints).
|
||||
Label right_exponent, done;
|
||||
// Get exponent word.
|
||||
ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset));
|
||||
// Get exponent alone in scratch2.
|
||||
Ubfx(scratch2,
|
||||
scratch,
|
||||
HeapNumber::kExponentShift,
|
||||
HeapNumber::kExponentBits);
|
||||
// Load dest with zero. We use this either for the final shift or
|
||||
// for the answer.
|
||||
mov(dest, Operand::Zero());
|
||||
// Check whether the exponent matches a 32 bit signed int that is not a Smi.
|
||||
// A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
|
||||
// the exponent that we are fastest at and also the highest exponent we can
|
||||
// handle here.
|
||||
const uint32_t non_smi_exponent = HeapNumber::kExponentBias + 30;
|
||||
// The non_smi_exponent, 0x41d, is too big for ARM's immediate field so we
|
||||
// split it up to avoid a constant pool entry. You can't do that in general
|
||||
// for cmp because of the overflow flag, but we know the exponent is in the
|
||||
// range 0-2047 so there is no overflow.
|
||||
int fudge_factor = 0x400;
|
||||
sub(scratch2, scratch2, Operand(fudge_factor));
|
||||
cmp(scratch2, Operand(non_smi_exponent - fudge_factor));
|
||||
// If we have a match of the int32-but-not-Smi exponent then skip some
|
||||
// logic.
|
||||
b(eq, &right_exponent);
|
||||
// If the exponent is higher than that then go to slow case. This catches
|
||||
// numbers that don't fit in a signed int32, infinities and NaNs.
|
||||
b(gt, not_int32);
|
||||
|
||||
// We know the exponent is smaller than 30 (biased). If it is less than
|
||||
// 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
|
||||
// it rounds to zero.
|
||||
const uint32_t zero_exponent = HeapNumber::kExponentBias + 0;
|
||||
sub(scratch2, scratch2, Operand(zero_exponent - fudge_factor), SetCC);
|
||||
// Dest already has a Smi zero.
|
||||
b(lt, &done);
|
||||
|
||||
// We have an exponent between 0 and 30 in scratch2. Subtract from 30 to
|
||||
// get how much to shift down.
|
||||
rsb(dest, scratch2, Operand(30));
|
||||
|
||||
bind(&right_exponent);
|
||||
// Get the top bits of the mantissa.
|
||||
and_(scratch2, scratch, Operand(HeapNumber::kMantissaMask));
|
||||
// Put back the implicit 1.
|
||||
orr(scratch2, scratch2, Operand(1 << HeapNumber::kExponentShift));
|
||||
// Shift up the mantissa bits to take up the space the exponent used to
|
||||
// take. We just orred in the implicit bit so that took care of one and
|
||||
// we want to leave the sign bit 0 so we subtract 2 bits from the shift
|
||||
// distance.
|
||||
const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
|
||||
mov(scratch2, Operand(scratch2, LSL, shift_distance));
|
||||
// Put sign in zero flag.
|
||||
tst(scratch, Operand(HeapNumber::kSignMask));
|
||||
// Get the second half of the double. For some exponents we don't
|
||||
// actually need this because the bits get shifted out again, but
|
||||
// it's probably slower to test than just to do it.
|
||||
ldr(scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset));
|
||||
// Shift down 22 bits to get the last 10 bits.
|
||||
orr(scratch, scratch2, Operand(scratch, LSR, 32 - shift_distance));
|
||||
// Move down according to the exponent.
|
||||
mov(dest, Operand(scratch, LSR, dest));
|
||||
// Fix sign if sign bit was set.
|
||||
rsb(dest, dest, Operand::Zero(), LeaveCC, ne);
|
||||
bind(&done);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input,
|
||||
DwVfpRegister double_scratch) {
|
||||
ASSERT(!double_input.is(double_scratch));
|
||||
@ -2608,85 +2509,32 @@ void MacroAssembler::TryInt32Floor(Register result,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result,
|
||||
Register input_high,
|
||||
Register input_low,
|
||||
Register scratch) {
|
||||
Label done, normal_exponent, restore_sign;
|
||||
|
||||
// Extract the biased exponent in result.
|
||||
Ubfx(result,
|
||||
input_high,
|
||||
HeapNumber::kExponentShift,
|
||||
HeapNumber::kExponentBits);
|
||||
|
||||
// Check for Infinity and NaNs, which should return 0.
|
||||
cmp(result, Operand(HeapNumber::kExponentMask));
|
||||
mov(result, Operand::Zero(), LeaveCC, eq);
|
||||
b(eq, &done);
|
||||
|
||||
// Express exponent as delta to (number of mantissa bits + 31).
|
||||
sub(result,
|
||||
result,
|
||||
Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31),
|
||||
SetCC);
|
||||
|
||||
// If the delta is strictly positive, all bits would be shifted away,
|
||||
// which means that we can return 0.
|
||||
b(le, &normal_exponent);
|
||||
mov(result, Operand::Zero());
|
||||
b(&done);
|
||||
|
||||
bind(&normal_exponent);
|
||||
const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1;
|
||||
// Calculate shift.
|
||||
add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC);
|
||||
|
||||
// Save the sign.
|
||||
Register sign = result;
|
||||
result = no_reg;
|
||||
and_(sign, input_high, Operand(HeapNumber::kSignMask));
|
||||
|
||||
// Set the implicit 1 before the mantissa part in input_high.
|
||||
orr(input_high,
|
||||
input_high,
|
||||
Operand(1 << HeapNumber::kMantissaBitsInTopWord));
|
||||
// Shift the mantissa bits to the correct position.
|
||||
// We don't need to clear non-mantissa bits as they will be shifted away.
|
||||
// If they weren't, it would mean that the answer is in the 32bit range.
|
||||
mov(input_high, Operand(input_high, LSL, scratch));
|
||||
|
||||
// Replace the shifted bits with bits from the lower mantissa word.
|
||||
Label pos_shift, shift_done;
|
||||
rsb(scratch, scratch, Operand(32), SetCC);
|
||||
b(&pos_shift, ge);
|
||||
|
||||
// Negate scratch.
|
||||
rsb(scratch, scratch, Operand::Zero());
|
||||
mov(input_low, Operand(input_low, LSL, scratch));
|
||||
b(&shift_done);
|
||||
|
||||
bind(&pos_shift);
|
||||
mov(input_low, Operand(input_low, LSR, scratch));
|
||||
|
||||
bind(&shift_done);
|
||||
orr(input_high, input_high, Operand(input_low));
|
||||
// Restore sign if necessary.
|
||||
cmp(sign, Operand::Zero());
|
||||
result = sign;
|
||||
sign = no_reg;
|
||||
rsb(result, input_high, Operand::Zero(), LeaveCC, ne);
|
||||
mov(result, input_high, LeaveCC, eq);
|
||||
bind(&done);
|
||||
void MacroAssembler::ECMAConvertNumberToInt32(Register source,
|
||||
Register result,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low,
|
||||
DwVfpRegister double_scratch1,
|
||||
DwVfpRegister double_scratch2) {
|
||||
if (CpuFeatures::IsSupported(VFP2)) {
|
||||
CpuFeatureScope scope(this, VFP2);
|
||||
vldr(double_scratch1, FieldMemOperand(source, HeapNumber::kValueOffset));
|
||||
ECMAToInt32VFP(result, double_scratch1, double_scratch2,
|
||||
scratch, input_high, input_low);
|
||||
} else {
|
||||
Ldrd(input_low, input_high,
|
||||
FieldMemOperand(source, HeapNumber::kValueOffset));
|
||||
ECMAToInt32NoVFP(result, scratch, input_high, input_low);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::EmitECMATruncate(Register result,
|
||||
DwVfpRegister double_input,
|
||||
DwVfpRegister double_scratch,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low) {
|
||||
void MacroAssembler::ECMAToInt32VFP(Register result,
|
||||
DwVfpRegister double_input,
|
||||
DwVfpRegister double_scratch,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low) {
|
||||
CpuFeatureScope scope(this, VFP2);
|
||||
ASSERT(!input_high.is(result));
|
||||
ASSERT(!input_low.is(result));
|
||||
@ -2696,38 +2544,138 @@ void MacroAssembler::EmitECMATruncate(Register result,
|
||||
!scratch.is(input_low));
|
||||
ASSERT(!double_input.is(double_scratch));
|
||||
|
||||
Label done;
|
||||
Label overflow, out_of_range, negate, done;
|
||||
|
||||
// Test if the value can be exactly represented as a signed integer.
|
||||
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(kVFPInvalidOpExceptionBit));
|
||||
b(eq, &done);
|
||||
|
||||
// Clear cumulative exception flags.
|
||||
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 invalid conversions (out of range and NaNs).
|
||||
tst(scratch, Operand(kVFPInvalidOpExceptionBit));
|
||||
// If we had no exceptions we are done.
|
||||
b(eq, &done);
|
||||
|
||||
// Load the double value and perform a manual truncation.
|
||||
vmov(input_low, input_high, double_input);
|
||||
EmitOutOfInt32RangeTruncate(result,
|
||||
input_high,
|
||||
input_low,
|
||||
scratch);
|
||||
bind(&done);
|
||||
Ubfx(scratch, input_high,
|
||||
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
|
||||
// Load scratch with exponent - 1. This is faster than loading
|
||||
// with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
|
||||
sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
|
||||
// Compare exponent with 31 (compare exponent - 1 with 30).
|
||||
cmp(scratch, Operand(30));
|
||||
b(ge, &overflow);
|
||||
// Exponent is less than 31 so vcvt will never saturate.
|
||||
// So, just return the result.
|
||||
vcvt_s32_f64(double_scratch.low(), double_input);
|
||||
vmov(result, double_scratch.low());
|
||||
b(&done);
|
||||
|
||||
bind(&overflow);
|
||||
// If exponent is greater than or equal to 84, the 32 less significant
|
||||
// bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
|
||||
// the result is 0.
|
||||
// This test also catch Nan and infinities which also return 0.
|
||||
// Compare exponent with 84 (compare exponent - 1 with 83).
|
||||
cmp(scratch, Operand(83));
|
||||
b(ge, &out_of_range);
|
||||
|
||||
// If we reach this code, 31 <= exponent <= 83.
|
||||
// So, we don't have to handle cases where 0 <= exponent <= 20 for
|
||||
// which we would need to shift right the high part of the mantissa.
|
||||
ECMAToInt32Tail(result, scratch, input_high, input_low,
|
||||
&out_of_range, &negate, &done);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::ECMAToInt32NoVFP(Register result,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low) {
|
||||
ASSERT(!result.is(scratch));
|
||||
ASSERT(!result.is(input_high));
|
||||
ASSERT(!result.is(input_low));
|
||||
ASSERT(!scratch.is(input_high));
|
||||
ASSERT(!scratch.is(input_low));
|
||||
ASSERT(!input_high.is(input_low));
|
||||
|
||||
Label both, out_of_range, negate, done;
|
||||
|
||||
Ubfx(scratch, input_high,
|
||||
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
|
||||
// Load scratch with exponent - 1. This is faster than loading
|
||||
// with exponent because Bias + 1 = 1024 which is an *ARM* immediate value.
|
||||
sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1));
|
||||
// If exponent is negative, 0 < input < 1, the result is 0.
|
||||
// If exponent is greater than or equal to 84, the 32 less significant
|
||||
// bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits),
|
||||
// the result is 0.
|
||||
// This test also catch Nan and infinities which also return 0.
|
||||
// Compare exponent with 84 (compare exponent - 1 with 83).
|
||||
cmp(scratch, Operand(83));
|
||||
// We do an unsigned comparison so negative numbers are treated as big
|
||||
// positive number and the two tests above are done in one test.
|
||||
b(hs, &out_of_range);
|
||||
|
||||
// Load scratch with 20 - exponent (load with 19 - (exponent - 1)).
|
||||
rsb(scratch, scratch, Operand(19), SetCC);
|
||||
b(mi, &both);
|
||||
|
||||
// 0 <= exponent <= 20, shift only input_high.
|
||||
// Scratch contains: 20 - exponent.
|
||||
Ubfx(result, input_high,
|
||||
0, HeapNumber::kMantissaBitsInTopWord);
|
||||
// Set the implicit 1 before the mantissa part in input_high.
|
||||
orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord));
|
||||
mov(result, Operand(result, LSR, scratch));
|
||||
b(&negate);
|
||||
|
||||
bind(&both);
|
||||
// Restore scratch to exponent - 1 to be consistent with ECMAToInt32VFP.
|
||||
rsb(scratch, scratch, Operand(19));
|
||||
ECMAToInt32Tail(result, scratch, input_high, input_low,
|
||||
&out_of_range, &negate, &done);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::ECMAToInt32Tail(Register result,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low,
|
||||
Label* out_of_range,
|
||||
Label* negate,
|
||||
Label* done) {
|
||||
Label only_low;
|
||||
|
||||
// On entry, scratch contains exponent - 1.
|
||||
// Load scratch with 52 - exponent (load with 51 - (exponent - 1)).
|
||||
rsb(scratch, scratch, Operand(51), SetCC);
|
||||
b(ls, &only_low);
|
||||
// 21 <= exponent <= 51, shift input_low and input_high
|
||||
// to generate the result.
|
||||
mov(input_low, Operand(input_low, LSR, scratch));
|
||||
// Scratch contains: 52 - exponent.
|
||||
// We needs: exponent - 20.
|
||||
// So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20.
|
||||
rsb(scratch, scratch, Operand(32));
|
||||
Ubfx(result, input_high,
|
||||
0, HeapNumber::kMantissaBitsInTopWord);
|
||||
// Set the implicit 1 before the mantissa part in input_high.
|
||||
orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord));
|
||||
orr(result, input_low, Operand(result, LSL, scratch));
|
||||
b(negate);
|
||||
|
||||
bind(out_of_range);
|
||||
mov(result, Operand::Zero());
|
||||
b(done);
|
||||
|
||||
bind(&only_low);
|
||||
// 52 <= exponent <= 83, shift only input_low.
|
||||
// On entry, scratch contains: 52 - exponent.
|
||||
rsb(scratch, scratch, Operand::Zero());
|
||||
mov(result, Operand(input_low, LSL, scratch));
|
||||
|
||||
bind(negate);
|
||||
// If input was positive, input_high ASR 31 equals 0 and
|
||||
// input_high LSR 31 equals zero.
|
||||
// New result = (result eor 0) + 0 = result.
|
||||
// If the input was negative, we have to negate the result.
|
||||
// Input_high ASR 31 equals 0xffffffff and input_high LSR 31 equals 1.
|
||||
// New result = (result eor 0xffffffff) + 1 = 0 - result.
|
||||
eor(result, result, Operand(input_high, ASR, 31));
|
||||
add(result, result, Operand(input_high, LSR, 31));
|
||||
|
||||
bind(done);
|
||||
}
|
||||
|
||||
|
||||
|
@ -933,17 +933,6 @@ class MacroAssembler: public Assembler {
|
||||
Register scratch1,
|
||||
SwVfpRegister scratch2);
|
||||
|
||||
// Convert the HeapNumber pointed to by source to a 32bits signed integer
|
||||
// dest. If the HeapNumber does not fit into a 32bits signed integer branch
|
||||
// to not_int32 label. If VFP3 is available double_scratch is used but not
|
||||
// scratch2.
|
||||
void ConvertToInt32(Register source,
|
||||
Register dest,
|
||||
Register scratch,
|
||||
Register scratch2,
|
||||
DwVfpRegister double_scratch,
|
||||
Label *not_int32);
|
||||
|
||||
// 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,
|
||||
@ -965,26 +954,34 @@ class MacroAssembler: public Assembler {
|
||||
Label* done,
|
||||
Label* exact);
|
||||
|
||||
// Helper for EmitECMATruncate.
|
||||
// This will truncate a floating-point value outside of the signed 32bit
|
||||
// integer range to a 32bit signed integer.
|
||||
// Expects the double value loaded in input_high and input_low.
|
||||
// Exits with the answer in 'result'.
|
||||
// Note that this code does not work for values in the 32bit range!
|
||||
void EmitOutOfInt32RangeTruncate(Register result,
|
||||
Register input_high,
|
||||
Register input_low,
|
||||
Register scratch);
|
||||
// Performs a truncating conversion of a heap floating point number as used by
|
||||
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
|
||||
// Exits with 'result' holding the answer.
|
||||
void ECMAConvertNumberToInt32(Register source,
|
||||
Register result,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low,
|
||||
DwVfpRegister double_scratch1,
|
||||
DwVfpRegister double_scratch2);
|
||||
|
||||
// Performs a truncating conversion of a floating point number as used by
|
||||
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
|
||||
// Exits with 'result' holding the answer and all other registers clobbered.
|
||||
void EmitECMATruncate(Register result,
|
||||
DwVfpRegister double_input,
|
||||
DwVfpRegister double_scratch,
|
||||
void ECMAToInt32VFP(Register result,
|
||||
DwVfpRegister double_input,
|
||||
DwVfpRegister double_scratch,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low);
|
||||
|
||||
// Performs a truncating conversion of a floating point number as used by
|
||||
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
|
||||
// Exits with 'result' holding the answer.
|
||||
void ECMAToInt32NoVFP(Register result,
|
||||
Register scratch,
|
||||
Register scratch2,
|
||||
Register scratch3);
|
||||
Register input_high,
|
||||
Register input_low);
|
||||
|
||||
// Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz
|
||||
// instruction. On pre-ARM5 hardware this routine gives the wrong answer
|
||||
@ -1365,6 +1362,16 @@ class MacroAssembler: public Assembler {
|
||||
// it. See the implementation for register usage.
|
||||
void JumpToHandlerEntry();
|
||||
|
||||
// Helper for ECMAToInt32VFP and ECMAToInt32NoVFP.
|
||||
// It is expected that 31 <= exponent <= 83, and scratch is exponent - 1.
|
||||
void ECMAToInt32Tail(Register result,
|
||||
Register scratch,
|
||||
Register input_high,
|
||||
Register input_low,
|
||||
Label* out_of_range,
|
||||
Label* negate,
|
||||
Label* done);
|
||||
|
||||
// Compute memory operands for safepoint stack slots.
|
||||
static int SafepointRegisterStackIndex(int reg_code);
|
||||
MemOperand SafepointRegisterSlot(Register reg);
|
||||
|
@ -3512,7 +3512,7 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray(
|
||||
// not include -kHeapObjectTag into it.
|
||||
__ sub(r5, value, Operand(kHeapObjectTag));
|
||||
__ vldr(d0, r5, HeapNumber::kValueOffset);
|
||||
__ EmitECMATruncate(r5, d0, d1, r6, r7, r9);
|
||||
__ ECMAToInt32VFP(r5, d0, d1, r6, r7, r9);
|
||||
|
||||
switch (elements_kind) {
|
||||
case EXTERNAL_BYTE_ELEMENTS:
|
||||
|
Loading…
Reference in New Issue
Block a user