Chromium Code Reviews| Index: src/x64/code-stubs-x64.cc |
| diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc |
| index 0c0c2725cbf3e559c11c5a709985559ae3c4d528..ae0ad646e5984a95b4644a1dd71735df7691c8e1 100644 |
| --- a/src/x64/code-stubs-x64.cc |
| +++ b/src/x64/code-stubs-x64.cc |
| @@ -607,71 +607,87 @@ class FloatingPointHelper : public AllStatic { |
| }; |
| -// Get the integer part of a heap number. |
| -// Overwrites the contents of rdi, rbx and rcx. Result cannot be rdi or rbx. |
| -void IntegerConvert(MacroAssembler* masm, |
| - Register result, |
| - Register source) { |
| - // Result may be rcx. If result and source are the same register, source will |
| - // be overwritten. |
| - ASSERT(!result.is(rdi) && !result.is(rbx)); |
| - // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use |
| - // cvttsd2si (32-bit version) directly. |
| - Register double_exponent = rbx; |
| - Register double_value = rdi; |
| - Label done, exponent_63_plus; |
| - // 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. |
| - __ cmpl(double_exponent, Immediate(63)); |
| - __ j(above_equal, &exponent_63_plus, Label::kNear); |
| - // Handle exponent range 0..62. |
| - __ cvttsd2siq(result, xmm0); |
| - __ jmp(&done, Label::kNear); |
| +void DoubleToIStub::Generate(MacroAssembler* masm) { |
| + Register input_reg = this->source(); |
| + Register final_result_reg = this->destination(); |
| + ASSERT(is_truncating()); |
| - __ 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, Label::kNear); |
| - |
| - // 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); |
| - } |
| + Label check_negative, process_64_bits, done; |
| - __ bind(&done); |
| + int double_offset = offset(); |
| + |
| + // Account for return address and saved regs if input is rsp. |
| + if (input_reg.is(rsp)) double_offset += 3 * kPointerSize; |
| + |
| + MemOperand mantissa_operand(MemOperand(input_reg, double_offset)); |
| + MemOperand exponent_operand(MemOperand(input_reg, |
| + double_offset + kDoubleSize / 2)); |
| + |
| + Register scratch1; |
| + Register scratch_candidates[3] = { rbx, rdx, rdi }; |
| + for (int i = 0; i < 3; i++) { |
| + scratch1 = scratch_candidates[i]; |
| + if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break; |
| + } |
| + |
| + // Since we must use ecx for shifts below, use some other register (eax) |
| + // to calculate the result if ecx is the requested return register. |
|
Yang
2013/07/18 14:54:38
comments do not apply to x64 registers
danno
2013/07/19 08:56:50
Done.
|
| + Register result_reg = final_result_reg.is(rcx) ? rax : final_result_reg; |
| + // Save ecx if it isn't the return register and therefore volatile, or if it |
| + // is the return register, then save the temp register we use in its stead |
| + // for the result. |
| + Register save_reg = final_result_reg.is(rcx) ? rax : rcx; |
| + __ push(scratch1); |
| + __ push(save_reg); |
| + |
| + bool stash_exponent_copy = !input_reg.is(rsp); |
| + __ movl(scratch1, mantissa_operand); |
| + __ movsd(xmm0, mantissa_operand); |
| + __ movl(rcx, exponent_operand); |
| + if (stash_exponent_copy) __ push(rcx); |
| + |
| + __ andl(rcx, Immediate(HeapNumber::kExponentMask)); |
| + __ shrl(rcx, Immediate(HeapNumber::kExponentShift)); |
| + __ leal(result_reg, MemOperand(rcx, -HeapNumber::kExponentBias)); |
| + __ cmpl(result_reg, Immediate(HeapNumber::kMantissaBits)); |
| + __ j(below, &process_64_bits); |
| + |
| + // Result is entirely in lower 32-bits of mantissa |
| + int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize; |
| + __ subl(rcx, Immediate(delta)); |
| + __ xorl(result_reg, result_reg); |
| + __ cmpl(rcx, Immediate(31)); |
| + __ j(above, &done); |
| + __ shll_cl(scratch1); |
| + __ jmp(&check_negative); |
| + |
| + __ bind(&process_64_bits); |
| + __ cvttsd2siq(result_reg, xmm0); |
| + __ jmp(&done, Label::kNear); |
| + |
| + // If the double was negative, negate the integer result. |
| + __ bind(&check_negative); |
| + __ movl(result_reg, scratch1); |
| + __ negl(result_reg); |
|
Yang
2013/07/18 14:54:38
We don't do zero-extension while moving anywhere.
danno
2013/07/19 08:56:50
As discussed, on x64 we ignore the top 32-bits for
|
| + if (stash_exponent_copy) { |
| + __ cmpl(MemOperand(rsp, 0), Immediate(0)); |
| + } else { |
| + __ cmpl(exponent_operand, Immediate(0)); |
| + } |
| + __ cmovl(greater, result_reg, scratch1); |
| + |
| + // Restore registers |
| + __ bind(&done); |
| + if (stash_exponent_copy) { |
| + __ addq(rsp, Immediate(kDoubleSize)); |
| + } |
| + if (!final_result_reg.is(result_reg)) { |
| + ASSERT(final_result_reg.is(rcx)); |
| + __ movl(final_result_reg, result_reg); |
| + } |
| + __ pop(save_reg); |
| + __ pop(scratch1); |
| + __ ret(0); |
| } |
| @@ -1557,12 +1573,18 @@ void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm) { |
| __ JumpIfSmi(rax, &rax_is_smi); |
| __ bind(&rax_is_object); |
| - IntegerConvert(masm, rcx, rax); // Uses rdi, rcx and rbx. |
| + DoubleToIStub stub1(rax, rcx, HeapNumber::kValueOffset - kHeapObjectTag, |
| + true); |
| + __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); |
| + |
| __ jmp(&done); |
| __ bind(&rdx_is_object); |
| - IntegerConvert(masm, rdx, rdx); // Uses rdi, rcx and rbx. |
| + DoubleToIStub stub2(rdx, rdx, HeapNumber::kValueOffset - kHeapObjectTag, |
| + true); |
| + __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); |
| __ JumpIfNotSmi(rax, &rax_is_object); |
| + |
| __ bind(&rax_is_smi); |
| __ SmiToInteger32(rcx, rax); |
| @@ -1597,7 +1619,9 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
| __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); |
| __ j(not_equal, &check_undefined_arg1); |
| // Get the untagged integer version of the rdx heap number in rcx. |
| - IntegerConvert(masm, r8, rdx); |
| + DoubleToIStub stub1(rdx, r8, HeapNumber::kValueOffset - kHeapObjectTag, |
| + true); |
| + __ call(stub1.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); |
| // Here r8 has the untagged integer, rax has a Smi or a heap number. |
| __ bind(&load_arg2); |
| @@ -1617,7 +1641,10 @@ void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
| __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); |
| __ j(not_equal, &check_undefined_arg2); |
| // Get the untagged integer version of the rax heap number in rcx. |
| - IntegerConvert(masm, rcx, rax); |
| + DoubleToIStub stub2(rax, rcx, HeapNumber::kValueOffset - kHeapObjectTag, |
| + true); |
| + __ call(stub2.GetCode(masm->isolate()), RelocInfo::CODE_TARGET); |
| + |
| __ bind(&done); |
| __ movl(rax, r8); |
| } |