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..fb557f95d57036e428bd60b737f51805940e58dc 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 rcx for shifts below, use some other register (rax) |
+ // to calculate the result if ecx is the requested return register. |
+ 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); |
+ 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); |
} |
@@ -3336,7 +3363,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { |
Label first_non_object; |
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); |
__ j(below, &first_non_object, Label::kNear); |
- // Return non-zero (eax (not rax) is not zero) |
+ // Return non-zero (rax (not rax) is not zero) |
Label return_not_equal; |
STATIC_ASSERT(kHeapObjectTag != 0); |
__ bind(&return_not_equal); |
@@ -3398,7 +3425,7 @@ void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { |
masm, &check_for_strings, rdx, kScratchRegister); |
// We've already checked for object identity, so if both operands are |
- // internalized strings they aren't equal. Register eax (not rax) already |
+ // internalized strings they aren't equal. Register rax (not rax) already |
// holds a non-zero value, which indicates not equal, so just return. |
__ ret(0); |
} |