Chromium Code Reviews| Index: src/ia32/codegen-ia32.cc |
| =================================================================== |
| --- src/ia32/codegen-ia32.cc (revision 3685) |
| +++ src/ia32/codegen-ia32.cc (working copy) |
| @@ -741,6 +741,12 @@ |
| } |
| +enum ArgLocation { |
|
Kevin Millikin (Chromium)
2010/01/25 16:27:44
It seems like this should be a member of FloatingP
Vladislav Kaznacheev
2010/01/25 17:44:53
Done.
|
| + ARGS_ON_STACK, |
| + ARGS_IN_REGISTERS |
| +}; |
| + |
| + |
| class FloatingPointHelper : public AllStatic { |
| public: |
| // Code pattern for loading a floating point value. Input value must |
| @@ -750,9 +756,18 @@ |
| static void LoadFloatOperand(MacroAssembler* masm, Register number); |
| // Code pattern for loading floating point values. Input values must |
| // be either smi or heap number objects (fp values). Requirements: |
| - // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as |
| - // floating point numbers on FPU stack. |
| - static void LoadFloatOperands(MacroAssembler* masm, Register scratch); |
| + // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. |
| + // Returns operands as floating point numbers on FPU stack. |
| + static void LoadFloatOperands(MacroAssembler* masm, |
| + Register scratch, |
| + ArgLocation arg_location = ARGS_ON_STACK); |
| + |
| + // Similar to LoadFloatOperand but assumes that both operands are smis. |
| + // Accepts operands on stack or in eax, ebx. |
| + static void LoadFloatSmis(MacroAssembler* masm, |
| + Register scratch, |
| + ArgLocation arg_location); |
| + |
| // Test if operands are smi or number objects (fp). Requirements: |
| // operand_1 in eax, operand_2 in edx; falls through on float |
| // operands, jumps to the non_float label otherwise. |
| @@ -769,6 +784,12 @@ |
| // either operand is not a number. Operands are in edx and eax. |
| // Leaves operands unchanged. |
| static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers); |
| + |
| + // Similar to LoadSse2Operands but assumes that both operands are smis. |
| + // Accepts operands on stack or in eax, ebx. |
| + static void LoadSse2Smis(MacroAssembler* masm, |
| + Register scratch, |
| + ArgLocation arg_location); |
| }; |
| @@ -1331,12 +1352,12 @@ |
| __ mov(answer.reg(), left->reg()); |
| switch (op) { |
| case Token::ADD: |
| - __ add(answer.reg(), Operand(right->reg())); // Add optimistically. |
| + __ add(answer.reg(), Operand(right->reg())); |
| deferred->Branch(overflow); |
| break; |
| case Token::SUB: |
| - __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically. |
| + __ sub(answer.reg(), Operand(right->reg())); |
| deferred->Branch(overflow); |
| break; |
| @@ -7056,6 +7077,17 @@ |
| void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
| + if (HasArgumentsInRegisters()) { |
| + __ mov(ebx, eax); |
| + __ mov(eax, edx); |
| + } else { |
| + __ mov(ebx, Operand(esp, 1 * kPointerSize)); |
| + __ mov(eax, Operand(esp, 2 * kPointerSize)); |
| + } |
| + |
| + Label not_smis, not_smis_or_overflow, not_smis_undo_optimistic; |
| + Label use_fp_on_smis, done; |
| + |
| // Perform fast-case smi code for the operation (eax <op> ebx) and |
| // leave result in register eax. |
| @@ -7067,12 +7099,12 @@ |
| switch (op_) { |
| case Token::ADD: |
| __ add(eax, Operand(ebx)); // add optimistically |
| - __ j(overflow, slow, not_taken); |
| + __ j(overflow, ¬_smis_or_overflow, not_taken); |
| break; |
| case Token::SUB: |
| __ sub(eax, Operand(ebx)); // subtract optimistically |
| - __ j(overflow, slow, not_taken); |
| + __ j(overflow, ¬_smis_or_overflow, not_taken); |
| break; |
| case Token::DIV: |
| @@ -7081,7 +7113,7 @@ |
| __ cdq(); |
| // Check for 0 divisor. |
| __ test(ebx, Operand(ebx)); |
| - __ j(zero, slow, not_taken); |
| + __ j(zero, ¬_smis_or_overflow, not_taken); |
| break; |
| default: |
| @@ -7092,7 +7124,7 @@ |
| // Perform the actual smi check. |
| ASSERT(kSmiTag == 0); // adjust zero check if not the case |
| __ test(ecx, Immediate(kSmiTagMask)); |
| - __ j(not_zero, slow, not_taken); |
| + __ j(not_zero, ¬_smis_undo_optimistic, not_taken); |
| switch (op_) { |
| case Token::ADD: |
| @@ -7108,9 +7140,9 @@ |
| // Do multiplication. |
| __ imul(eax, Operand(ebx)); // multiplication of smis; result in eax |
| // Go slow on overflows. |
| - __ j(overflow, slow, not_taken); |
| + __ j(overflow, &use_fp_on_smis, not_taken); |
| // Check for negative zero result. |
| - __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y |
| + __ NegativeZeroTest(eax, ecx, &use_fp_on_smis); // use ecx = x | y |
| break; |
| case Token::DIV: |
| @@ -7121,12 +7153,12 @@ |
| // by idiv instruction. |
| ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| __ cmp(eax, 0x40000000); |
| - __ j(equal, slow); |
| + __ j(equal, &use_fp_on_smis); |
| // Check for negative zero result. |
| - __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y |
| + __ NegativeZeroTest(eax, ecx, &use_fp_on_smis); // use ecx = x | y |
| // Check that the remainder is zero. |
| __ test(edx, Operand(edx)); |
| - __ j(not_zero, slow); |
| + __ j(not_zero, &use_fp_on_smis); |
| // Tag the result and store it in register eax. |
| __ SmiTag(eax); |
| break; |
| @@ -7181,7 +7213,7 @@ |
| __ shl_cl(eax); |
| // Check that the *signed* result fits in a smi. |
| __ cmp(eax, 0xc0000000); |
| - __ j(sign, slow, not_taken); |
| + __ j(sign, &use_fp_on_smis, not_taken); |
| break; |
| default: |
| UNREACHABLE(); |
| @@ -7194,6 +7226,116 @@ |
| UNREACHABLE(); |
| break; |
| } |
| + GenerateReturn(masm); |
| + |
| + __ bind(¬_smis_or_overflow); |
| + // Revert optimistic operation. |
| + switch (op_) { |
| + case Token::ADD: __ sub(eax, Operand(ebx)); break; |
| + case Token::SUB: __ add(eax, Operand(ebx)); break; |
| + default: break; |
| + } |
| + ASSERT(kSmiTag == 0); // Adjust zero check if not the case. |
| + __ test(ecx, Immediate(kSmiTagMask)); |
| + __ j(not_zero, ¬_smis, not_taken); |
| + // Correct operand values are in eax, ebx at this point. |
| + |
| + __ bind(&use_fp_on_smis); |
| + // Both operands are known to be SMIs but the result does not fit into a SMI. |
| + switch (op_) { |
| + case Token::ADD: |
| + case Token::SUB: |
| + case Token::MUL: |
| + case Token::DIV: { |
| + Label after_alloc_failure; |
| + |
| + ArgLocation arg_location = |
| + (op_ == Token::ADD || op_ == Token::SUB) ? |
| + ARGS_IN_REGISTERS : |
| + ARGS_ON_STACK; |
| + |
| + __ AllocateHeapNumber( |
| + edx, |
| + ecx, |
| + no_reg, |
| + arg_location == ARGS_IN_REGISTERS ? &after_alloc_failure : slow); |
| + |
| + if (CpuFeatures::IsSupported(SSE2)) { |
| + CpuFeatures::Scope use_sse2(SSE2); |
| + FloatingPointHelper::LoadSse2Smis(masm, ecx, arg_location); |
| + switch (op_) { |
| + case Token::ADD: __ addsd(xmm0, xmm1); break; |
| + case Token::SUB: __ subsd(xmm0, xmm1); break; |
| + case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| + case Token::DIV: __ divsd(xmm0, xmm1); break; |
| + default: UNREACHABLE(); |
| + } |
| + __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); |
| + } else { // SSE2 not available, use FPU. |
| + FloatingPointHelper::LoadFloatSmis(masm, ecx, arg_location); |
| + switch (op_) { |
| + case Token::ADD: __ faddp(1); break; |
| + case Token::SUB: __ fsubp(1); break; |
| + case Token::MUL: __ fmulp(1); break; |
| + case Token::DIV: __ fdivp(1); break; |
| + default: UNREACHABLE(); |
| + } |
| + __ fstp_d(FieldOperand(edx, HeapNumber::kValueOffset)); |
| + } |
| + __ mov(eax, edx); |
| + GenerateReturn(masm); |
| + |
| + if (HasArgumentsInRegisters()) { |
|
Kevin Millikin (Chromium)
2010/01/25 16:27:44
Is this right? What if op_ == Token::ADD or Token
Vladislav Kaznacheev
2010/01/25 17:44:53
This was a bug. Fixed.
On 2010/01/25 16:27:44, Kev
|
| + __ bind(&after_alloc_failure); |
| + __ mov(edx, eax); |
| + __ mov(eax, ebx); |
| + __ jmp(slow); |
| + } |
| + } |
|
Kevin Millikin (Chromium)
2010/01/25 16:27:44
Missing break would be a problem (at least dead co
Vladislav Kaznacheev
2010/01/25 17:44:53
Done.
|
| + case Token::BIT_OR: |
| + case Token::BIT_AND: |
| + case Token::BIT_XOR: |
| + case Token::SAR: |
| + // Do nothing here as these operations always succeed on a pair of smis. |
| + break; |
| + |
| + case Token::MOD: |
| + case Token::SHR: |
| + // Do nothing here as these go directly to runtime. |
| + break; |
| + |
| + case Token::SHL: { |
| + __ AllocateHeapNumber(ebx, ecx, edx, slow); |
| + // Store the result in the HeapNumber and return. |
| + if (CpuFeatures::IsSupported(SSE2)) { |
| + CpuFeatures::Scope use_sse2(SSE2); |
| + __ cvtsi2sd(xmm0, Operand(eax)); |
| + __ movdbl(FieldOperand(ebx, HeapNumber::kValueOffset), xmm0); |
| + } else { |
| + __ mov(Operand(esp, 1 * kPointerSize), eax); |
| + __ fild_s(Operand(esp, 1 * kPointerSize)); |
| + __ fstp_d(FieldOperand(ebx, HeapNumber::kValueOffset)); |
| + } |
| + __ mov(eax, ebx); |
| + GenerateReturn(masm); |
| + break; |
| + } |
| + |
| + default: UNREACHABLE(); break; |
| + } |
| + |
| + __ bind(¬_smis_undo_optimistic); |
| + switch (op_) { |
| + case Token::ADD: __ sub(eax, Operand(ebx)); break; |
| + case Token::SUB: __ add(eax, Operand(ebx)); break; |
| + default: break; |
| + } |
| + |
| + __ bind(¬_smis); |
| + __ mov(edx, eax); |
| + __ mov(eax, ebx); |
| + |
| + __ bind(&done); |
| } |
| @@ -7206,27 +7348,17 @@ |
| // case smi code is not generated by the caller. Generating it here will speed |
| // up common operations. |
| if (HasSmiCodeInStub()) { |
| - Label slow; |
| - __ mov(ebx, Operand(esp, 1 * kPointerSize)); |
| - __ mov(eax, Operand(esp, 2 * kPointerSize)); |
| - GenerateSmiCode(masm, &slow); |
| - GenerateReturn(masm); |
| - // Too bad. The fast case smi code didn't succeed. |
| - __ bind(&slow); |
| + GenerateSmiCode(masm, &call_runtime); |
| + } else if (op_ != Token::MOD) { // MOD goes straight to runtime. |
| + GenerateLoadArguments(masm); |
| } |
| - // Make sure the arguments are in edx and eax. |
| - GenerateLoadArguments(masm); |
| - |
| // Floating point case. |
| switch (op_) { |
| case Token::ADD: |
| case Token::SUB: |
| case Token::MUL: |
| case Token::DIV: { |
| - // eax: y |
| - // edx: x |
| - |
| if (CpuFeatures::IsSupported(SSE2)) { |
| CpuFeatures::Scope use_sse2(SSE2); |
| FloatingPointHelper::LoadSse2Operands(masm, &call_runtime); |
| @@ -7238,59 +7370,12 @@ |
| case Token::DIV: __ divsd(xmm0, xmm1); break; |
| default: UNREACHABLE(); |
| } |
| - // Allocate a heap number, if needed. |
| - Label skip_allocation; |
| - switch (mode_) { |
| - case OVERWRITE_LEFT: |
| - __ mov(eax, Operand(edx)); |
| - // Fall through! |
| - case OVERWRITE_RIGHT: |
| - // If the argument in eax is already an object, we skip the |
| - // allocation of a heap number. |
| - __ test(eax, Immediate(kSmiTagMask)); |
| - __ j(not_zero, &skip_allocation, not_taken); |
| - // Fall through! |
| - case NO_OVERWRITE: { |
| - // Allocate a heap number for the result. Keep eax and edx intact |
| - // for the possible runtime call. |
| - __ AllocateHeapNumber(ebx, ecx, no_reg, &call_runtime); |
| - // Now eax can be overwritten losing one of the arguments as we are |
| - // now done and will not need it any more. |
| - __ mov(eax, ebx); |
| - __ bind(&skip_allocation); |
| - break; |
| - } |
| - default: UNREACHABLE(); |
| - } |
| + GenerateHeapResultAllocation(masm, &call_runtime); |
| __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| GenerateReturn(masm); |
| } else { // SSE2 not available, use FPU. |
| FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
| - // Allocate a heap number, if needed. |
| - Label skip_allocation; |
| - switch (mode_) { |
| - case OVERWRITE_LEFT: |
| - __ mov(eax, Operand(edx)); |
| - // Fall through! |
| - case OVERWRITE_RIGHT: |
| - // If the argument in eax is already an object, we skip the |
| - // allocation of a heap number. |
| - __ test(eax, Immediate(kSmiTagMask)); |
| - __ j(not_zero, &skip_allocation, not_taken); |
| - // Fall through! |
| - case NO_OVERWRITE: |
| - // Allocate a heap number for the result. Keep eax and edx intact |
| - // for the possible runtime call. |
| - __ AllocateHeapNumber(ebx, ecx, no_reg, &call_runtime); |
| - // Now eax can be overwritten losing one of the arguments as we are |
| - // now done and will not need it any more. |
| - __ mov(eax, ebx); |
| - __ bind(&skip_allocation); |
| - break; |
| - default: UNREACHABLE(); |
| - } |
| - FloatingPointHelper::LoadFloatOperands(masm, ecx); |
| - |
| + FloatingPointHelper::LoadFloatOperands(masm, ecx, ARGS_IN_REGISTERS); |
| switch (op_) { |
| case Token::ADD: __ faddp(1); break; |
| case Token::SUB: __ fsubp(1); break; |
| @@ -7298,8 +7383,13 @@ |
| case Token::DIV: __ fdivp(1); break; |
| default: UNREACHABLE(); |
| } |
| + Label after_alloc_failure; |
| + GenerateHeapResultAllocation(masm, &after_alloc_failure); |
| __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| GenerateReturn(masm); |
| + __ bind(&after_alloc_failure); |
| + __ ffree(); |
| + __ jmp(&call_runtime); |
| } |
| } |
| case Token::MOD: { |
| @@ -7312,12 +7402,8 @@ |
| case Token::SAR: |
| case Token::SHL: |
| case Token::SHR: { |
| - Label non_smi_result, skip_allocation; |
| - Label operand_conversion_failure; |
| - FloatingPointHelper::LoadAsIntegers( |
| - masm, |
| - use_sse3_, |
| - &operand_conversion_failure); |
| + Label non_smi_result; |
| + FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); |
| switch (op_) { |
| case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; |
| case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |
| @@ -7330,7 +7416,7 @@ |
| if (op_ == Token::SHR) { |
| // Check if result is non-negative and fits in a smi. |
| __ test(eax, Immediate(0xc0000000)); |
| - __ j(not_zero, &non_smi_result); |
| + __ j(not_zero, &call_runtime); |
| } else { |
| // Check if result fits in a smi. |
| __ cmp(eax, 0xc0000000); |
| @@ -7345,6 +7431,7 @@ |
| __ bind(&non_smi_result); |
| // Allocate a heap number if needed. |
| __ mov(ebx, Operand(eax)); // ebx: result |
| + Label skip_allocation; |
| switch (mode_) { |
| case OVERWRITE_LEFT: |
| case OVERWRITE_RIGHT: |
| @@ -7373,15 +7460,6 @@ |
| } |
| GenerateReturn(masm); |
| } |
| - |
| - // Go to runtime for non-number inputs. |
| - __ bind(&operand_conversion_failure); |
| - // SHR should return uint32 - go to runtime for non-smi/negative result. |
| - if (op_ == Token::SHR) { |
| - __ bind(&non_smi_result); |
| - } |
| - __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| - __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| break; |
| } |
| default: UNREACHABLE(); break; |
| @@ -7407,17 +7485,15 @@ |
| // Test for string arguments before calling runtime. |
| Label not_strings, not_string1, string1; |
| Result answer; |
| - __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
| - __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
| - __ test(eax, Immediate(kSmiTagMask)); |
| + __ test(edx, Immediate(kSmiTagMask)); |
| __ j(zero, ¬_string1); |
| - __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, eax); |
| + __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx); |
| __ j(above_equal, ¬_string1); |
| - // First argument is a a string, test second. |
| - __ test(edx, Immediate(kSmiTagMask)); |
| + // First argument is a string, test second. |
| + __ test(eax, Immediate(kSmiTagMask)); |
| __ j(zero, &string1); |
| - __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx); |
| + __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); |
| __ j(above_equal, &string1); |
| // First and second argument are strings. Jump to the string add stub. |
| @@ -7426,17 +7502,25 @@ |
| // Only first argument is a string. |
| __ bind(&string1); |
| - __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); |
| + __ InvokeBuiltin( |
| + HasArgumentsReversed() ? |
|
Mads Ager (chromium)
2010/01/25 15:44:03
Indent by one more space. Looks like 3-space inden
Vladislav Kaznacheev
2010/01/25 16:24:47
Done.
|
| + Builtins::STRING_ADD_RIGHT : |
| + Builtins::STRING_ADD_LEFT, |
| + JUMP_FUNCTION); |
| // First argument was not a string, test second. |
| __ bind(¬_string1); |
| - __ test(edx, Immediate(kSmiTagMask)); |
| + __ test(eax, Immediate(kSmiTagMask)); |
| __ j(zero, ¬_strings); |
| - __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx); |
| + __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); |
| __ j(above_equal, ¬_strings); |
| // Only second argument is a string. |
| - __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); |
| + __ InvokeBuiltin( |
| + HasArgumentsReversed() ? |
|
Mads Ager (chromium)
2010/01/25 15:44:03
Indent by one more space.
Vladislav Kaznacheev
2010/01/25 16:24:47
Done.
|
| + Builtins::STRING_ADD_LEFT : |
| + Builtins::STRING_ADD_RIGHT, |
| + JUMP_FUNCTION); |
| __ bind(¬_strings); |
| // Neither argument is a string. |
| @@ -7448,7 +7532,7 @@ |
| break; |
| case Token::MUL: |
| __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); |
| - break; |
| + break; |
| case Token::DIV: |
| __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); |
| break; |
| @@ -7479,6 +7563,53 @@ |
| } |
| +void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, |
| + Label* alloc_failure) { |
| + Label skip_allocation; |
| + OverwriteMode mode = mode_; |
| + if (HasArgumentsReversed()) { |
| + if (mode == OVERWRITE_RIGHT) |
|
Mads Ager (chromium)
2010/01/25 15:44:03
Please uses '{' and '}' when having multi-line if
Vladislav Kaznacheev
2010/01/25 16:24:47
Done.
|
| + mode = OVERWRITE_LEFT; |
| + else if (mode == OVERWRITE_LEFT) |
| + mode = OVERWRITE_RIGHT; |
| + } |
| + switch (mode) { |
| + case OVERWRITE_LEFT: { |
| + // If the argument in edx is already an object, we skip the |
| + // allocation of a heap number. |
| + __ test(edx, Immediate(kSmiTagMask)); |
| + __ j(not_zero, &skip_allocation, not_taken); |
| + // Allocate a heap number for the result. Keep eax and edx intact |
| + // for the possible runtime call. |
| + __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
| + // Now edx can be overwritten losing one of the arguments as we are |
| + // now done and will not need it any more. |
| + __ mov(edx, Operand(ebx)); |
| + __ bind(&skip_allocation); |
| + // Use object in edx as a result holder |
| + __ mov(eax, Operand(edx)); |
| + break; |
| + } |
| + case OVERWRITE_RIGHT: |
| + // If the argument in eax is already an object, we skip the |
| + // allocation of a heap number. |
| + __ test(eax, Immediate(kSmiTagMask)); |
| + __ j(not_zero, &skip_allocation, not_taken); |
| + // Fall through! |
| + case NO_OVERWRITE: |
| + // Allocate a heap number for the result. Keep eax and edx intact |
| + // for the possible runtime call. |
| + __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
| + // Now eax can be overwritten losing one of the arguments as we are |
| + // now done and will not need it any more. |
| + __ mov(eax, ebx); |
| + __ bind(&skip_allocation); |
| + break; |
| + default: UNREACHABLE(); |
| + } |
| +} |
| + |
| + |
| void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
| // If arguments are not passed in registers read them from the stack. |
| if (!HasArgumentsInRegisters()) { |
| @@ -7741,16 +7872,47 @@ |
| } |
| +void FloatingPointHelper::LoadSse2Smis(MacroAssembler* masm, |
| + Register scratch, |
| + ArgLocation arg_location) { |
| + if (arg_location == ARGS_IN_REGISTERS) { |
| + __ mov(scratch, eax); |
| + } else { |
| + __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| + } |
| + __ SmiUntag(scratch); // Untag smi before converting to float. |
| + __ cvtsi2sd(xmm0, Operand(scratch)); |
| + |
| + |
| + if (arg_location == ARGS_IN_REGISTERS) { |
| + __ mov(scratch, ebx); |
| + } else { |
| + __ mov(scratch, Operand(esp, 1 * kPointerSize)); |
| + } |
| + __ SmiUntag(scratch); // Untag smi before converting to float. |
| + __ cvtsi2sd(xmm1, Operand(scratch)); |
| +} |
| + |
| + |
| void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| - Register scratch) { |
| + Register scratch, |
| + ArgLocation arg_location) { |
| Label load_smi_1, load_smi_2, done_load_1, done; |
| - __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| + if (arg_location == ARGS_IN_REGISTERS) { |
| + __ mov(scratch, edx); |
| + } else { |
| + __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| + } |
| __ test(scratch, Immediate(kSmiTagMask)); |
| __ j(zero, &load_smi_1, not_taken); |
| __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
| __ bind(&done_load_1); |
| - __ mov(scratch, Operand(esp, 1 * kPointerSize)); |
| + if (arg_location == ARGS_IN_REGISTERS) { |
| + __ mov(scratch, eax); |
| + } else { |
| + __ mov(scratch, Operand(esp, 1 * kPointerSize)); |
| + } |
| __ test(scratch, Immediate(kSmiTagMask)); |
| __ j(zero, &load_smi_2, not_taken); |
| __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
| @@ -7773,6 +7935,31 @@ |
| } |
| +void FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm, |
| + Register scratch, |
| + ArgLocation arg_location) { |
| + if (arg_location == ARGS_IN_REGISTERS) { |
| + __ mov(scratch, eax); |
| + } else { |
| + __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| + } |
| + __ SmiUntag(scratch); |
| + __ push(scratch); |
| + __ fild_s(Operand(esp, 0)); |
| + __ pop(scratch); |
| + |
| + if (arg_location == ARGS_IN_REGISTERS) { |
| + __ mov(scratch, ebx); |
| + } else { |
| + __ mov(scratch, Operand(esp, 1 * kPointerSize)); |
| + } |
| + __ SmiUntag(scratch); |
| + __ push(scratch); |
| + __ fild_s(Operand(esp, 0)); |
| + __ pop(scratch); |
| +} |
| + |
| + |
| void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
| Label* non_float, |
| Register scratch) { |