Commit 44fb6cc8 authored by lrn@chromium.org's avatar lrn@chromium.org

X64: Made bit-fiddling fallback for double-to-int32 conversion.

Review URL: http://codereview.chromium.org/2048007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4648 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 39e24860
...@@ -606,6 +606,14 @@ class Assembler : public Malloced { ...@@ -606,6 +606,14 @@ class Assembler : public Malloced {
immediate_arithmetic_op(0x0, dst, src); immediate_arithmetic_op(0x0, dst, src);
} }
void sbbl(Register dst, Register src) {
if (dst.low_bits() == 4) { // Forces SIB byte if dst is base register.
arithmetic_op_32(0x19, src, dst);
} else {
arithmetic_op_32(0x1b, dst, src);
}
}
void cmpb(Register dst, Immediate src) { void cmpb(Register dst, Immediate src) {
immediate_arithmetic_op_8(0x7, dst, src); immediate_arithmetic_op_8(0x7, dst, src);
} }
......
...@@ -8030,28 +8030,70 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, ...@@ -8030,28 +8030,70 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm,
// Get the integer part of a heap number. // Get the integer part of a heap number.
// Trashes rdi and rbx. Dest is rcx. Source cannot be rcx or one of the // Overwrites the contents of rdi, rbx and rcx. Result cannot be rdi or rbx.
// trashed registers.
void IntegerConvert(MacroAssembler* masm, void IntegerConvert(MacroAssembler* masm,
Register source, Register result,
Label* conversion_failure) { Register source) {
ASSERT(!source.is(rcx) && !source.is(rdi) && !source.is(rbx)); // Result may be rcx. If result and source are the same register, source will
Register scratch = rbx; // be overwritten.
Register scratch2 = rdi; ASSERT(!result.is(rdi) && !result.is(rbx));
// Get exponent word. // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use
__ movq(scratch2, FieldOperand(source, HeapNumber::kValueOffset)); // cvttsd2si (32-bit version) directly.
// Get exponent alone in scratch2. Register double_exponent = rbx;
__ movq(xmm0, scratch2); Register double_value = rdi;
__ shr(scratch2, Immediate(HeapNumber::kMantissaBits)); Label done, exponent_63_plus;
__ andl(scratch2, Immediate((1 << HeapNumber::KExponentBits) - 1)); // Get double and extract exponent.
__ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset));
// Clear result preemptively, in case we need to return zero.
__ xorl(result, result);
__ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there.
// Double to remove sign bit, shift exponent down to least significant bits.
// and subtract bias to get the unshifted, unbiased exponent.
__ lea(double_exponent, Operand(double_value, double_value, times_1, 0));
__ shr(double_exponent, Immediate(64 - HeapNumber::KExponentBits));
__ subl(double_exponent, Immediate(HeapNumber::kExponentBias));
// Check whether the exponent is too big for a 63 bit unsigned integer. // Check whether the exponent is too big for a 63 bit unsigned integer.
// (Notice: Doesn't handle MIN_SMI). __ cmpl(double_exponent, Immediate(63));
__ cmpl(scratch2, Immediate(63 + HeapNumber::kExponentBias)); __ j(above_equal, &exponent_63_plus);
__ j(greater_equal, conversion_failure); // Handle exponent range 0..62.
// Handle exponent range -inf..62. __ cvttsd2siq(result, xmm0);
__ cvttsd2siq(rcx, xmm0); __ jmp(&done);
// TODO(lrn): Do bit-fiddling for exponents in range 63..84 and return
// zero for everything else (also including negative exponents). __ bind(&exponent_63_plus);
// Exponent negative or 63+.
__ cmpl(double_exponent, Immediate(83));
// If exponent negative or above 83, number contains no significant bits in
// the range 0..2^31, so result is zero, and rcx already holds zero.
__ j(above, &done);
// Exponent in rage 63..83.
// Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely
// the least significant exponent-52 bits.
// Negate low bits of mantissa if value is negative.
__ addq(double_value, double_value); // Move sign bit to carry.
__ sbbl(result, result); // And convert carry to -1 in result register.
// if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0.
__ addl(double_value, result);
// Do xor in opposite directions depending on where we want the result
// (depending on whether result is rcx or not).
if (result.is(rcx)) {
__ xorl(double_value, result);
// Left shift mantissa by (exponent - mantissabits - 1) to save the
// bits that have positional values below 2^32 (the extra -1 comes from the
// doubling done above to move the sign bit into the carry flag).
__ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1));
__ shll_cl(double_value);
__ movl(result, double_value);
} else {
// As the then-branch, but move double-value to result before shifting.
__ xorl(result, double_value);
__ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1));
__ shll_cl(result);
}
__ bind(&done);
} }
...@@ -8101,14 +8143,11 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) { ...@@ -8101,14 +8143,11 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) {
__ j(not_equal, &slow); __ j(not_equal, &slow);
// Convert the heap number in rax to an untagged integer in rcx. // Convert the heap number in rax to an untagged integer in rcx.
IntegerConvert(masm, rax, &slow); IntegerConvert(masm, rax, rax);
// Do the bitwise operation and check if the result fits in a smi. // Do the bitwise operation and smi tag the result.
Label try_float; __ notl(rax);
__ not_(rcx); __ Integer32ToSmi(rax, rax);
// Tag the result as a smi and we're done.
ASSERT(kSmiTagSize == 1);
__ Integer32ToSmi(rax, rcx);
} }
// Return from the stub. // Return from the stub.
...@@ -9704,8 +9743,7 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, ...@@ -9704,8 +9743,7 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
__ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &check_undefined_arg1); __ j(not_equal, &check_undefined_arg1);
// Get the untagged integer version of the edx heap number in rcx. // Get the untagged integer version of the edx heap number in rcx.
IntegerConvert(masm, rdx, conversion_failure); IntegerConvert(masm, rdx, rdx);
__ movl(rdx, rcx);
// Here rdx has the untagged integer, rax has a Smi or a heap number. // Here rdx has the untagged integer, rax has a Smi or a heap number.
__ bind(&load_arg2); __ bind(&load_arg2);
...@@ -9727,7 +9765,7 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, ...@@ -9727,7 +9765,7 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
__ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, &check_undefined_arg2); __ j(not_equal, &check_undefined_arg2);
// Get the untagged integer version of the eax heap number in ecx. // Get the untagged integer version of the eax heap number in ecx.
IntegerConvert(masm, rax, conversion_failure); IntegerConvert(masm, rcx, rax);
__ bind(&done); __ bind(&done);
__ movl(rax, rdx); __ movl(rax, rdx);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment