Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 5030) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -5423,9 +5423,13 @@ |
frame_->EmitPush(r0); // r0 has result |
} else { |
- bool overwrite = |
+ bool can_overwrite = |
(node->expression()->AsBinaryOperation() != NULL && |
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
+ UnaryOverwriteMode overwrite = |
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
+ |
+ bool no_negative_zero = node->expression()->no_negative_zero(); |
Load(node->expression()); |
switch (op) { |
case Token::NOT: |
@@ -5436,7 +5440,10 @@ |
case Token::SUB: { |
frame_->PopToR0(); |
- GenericUnaryOpStub stub(Token::SUB, overwrite); |
+ GenericUnaryOpStub stub( |
+ Token::SUB, |
+ overwrite, |
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero); |
frame_->CallStub(&stub, 0); |
frame_->EmitPush(r0); // r0 has result |
break; |
@@ -7641,189 +7648,197 @@ |
__ Swap(r0, r1, ip); |
} |
+ // The type transition also calculates the answer. |
+ bool generate_code_to_calculate_answer = true; |
+ |
if (ShouldGenerateFPCode()) { |
- Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1; |
- |
if (runtime_operands_type_ == BinaryOpIC::DEFAULT) { |
switch (op_) { |
case Token::ADD: |
case Token::SUB: |
case Token::MUL: |
case Token::DIV: |
- GenerateTypeTransition(masm); |
+ GenerateTypeTransition(masm); // Tail call. |
+ generate_code_to_calculate_answer = false; |
break; |
default: |
break; |
} |
- // Restore heap number map register. |
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
} |
- if (mode_ == NO_OVERWRITE) { |
- // In the case where there is no chance of an overwritable float we may as |
- // well do the allocation immediately while r0 and r1 are untouched. |
- __ AllocateHeapNumber(r5, r3, r7, heap_number_map, &slow); |
- } |
+ if (generate_code_to_calculate_answer) { |
+ Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1; |
+ if (mode_ == NO_OVERWRITE) { |
+ // In the case where there is no chance of an overwritable float we may |
+ // as well do the allocation immediately while r0 and r1 are untouched. |
+ __ AllocateHeapNumber(r5, r3, r7, heap_number_map, &slow); |
+ } |
- // Move r0 to a double in r2-r3. |
- __ tst(r0, Operand(kSmiTagMask)); |
- __ b(eq, &r0_is_smi); // It's a Smi so don't check it's a heap number. |
- __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
- __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
- __ cmp(r4, heap_number_map); |
- __ b(ne, &slow); |
- if (mode_ == OVERWRITE_RIGHT) { |
- __ mov(r5, Operand(r0)); // Overwrite this heap number. |
- } |
- if (use_fp_registers) { |
- CpuFeatures::Scope scope(VFP3); |
- // Load the double from tagged HeapNumber r0 to d7. |
- __ sub(r7, r0, Operand(kHeapObjectTag)); |
- __ vldr(d7, r7, HeapNumber::kValueOffset); |
- } else { |
- // Calling convention says that second double is in r2 and r3. |
- __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
- } |
- __ jmp(&finished_loading_r0); |
- __ bind(&r0_is_smi); |
- if (mode_ == OVERWRITE_RIGHT) { |
- // We can't overwrite a Smi so get address of new heap number into r5. |
- __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); |
- } |
+ // Move r0 to a double in r2-r3. |
+ __ tst(r0, Operand(kSmiTagMask)); |
+ __ b(eq, &r0_is_smi); // It's a Smi so don't check it's a heap number. |
+ __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
+ __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
+ __ cmp(r4, heap_number_map); |
+ __ b(ne, &slow); |
+ if (mode_ == OVERWRITE_RIGHT) { |
+ __ mov(r5, Operand(r0)); // Overwrite this heap number. |
+ } |
+ if (use_fp_registers) { |
+ CpuFeatures::Scope scope(VFP3); |
+ // Load the double from tagged HeapNumber r0 to d7. |
+ __ sub(r7, r0, Operand(kHeapObjectTag)); |
+ __ vldr(d7, r7, HeapNumber::kValueOffset); |
+ } else { |
+ // Calling convention says that second double is in r2 and r3. |
+ __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
+ } |
+ __ jmp(&finished_loading_r0); |
+ __ bind(&r0_is_smi); |
+ if (mode_ == OVERWRITE_RIGHT) { |
+ // We can't overwrite a Smi so get address of new heap number into r5. |
+ __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); |
+ } |
- if (CpuFeatures::IsSupported(VFP3)) { |
- CpuFeatures::Scope scope(VFP3); |
- // Convert smi in r0 to double in d7. |
- __ mov(r7, Operand(r0, ASR, kSmiTagSize)); |
- __ vmov(s15, r7); |
- __ vcvt_f64_s32(d7, s15); |
- if (!use_fp_registers) { |
- __ vmov(r2, r3, d7); |
+ if (CpuFeatures::IsSupported(VFP3)) { |
+ CpuFeatures::Scope scope(VFP3); |
+ // Convert smi in r0 to double in d7. |
+ __ mov(r7, Operand(r0, ASR, kSmiTagSize)); |
+ __ vmov(s15, r7); |
+ __ vcvt_f64_s32(d7, s15); |
+ if (!use_fp_registers) { |
+ __ vmov(r2, r3, d7); |
+ } |
+ } else { |
+ // Write Smi from r0 to r3 and r2 in double format. |
+ __ mov(r7, Operand(r0)); |
+ ConvertToDoubleStub stub3(r3, r2, r7, r4); |
+ __ push(lr); |
+ __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET); |
+ __ pop(lr); |
} |
- } else { |
- // Write Smi from r0 to r3 and r2 in double format. |
- __ mov(r7, Operand(r0)); |
- ConvertToDoubleStub stub3(r3, r2, r7, r4); |
- __ push(lr); |
- __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET); |
- __ pop(lr); |
- } |
- // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis. |
- // r0 is known to be a smi. If r1 is also a smi then switch to GENERIC. |
- Label r1_is_not_smi; |
- if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) { |
- __ tst(r1, Operand(kSmiTagMask)); |
- __ b(ne, &r1_is_not_smi); |
- GenerateTypeTransition(masm); |
- // Restore heap number map register. |
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
- __ jmp(&r1_is_smi); |
- } |
+ // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis. |
+ // r0 is known to be a smi. If r1 is also a smi then switch to GENERIC. |
+ Label r1_is_not_smi; |
+ if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) { |
+ __ tst(r1, Operand(kSmiTagMask)); |
+ __ b(ne, &r1_is_not_smi); |
+ GenerateTypeTransition(masm); // Tail call. |
+ } |
- __ bind(&finished_loading_r0); |
+ __ bind(&finished_loading_r0); |
- // Move r1 to a double in r0-r1. |
- __ tst(r1, Operand(kSmiTagMask)); |
- __ b(eq, &r1_is_smi); // It's a Smi so don't check it's a heap number. |
- __ bind(&r1_is_not_smi); |
- __ ldr(r4, FieldMemOperand(r1, HeapNumber::kMapOffset)); |
- __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
- __ cmp(r4, heap_number_map); |
- __ b(ne, &slow); |
- if (mode_ == OVERWRITE_LEFT) { |
- __ mov(r5, Operand(r1)); // Overwrite this heap number. |
- } |
- if (use_fp_registers) { |
- CpuFeatures::Scope scope(VFP3); |
- // Load the double from tagged HeapNumber r1 to d6. |
- __ sub(r7, r1, Operand(kHeapObjectTag)); |
- __ vldr(d6, r7, HeapNumber::kValueOffset); |
- } else { |
- // Calling convention says that first double is in r0 and r1. |
- __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset)); |
- } |
- __ jmp(&finished_loading_r1); |
- __ bind(&r1_is_smi); |
- if (mode_ == OVERWRITE_LEFT) { |
- // We can't overwrite a Smi so get address of new heap number into r5. |
- __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); |
- } |
+ // Move r1 to a double in r0-r1. |
+ __ tst(r1, Operand(kSmiTagMask)); |
+ __ b(eq, &r1_is_smi); // It's a Smi so don't check it's a heap number. |
+ __ bind(&r1_is_not_smi); |
+ __ ldr(r4, FieldMemOperand(r1, HeapNumber::kMapOffset)); |
+ __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
+ __ cmp(r4, heap_number_map); |
+ __ b(ne, &slow); |
+ if (mode_ == OVERWRITE_LEFT) { |
+ __ mov(r5, Operand(r1)); // Overwrite this heap number. |
+ } |
+ if (use_fp_registers) { |
+ CpuFeatures::Scope scope(VFP3); |
+ // Load the double from tagged HeapNumber r1 to d6. |
+ __ sub(r7, r1, Operand(kHeapObjectTag)); |
+ __ vldr(d6, r7, HeapNumber::kValueOffset); |
+ } else { |
+ // Calling convention says that first double is in r0 and r1. |
+ __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset)); |
+ } |
+ __ jmp(&finished_loading_r1); |
+ __ bind(&r1_is_smi); |
+ if (mode_ == OVERWRITE_LEFT) { |
+ // We can't overwrite a Smi so get address of new heap number into r5. |
+ __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); |
+ } |
- if (CpuFeatures::IsSupported(VFP3)) { |
- CpuFeatures::Scope scope(VFP3); |
- // Convert smi in r1 to double in d6. |
- __ mov(r7, Operand(r1, ASR, kSmiTagSize)); |
- __ vmov(s13, r7); |
- __ vcvt_f64_s32(d6, s13); |
- if (!use_fp_registers) { |
- __ vmov(r0, r1, d6); |
+ if (CpuFeatures::IsSupported(VFP3)) { |
+ CpuFeatures::Scope scope(VFP3); |
+ // Convert smi in r1 to double in d6. |
+ __ mov(r7, Operand(r1, ASR, kSmiTagSize)); |
+ __ vmov(s13, r7); |
+ __ vcvt_f64_s32(d6, s13); |
+ if (!use_fp_registers) { |
+ __ vmov(r0, r1, d6); |
+ } |
+ } else { |
+ // Write Smi from r1 to r1 and r0 in double format. |
+ __ mov(r7, Operand(r1)); |
+ ConvertToDoubleStub stub4(r1, r0, r7, r9); |
+ __ push(lr); |
+ __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET); |
+ __ pop(lr); |
} |
- } else { |
- // Write Smi from r1 to r1 and r0 in double format. |
- __ mov(r7, Operand(r1)); |
- ConvertToDoubleStub stub4(r1, r0, r7, r9); |
- __ push(lr); |
- __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET); |
- __ pop(lr); |
+ |
+ __ bind(&finished_loading_r1); |
} |
- __ bind(&finished_loading_r1); |
+ if (generate_code_to_calculate_answer || do_the_call.is_linked()) { |
+ __ bind(&do_the_call); |
+ // If we are inlining the operation using VFP3 instructions for |
+ // add, subtract, multiply, or divide, the arguments are in d6 and d7. |
+ if (use_fp_registers) { |
+ CpuFeatures::Scope scope(VFP3); |
+ // ARMv7 VFP3 instructions to implement |
+ // double precision, add, subtract, multiply, divide. |
- __ bind(&do_the_call); |
- // If we are inlining the operation using VFP3 instructions for |
- // add, subtract, multiply, or divide, the arguments are in d6 and d7. |
- if (use_fp_registers) { |
- CpuFeatures::Scope scope(VFP3); |
- // ARMv7 VFP3 instructions to implement |
- // double precision, add, subtract, multiply, divide. |
+ if (Token::MUL == op_) { |
+ __ vmul(d5, d6, d7); |
+ } else if (Token::DIV == op_) { |
+ __ vdiv(d5, d6, d7); |
+ } else if (Token::ADD == op_) { |
+ __ vadd(d5, d6, d7); |
+ } else if (Token::SUB == op_) { |
+ __ vsub(d5, d6, d7); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ __ sub(r0, r5, Operand(kHeapObjectTag)); |
+ __ vstr(d5, r0, HeapNumber::kValueOffset); |
+ __ add(r0, r0, Operand(kHeapObjectTag)); |
+ __ mov(pc, lr); |
+ } else { |
+ // If we did not inline the operation, then the arguments are in: |
+ // r0: Left value (least significant part of mantissa). |
+ // r1: Left value (sign, exponent, top of mantissa). |
+ // r2: Right value (least significant part of mantissa). |
+ // r3: Right value (sign, exponent, top of mantissa). |
+ // r5: Address of heap number for result. |
- if (Token::MUL == op_) { |
- __ vmul(d5, d6, d7); |
- } else if (Token::DIV == op_) { |
- __ vdiv(d5, d6, d7); |
- } else if (Token::ADD == op_) { |
- __ vadd(d5, d6, d7); |
- } else if (Token::SUB == op_) { |
- __ vsub(d5, d6, d7); |
- } else { |
- UNREACHABLE(); |
+ __ push(lr); // For later. |
+ __ PrepareCallCFunction(4, r4); // Two doubles count as 4 arguments. |
+ // Call C routine that may not cause GC or other trouble. r5 is callee |
+ // save. |
+ __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); |
+ // Store answer in the overwritable heap number. |
+ #if !defined(USE_ARM_EABI) |
+ // Double returned in fp coprocessor register 0 and 1, encoded as |
+ // register cr8. Offsets must be divisible by 4 for coprocessor so we |
+ // need to substract the tag from r5. |
+ __ sub(r4, r5, Operand(kHeapObjectTag)); |
+ __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset)); |
+ #else |
+ // Double returned in registers 0 and 1. |
+ __ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset)); |
+ #endif |
+ __ mov(r0, Operand(r5)); |
+ // And we are done. |
+ __ pop(pc); |
} |
- __ sub(r0, r5, Operand(kHeapObjectTag)); |
- __ vstr(d5, r0, HeapNumber::kValueOffset); |
- __ add(r0, r0, Operand(kHeapObjectTag)); |
- __ mov(pc, lr); |
- } else { |
- // If we did not inline the operation, then the arguments are in: |
- // r0: Left value (least significant part of mantissa). |
- // r1: Left value (sign, exponent, top of mantissa). |
- // r2: Right value (least significant part of mantissa). |
- // r3: Right value (sign, exponent, top of mantissa). |
- // r5: Address of heap number for result. |
- |
- __ push(lr); // For later. |
- __ PrepareCallCFunction(4, r4); // Two doubles count as 4 arguments. |
- // Call C routine that may not cause GC or other trouble. r5 is callee |
- // save. |
- __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); |
- // Store answer in the overwritable heap number. |
- #if !defined(USE_ARM_EABI) |
- // Double returned in fp coprocessor register 0 and 1, encoded as register |
- // cr8. Offsets must be divisible by 4 for coprocessor so we need to |
- // substract the tag from r5. |
- __ sub(r4, r5, Operand(kHeapObjectTag)); |
- __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset)); |
- #else |
- // Double returned in registers 0 and 1. |
- __ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset)); |
- #endif |
- __ mov(r0, Operand(r5)); |
- // And we are done. |
- __ pop(pc); |
} |
} |
+ if (!generate_code_to_calculate_answer && |
+ !slow_reverse.is_linked() && |
+ !slow.is_linked()) { |
+ return; |
+ } |
+ |
if (lhs.is(r0)) { |
__ b(&slow); |
__ bind(&slow_reverse); |
@@ -8745,29 +8760,15 @@ |
__ Push(r1, r0); |
- // Internal frame is necessary to handle exceptions properly. |
- __ EnterInternalFrame(); |
- // Call the stub proper to get the result in r0. |
- __ Call(&get_result); |
- __ LeaveInternalFrame(); |
- |
- __ push(r0); |
- |
- __ mov(r0, Operand(Smi::FromInt(MinorKey()))); |
- __ push(r0); |
- __ mov(r0, Operand(Smi::FromInt(op_))); |
- __ push(r0); |
+ __ mov(r2, Operand(Smi::FromInt(MinorKey()))); |
+ __ mov(r1, Operand(Smi::FromInt(op_))); |
__ mov(r0, Operand(Smi::FromInt(runtime_operands_type_))); |
- __ push(r0); |
+ __ Push(r2, r1, r0); |
__ TailCallExternalReference( |
ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), |
- 6, |
+ 5, |
1); |
- |
- // The entry point for the result calculation is assumed to be immediately |
- // after this sequence. |
- __ bind(&get_result); |
} |
@@ -8899,24 +8900,31 @@ |
// Go slow case if the value of the expression is zero |
// to make sure that we switch between 0 and -0. |
- __ cmp(r0, Operand(0)); |
- __ b(eq, &slow); |
+ if (negative_zero_ == kStrictNegativeZero) { |
+ // If we have to check for zero, then we can check for the max negative |
+ // smi while we are at it. |
+ __ bic(ip, r0, Operand(0x80000000), SetCC); |
+ __ b(eq, &slow); |
+ __ rsb(r0, r0, Operand(0)); |
+ __ StubReturn(1); |
+ } else { |
+ // The value of the expression is a smi and 0 is OK for -0. Try |
+ // optimistic subtraction '0 - value'. |
+ __ rsb(r0, r0, Operand(0), SetCC); |
+ __ StubReturn(1, vc); |
+ // We don't have to reverse the optimistic neg since the only case |
+ // where we fall through is the minimum negative Smi, which is the case |
+ // where the neg leaves the register unchanged. |
+ __ jmp(&slow); // Go slow on max negative Smi. |
+ } |
- // The value of the expression is a smi that is not zero. Try |
- // optimistic subtraction '0 - value'. |
- __ rsb(r1, r0, Operand(0), SetCC); |
- __ b(vs, &slow); |
- |
- __ mov(r0, Operand(r1)); // Set r0 to result. |
- __ b(&done); |
- |
__ bind(&try_float); |
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
__ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
__ cmp(r1, heap_number_map); |
__ b(ne, &slow); |
// r0 is a heap number. Get a new heap number in r1. |
- if (overwrite_) { |
+ if (overwrite_ == UNARY_OVERWRITE) { |
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
__ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. |
__ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
@@ -8949,7 +8957,7 @@ |
__ b(&done); |
__ bind(&try_float); |
- if (!overwrite_) { |
+ if (!overwrite_ == UNARY_OVERWRITE) { |
// Allocate a fresh heap number, but don't overwrite r0 until |
// we're sure we can do it without going through the slow case |
// that needs the value in r0. |