Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 4902) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -262,69 +262,19 @@ |
class FloatingPointHelper : public AllStatic { |
public: |
- // Code pattern for loading a floating point value. Input value must |
- // be either a smi or a heap number object (fp value). Requirements: |
- // operand on TOS+1. Returns operand as floating point number on FPU |
- // stack. |
- static void LoadFloatOperand(MacroAssembler* masm, Register scratch); |
+ // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. |
+ // If the operands are not both numbers, jump to not_numbers. |
+ // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. |
+ // NumberOperands assumes both are smis or heap numbers. |
+ static void LoadSSE2SmiOperands(MacroAssembler* masm); |
+ static void LoadSSE2NumberOperands(MacroAssembler* masm); |
+ static void LoadSSE2UnknownOperands(MacroAssembler* masm, |
+ Label* not_numbers); |
- // Code pattern for loading a floating point value. Input value must |
- // be either a smi or a heap number object (fp value). Requirements: |
- // operand in src register. Returns operand as floating point number |
- // in XMM register. May destroy src register. |
- static void LoadFloatOperand(MacroAssembler* masm, |
- Register src, |
- XMMRegister dst); |
- |
- // Code pattern for loading a possible number into a XMM register. |
- // If the contents of src is not a number, control branches to |
- // the Label not_number. If contents of src is a smi or a heap number |
- // object (fp value), it is loaded into the XMM register as a double. |
- // The register src is not changed, and src may not be kScratchRegister. |
- static void LoadFloatOperand(MacroAssembler* masm, |
- Register src, |
- XMMRegister dst, |
- Label *not_number); |
- |
- // Code pattern for loading floating point values. Input values must |
- // be either smi or heap number objects (fp values). Requirements: |
- // operand_1 in rdx, operand_2 in rax; Returns operands as |
- // floating point numbers in XMM registers. |
- static void LoadFloatOperands(MacroAssembler* masm, |
- XMMRegister dst1, |
- XMMRegister dst2); |
- |
- // Similar to LoadFloatOperands, assumes that the operands are smis. |
- static void LoadFloatOperandsFromSmis(MacroAssembler* masm, |
- XMMRegister dst1, |
- XMMRegister dst2); |
- |
- // Code pattern for loading floating point values onto the fp stack. |
- // Input values must be either smi or heap number objects (fp values). |
- // Requirements: |
- // Register version: operands in registers lhs and rhs. |
- // Stack version: operands on TOS+1 and TOS+2. |
- // Returns operands as floating point numbers on fp stack. |
- static void LoadFloatOperands(MacroAssembler* masm, |
- Register lhs, |
- Register rhs); |
- |
- // Test if operands are smi or number objects (fp). Requirements: |
- // operand_1 in rax, operand_2 in rdx; falls through on float or smi |
- // operands, jumps to the non_float label otherwise. |
- static void CheckNumberOperands(MacroAssembler* masm, |
- Label* non_float); |
- // As CheckNumberOperands above, but expects the HeapNumber map in |
- // a register. |
- static void CheckNumberOperands(MacroAssembler* masm, |
- Label* non_float, |
- Register heap_number_map); |
- |
// Takes the operands in rdx and rax and loads them as integers in rax |
// and rcx. |
static void LoadAsIntegers(MacroAssembler* masm, |
- Label* operand_conversion_failure, |
- Register heap_number_map); |
+ Label* operand_conversion_failure); |
}; |
@@ -9112,11 +9062,7 @@ |
if (include_number_compare_) { |
Label non_number_comparison; |
Label unordered; |
- FloatingPointHelper::LoadFloatOperand(masm, rdx, xmm0, |
- &non_number_comparison); |
- FloatingPointHelper::LoadFloatOperand(masm, rax, xmm1, |
- &non_number_comparison); |
- |
+ FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); |
__ ucomisd(xmm0, xmm1); |
// Don't base result on EFLAGS when a NaN is involved. |
@@ -9973,86 +9919,72 @@ |
} |
-void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
- Register number) { |
- Label load_smi, done; |
- |
- __ JumpIfSmi(number, &load_smi); |
- __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); |
- __ jmp(&done); |
- |
- __ bind(&load_smi); |
- __ SmiToInteger32(number, number); |
- __ push(number); |
- __ fild_s(Operand(rsp, 0)); |
- __ pop(number); |
- |
- __ bind(&done); |
+void FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) { |
+ __ SmiToInteger32(kScratchRegister, rdx); |
+ __ cvtlsi2sd(xmm0, kScratchRegister); |
+ __ SmiToInteger32(kScratchRegister, rax); |
+ __ cvtlsi2sd(xmm1, kScratchRegister); |
} |
-void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
- Register src, |
- XMMRegister dst) { |
- ASSERT(!src.is(kScratchRegister)); |
- Label load_smi, done; |
- |
- __ JumpIfSmi(src, &load_smi); |
- __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); |
+void FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) { |
+ Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done; |
+ // Load operand in rdx into xmm0. |
+ __ JumpIfSmi(rdx, &load_smi_rdx); |
+ __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
+ // Load operand in rax into xmm1. |
+ __ JumpIfSmi(rax, &load_smi_rax); |
+ __ bind(&load_nonsmi_rax); |
+ __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
__ jmp(&done); |
- __ bind(&load_smi); |
- __ SmiToInteger32(kScratchRegister, src); |
- __ cvtlsi2sd(dst, kScratchRegister); |
+ __ bind(&load_smi_rdx); |
+ __ SmiToInteger32(kScratchRegister, rdx); |
+ __ cvtlsi2sd(xmm0, kScratchRegister); |
+ __ JumpIfNotSmi(rax, &load_nonsmi_rax); |
- __ bind(&done); |
-} |
+ __ bind(&load_smi_rax); |
+ __ SmiToInteger32(kScratchRegister, rax); |
+ __ cvtlsi2sd(xmm1, kScratchRegister); |
- |
-void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
- Register src, |
- XMMRegister dst, |
- Label* not_number) { |
- Label load_smi, done; |
- ASSERT(!src.is(kScratchRegister)); |
- __ JumpIfSmi(src, &load_smi); |
- __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); |
- __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister); |
- __ j(not_equal, not_number); |
- __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); |
- __ jmp(&done); |
- |
- __ bind(&load_smi); |
- __ SmiToInteger32(kScratchRegister, src); |
- __ cvtlsi2sd(dst, kScratchRegister); |
- |
__ bind(&done); |
} |
-void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
- XMMRegister dst1, |
- XMMRegister dst2) { |
- LoadFloatOperand(masm, rdx, dst1); |
- LoadFloatOperand(masm, rax, dst2); |
-} |
+void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, |
+ Label* not_numbers) { |
+ Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done; |
+ // Load operand in rdx into xmm0, or branch to not_numbers. |
+ __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex); |
+ __ JumpIfSmi(rdx, &load_smi_rdx); |
+ __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx); |
+ __ j(not_equal, not_numbers); // Argument in rdx is not a number. |
+ __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
+ // Load operand in rax into xmm1, or branch to not_numbers. |
+ __ JumpIfSmi(rax, &load_smi_rax); |
+ __ bind(&load_nonsmi_rax); |
+ __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), rcx); |
+ __ j(not_equal, not_numbers); |
+ __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
+ __ jmp(&done); |
-void FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm, |
- XMMRegister dst1, |
- XMMRegister dst2) { |
+ __ bind(&load_smi_rdx); |
__ SmiToInteger32(kScratchRegister, rdx); |
- __ cvtlsi2sd(dst1, kScratchRegister); |
+ __ cvtlsi2sd(xmm0, kScratchRegister); |
+ __ JumpIfNotSmi(rax, &load_nonsmi_rax); |
+ |
+ __ bind(&load_smi_rax); |
__ SmiToInteger32(kScratchRegister, rax); |
- __ cvtlsi2sd(dst2, kScratchRegister); |
+ __ cvtlsi2sd(xmm1, kScratchRegister); |
+ __ bind(&done); |
} |
// Input: rdx, rax are the left and right objects of a bit op. |
// Output: rax, rcx are left and right integers for a bit op. |
void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
- Label* conversion_failure, |
- Register heap_number_map) { |
+ Label* conversion_failure) { |
// Check float operands. |
Label arg1_is_object, check_undefined_arg1; |
Label arg2_is_object, check_undefined_arg2; |
@@ -10070,7 +10002,8 @@ |
__ jmp(&load_arg2); |
__ bind(&arg1_is_object); |
- __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); |
+ __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
+ __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); |
__ j(not_equal, &check_undefined_arg1); |
// Get the untagged integer version of the edx heap number in rcx. |
IntegerConvert(masm, rdx, rdx); |
@@ -10091,7 +10024,8 @@ |
__ jmp(&done); |
__ bind(&arg2_is_object); |
- __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); |
+ __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
+ __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex); |
__ j(not_equal, &check_undefined_arg2); |
// Get the untagged integer version of the eax heap number in ecx. |
IntegerConvert(masm, rcx, rax); |
@@ -10100,74 +10034,6 @@ |
} |
-void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
- Register lhs, |
- Register rhs) { |
- Label load_smi_lhs, load_smi_rhs, done_load_lhs, done; |
- __ JumpIfSmi(lhs, &load_smi_lhs); |
- __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset)); |
- __ bind(&done_load_lhs); |
- |
- __ JumpIfSmi(rhs, &load_smi_rhs); |
- __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); |
- __ jmp(&done); |
- |
- __ bind(&load_smi_lhs); |
- __ SmiToInteger64(kScratchRegister, lhs); |
- __ push(kScratchRegister); |
- __ fild_d(Operand(rsp, 0)); |
- __ pop(kScratchRegister); |
- __ jmp(&done_load_lhs); |
- |
- __ bind(&load_smi_rhs); |
- __ SmiToInteger64(kScratchRegister, rhs); |
- __ push(kScratchRegister); |
- __ fild_d(Operand(rsp, 0)); |
- __ pop(kScratchRegister); |
- |
- __ bind(&done); |
-} |
- |
- |
-void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm, |
- Label* non_float) { |
- Label test_other, done; |
- // Test if both operands are numbers (heap_numbers or smis). |
- // If not, jump to label non_float. |
- __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK |
- __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map()); |
- __ j(not_equal, non_float); // The argument in rdx is not a number. |
- |
- __ bind(&test_other); |
- __ JumpIfSmi(rax, &done); // argument in rax is OK |
- __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map()); |
- __ j(not_equal, non_float); // The argument in rax is not a number. |
- |
- // Fall-through: Both operands are numbers. |
- __ bind(&done); |
-} |
- |
- |
-void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm, |
- Label* non_float, |
- Register heap_number_map) { |
- Label test_other, done; |
- // Test if both operands are numbers (heap_numbers or smis). |
- // If not, jump to label non_float. |
- __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK |
- __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); |
- __ j(not_equal, non_float); // The argument in rdx is not a number. |
- |
- __ bind(&test_other); |
- __ JumpIfSmi(rax, &done); // argument in rax is OK |
- __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); |
- __ j(not_equal, non_float); // The argument in rax is not a number. |
- |
- // Fall-through: Both operands are numbers. |
- __ bind(&done); |
-} |
- |
- |
const char* GenericBinaryOpStub::GetName() { |
if (name_ != NULL) return name_; |
const int len = 100; |
@@ -10474,15 +10340,15 @@ |
} |
// left is rdx, right is rax. |
__ AllocateHeapNumber(rbx, rcx, slow); |
- FloatingPointHelper::LoadFloatOperandsFromSmis(masm, xmm4, xmm5); |
+ FloatingPointHelper::LoadSSE2SmiOperands(masm); |
switch (op_) { |
- case Token::ADD: __ addsd(xmm4, xmm5); break; |
- case Token::SUB: __ subsd(xmm4, xmm5); break; |
- case Token::MUL: __ mulsd(xmm4, xmm5); break; |
- case Token::DIV: __ divsd(xmm4, xmm5); break; |
+ 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(); |
} |
- __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm4); |
+ __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0); |
__ movq(rax, rbx); |
GenerateReturn(masm); |
} |
@@ -10527,8 +10393,6 @@ |
} |
// Floating point case. |
if (ShouldGenerateFPCode()) { |
- // Load the HeapNumber map here and use it throughout the FP code. |
- Register heap_number_map = r9; |
switch (op_) { |
case Token::ADD: |
case Token::SUB: |
@@ -10543,34 +10407,27 @@ |
// forever for all other operations (also if smi code is skipped). |
GenerateTypeTransition(masm); |
} |
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
Label not_floats; |
// rax: y |
// rdx: x |
- if (static_operands_type_.IsNumber() && FLAG_debug_code) { |
- // Assert at runtime that inputs are only numbers. |
- __ AbortIfNotNumber(rdx); |
- __ AbortIfNotNumber(rax); |
- } else { |
+ ASSERT(!static_operands_type_.IsSmi()); |
+ if (static_operands_type_.IsNumber()) { |
if (FLAG_debug_code) { |
- __ AbortIfNotRootValue(heap_number_map, |
- Heap::kHeapNumberMapRootIndex, |
- "HeapNumberMap register clobbered."); |
+ // Assert at runtime that inputs are only numbers. |
+ __ AbortIfNotNumber(rdx); |
+ __ AbortIfNotNumber(rax); |
} |
- FloatingPointHelper::CheckNumberOperands(masm, |
- &call_runtime, |
- heap_number_map); |
+ FloatingPointHelper::LoadSSE2NumberOperands(masm); |
+ } else { |
+ FloatingPointHelper::LoadSSE2UnknownOperands(masm, &call_runtime); |
} |
- // Fast-case: Both operands are numbers. |
- // xmm4 and xmm5 are volatile XMM registers. |
- FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); |
switch (op_) { |
- case Token::ADD: __ addsd(xmm4, xmm5); break; |
- case Token::SUB: __ subsd(xmm4, xmm5); break; |
- case Token::MUL: __ mulsd(xmm4, xmm5); break; |
- case Token::DIV: __ divsd(xmm4, xmm5); break; |
+ 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. |
@@ -10584,24 +10441,9 @@ |
} |
} |
switch (mode) { |
- // TODO(lrn): Allocate this when we first see that the |
- // left register is a smi (and load it into xmm4). |
case OVERWRITE_LEFT: |
__ JumpIfNotSmi(rdx, &skip_allocation); |
- // Allocate heap number in new space. |
- __ AllocateInNewSpace(HeapNumber::kSize, |
- rbx, |
- rcx, |
- no_reg, |
- &call_runtime, |
- TAG_OBJECT); |
- if (FLAG_debug_code) { |
- __ AbortIfNotRootValue(heap_number_map, |
- Heap::kHeapNumberMapRootIndex, |
- "HeapNumberMap register clobbered."); |
- } |
- __ movq(FieldOperand(rbx, HeapObject::kMapOffset), |
- heap_number_map); |
+ __ AllocateHeapNumber(rbx, rcx, &call_runtime); |
__ movq(rdx, rbx); |
__ bind(&skip_allocation); |
__ movq(rax, rdx); |
@@ -10609,32 +10451,18 @@ |
case OVERWRITE_RIGHT: |
// If the argument in rax is already an object, we skip the |
// allocation of a heap number. |
- // TODO(lrn): Allocate the heap number when we first see that the |
- // right register is a smi (and load it into xmm5). |
__ JumpIfNotSmi(rax, &skip_allocation); |
// Fall through! |
case NO_OVERWRITE: |
// Allocate a heap number for the result. Keep rax and rdx intact |
// for the possible runtime call. |
- __ AllocateInNewSpace(HeapNumber::kSize, |
- rbx, |
- rcx, |
- no_reg, |
- &call_runtime, |
- TAG_OBJECT); |
- if (FLAG_debug_code) { |
- __ AbortIfNotRootValue(heap_number_map, |
- Heap::kHeapNumberMapRootIndex, |
- "HeapNumberMap register clobbered."); |
- } |
- __ movq(FieldOperand(rbx, HeapObject::kMapOffset), |
- heap_number_map); |
+ __ AllocateHeapNumber(rbx, rcx, &call_runtime); |
__ movq(rax, rbx); |
__ bind(&skip_allocation); |
break; |
default: UNREACHABLE(); |
} |
- __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); |
+ __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); |
GenerateReturn(masm); |
__ bind(¬_floats); |
if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
@@ -10659,11 +10487,8 @@ |
case Token::SAR: |
case Token::SHL: |
case Token::SHR: { |
- Label skip_allocation, non_smi_shr_result; |
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
- FloatingPointHelper::LoadAsIntegers(masm, |
- &call_runtime, |
- heap_number_map); |
+ Label skip_allocation, non_smi_result; |
+ FloatingPointHelper::LoadAsIntegers(masm, &call_runtime); |
switch (op_) { |
case Token::BIT_OR: __ orl(rax, rcx); break; |
case Token::BIT_AND: __ andl(rax, rcx); break; |
@@ -10675,22 +10500,21 @@ |
} |
if (op_ == Token::SHR) { |
// Check if result is negative. This can only happen for a shift |
- // by zero. |
+ // by zero, which also doesn't update the sign flag. |
__ testl(rax, rax); |
- __ j(negative, &non_smi_shr_result); |
+ __ j(negative, &non_smi_result); |
} |
- STATIC_ASSERT(kSmiValueSize == 32); |
- // Tag smi result and return. |
+ __ JumpIfNotValidSmiValue(rax, &non_smi_result); |
+ // Tag smi result, if possible, and return. |
__ Integer32ToSmi(rax, rax); |
GenerateReturn(masm); |
- // All bit-ops except SHR return a signed int32 that can be |
- // returned immediately as a smi. |
- if (op_ == Token::SHR) { |
- ASSERT(non_smi_shr_result.is_linked()); |
- __ bind(&non_smi_shr_result); |
+ // All ops except SHR return a signed int32 that we load in |
+ // a HeapNumber. |
+ if (op_ != Token::SHR && non_smi_result.is_linked()) { |
+ __ bind(&non_smi_result); |
// Allocate a heap number if needed. |
- __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). |
+ __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result |
switch (mode_) { |
case OVERWRITE_LEFT: |
case OVERWRITE_RIGHT: |
@@ -10701,31 +10525,22 @@ |
__ JumpIfNotSmi(rax, &skip_allocation); |
// Fall through! |
case NO_OVERWRITE: |
- // Allocate heap number in new space. |
- __ AllocateInNewSpace(HeapNumber::kSize, |
- rax, |
- rcx, |
- no_reg, |
- &call_runtime, |
- TAG_OBJECT); |
- // Set the map. |
- if (FLAG_debug_code) { |
- __ AbortIfNotRootValue(heap_number_map, |
- Heap::kHeapNumberMapRootIndex, |
- "HeapNumberMap register clobbered."); |
- } |
- __ movq(FieldOperand(rax, HeapObject::kMapOffset), |
- heap_number_map); |
+ __ AllocateHeapNumber(rax, rcx, &call_runtime); |
__ bind(&skip_allocation); |
break; |
default: UNREACHABLE(); |
} |
// Store the result in the HeapNumber and return. |
- __ cvtqsi2sd(xmm0, rbx); |
- __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); |
+ __ movq(Operand(rsp, 1 * kPointerSize), rbx); |
+ __ fild_s(Operand(rsp, 1 * kPointerSize)); |
+ __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
GenerateReturn(masm); |
} |
+ // SHR should return uint32 - go to runtime for non-smi/negative result. |
+ if (op_ == Token::SHR) { |
+ __ bind(&non_smi_result); |
+ } |
break; |
} |
default: UNREACHABLE(); break; |
@@ -10758,7 +10573,7 @@ |
Label not_strings, both_strings, not_string1, string1, string1_smi2; |
// If this stub has already generated FP-specific code then the arguments |
- // are already in rdx, rax. |
+ // are already in rdx, rax |
if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
GenerateLoadArguments(masm); |
} |