Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 2860) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -768,6 +768,11 @@ |
static void CheckFloatOperands(MacroAssembler* masm, |
Label* non_float, |
Register scratch); |
+ // Test if operands are numbers (smi or HeapNumber objects), and load |
+ // them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
+ // either operand is not a number. Operands are in edx and eax. |
+ // Leaves operands unchanged. |
+ static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers); |
// Allocate a heap number in new space with undefined value. |
// Returns tagged pointer in eax, or jumps to need_gc if new space is full. |
static void AllocateHeapNumber(MacroAssembler* masm, |
@@ -6699,41 +6704,79 @@ |
case Token::DIV: { |
// eax: y |
// edx: x |
- FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
- // Fast-case: Both operands are numbers. |
- // 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: |
- FloatingPointHelper::AllocateHeapNumber(masm, |
- &call_runtime, |
- ecx, |
- edx, |
- eax); |
- __ bind(&skip_allocation); |
- break; |
- default: UNREACHABLE(); |
- } |
- FloatingPointHelper::LoadFloatOperands(masm, ecx); |
- 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(); |
+ if (CpuFeatures::IsSupported(CpuFeatures::SSE2)) { |
+ CpuFeatures::Scope use_sse2(CpuFeatures::SSE2); |
+ FloatingPointHelper::LoadSse2Operands(masm, &call_runtime); |
+ |
+ 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(); |
+ } |
+ // 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: |
+ FloatingPointHelper::AllocateHeapNumber(masm, |
+ &call_runtime, |
+ ecx, |
+ edx, |
+ eax); |
+ __ bind(&skip_allocation); |
+ break; |
+ default: UNREACHABLE(); |
+ } |
+ __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
+ __ ret(2 * kPointerSize); |
+ |
+ } else { // SSE2 not available, use FPU. |
+ FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
Mark Mentovai
2009/09/09 15:09:55
Shouldn't this be done for both SSE2 and x87, or s
William Hesse
2009/09/10 07:27:37
The checking and the loading are combined into one
|
+ // Allocate a heap number, if needed. |
Mark Mentovai
2009/09/09 15:09:55
Is there a reason that this is done before the x87
William Hesse
2009/09/10 07:27:37
This code has to go after the check, but before th
|
+ 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: |
+ FloatingPointHelper::AllocateHeapNumber(masm, |
+ &call_runtime, |
+ ecx, |
+ edx, |
+ eax); |
+ __ bind(&skip_allocation); |
+ break; |
+ default: UNREACHABLE(); |
+ } |
+ FloatingPointHelper::LoadFloatOperands(masm, ecx); |
+ |
+ 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(eax, HeapNumber::kValueOffset)); |
+ __ ret(2 * kPointerSize); |
} |
- __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ ret(2 * kPointerSize); |
} |
case Token::MOD: { |
// For MOD we go directly to runtime in the non-smi case. |
@@ -6981,6 +7024,38 @@ |
} |
+void FloatingPointHelper::LoadSse2Operands(MacroAssembler* masm, |
+ Label* not_numbers) { |
+ Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; |
+ // Load operand in edx into xmm0, or branch to not_numbers. |
+ __ test(edx, Immediate(kSmiTagMask)); |
+ __ j(zero, &load_smi_edx, not_taken); // Argument in edx is a smi. |
+ __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Factory::heap_number_map()); |
+ __ j(not_equal, not_numbers); // Argument in edx is not a number. |
+ __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
+ __ bind(&load_eax); |
+ // Load operand in eax into xmm1, or branch to not_numbers. |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(zero, &load_smi_eax, not_taken); // Argument in eax is a smi. |
+ __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::heap_number_map()); |
+ __ j(equal, &load_float_eax); |
+ __ jmp(not_numbers); // Argument in eax is not a number. |
+ __ bind(&load_smi_edx); |
+ __ sar(edx, 1); // Untag smi before converting to float. |
+ __ cvtsi2sd(xmm0, Operand(edx)); |
+ __ shl(edx, 1); // Retag smi for heap number overwriting test. |
+ __ jmp(&load_eax); |
+ __ bind(&load_smi_eax); |
+ __ sar(eax, 1); // Untag smi before converting to float. |
+ __ cvtsi2sd(xmm1, Operand(eax)); |
+ __ shl(eax, 1); // Retag smi for heap number overwriting test. |
+ __ jmp(&done); |
+ __ bind(&load_float_eax); |
+ __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
+ __ bind(&done); |
+} |
+ |
+ |
void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
Register scratch) { |
Label load_smi_1, load_smi_2, done_load_1, done; |
@@ -7343,28 +7418,56 @@ |
// Inlined floating point compare. |
// Call builtin if operands are not floating point or smi. |
Label check_for_symbols; |
- FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); |
- FloatingPointHelper::LoadFloatOperands(masm, ecx); |
- __ FCmp(); |
+ Label unordered; |
+ if (CpuFeatures::IsSupported(CpuFeatures::SSE2)) { |
+ CpuFeatures::Scope use_sse2(CpuFeatures::SSE2); |
+ CpuFeatures::Scope use_cmov(CpuFeatures::CMOV); |
- // Jump to builtin for NaN. |
- __ j(parity_even, &call_builtin, not_taken); |
+ FloatingPointHelper::LoadSse2Operands(masm, &check_for_symbols); |
+ __ comisd(xmm0, xmm1); |
- // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up. |
- Label below_lbl, above_lbl; |
- // use edx, eax to convert unsigned to signed comparison |
- __ j(below, &below_lbl, not_taken); |
- __ j(above, &above_lbl, not_taken); |
+ // Jump to builtin for NaN. |
+ __ j(parity_even, &unordered, not_taken); |
+ __ mov(eax, 0); // equal |
+ __ mov(ecx, Immediate(Smi::FromInt(1))); |
+ __ cmov(above, eax, Operand(ecx)); |
+ __ mov(ecx, Immediate(Smi::FromInt(-1))); |
+ __ cmov(below, eax, Operand(ecx)); |
+ __ ret(2 * kPointerSize); |
+ } else { |
+ FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); |
+ FloatingPointHelper::LoadFloatOperands(masm, ecx); |
+ __ FCmp(); |
- __ xor_(eax, Operand(eax)); // equal |
- __ ret(2 * kPointerSize); |
+ // Jump to builtin for NaN. |
+ __ j(parity_even, &unordered, not_taken); |
- __ bind(&below_lbl); |
- __ mov(eax, -1); |
- __ ret(2 * kPointerSize); |
+ Label below_lbl, above_lbl; |
+ // Return a result of -1, 0, or 1, to indicate result of comparison. |
+ __ j(below, &below_lbl, not_taken); |
+ __ j(above, &above_lbl, not_taken); |
- __ bind(&above_lbl); |
- __ mov(eax, 1); |
+ __ xor_(eax, Operand(eax)); // equal |
+ // Both arguments were pushed in case a runtime call was needed. |
+ __ ret(2 * kPointerSize); |
+ |
+ __ bind(&below_lbl); |
+ __ mov(eax, Immediate(Smi::FromInt(-1))); |
+ __ ret(2 * kPointerSize); |
+ |
+ __ bind(&above_lbl); |
+ __ mov(eax, Immediate(Smi::FromInt(1))); |
+ __ ret(2 * kPointerSize); // eax, edx were pushed |
+ } |
+ // If one of the numbers was NaN, then the result is always false. |
+ // The cc is never not-equal. |
+ __ bind(&unordered); |
+ ASSERT(cc_ != not_equal); |
+ if (cc_ == less || cc_ == less_equal) { |
+ __ mov(eax, Immediate(Smi::FromInt(1))); |
+ } else { |
+ __ mov(eax, Immediate(Smi::FromInt(-1))); |
+ } |
__ ret(2 * kPointerSize); // eax, edx were pushed |
// Fast negative check for symbol-to-symbol equality. |