Index: src/arm/code-stubs-arm.cc |
=================================================================== |
--- src/arm/code-stubs-arm.cc (revision 6532) |
+++ src/arm/code-stubs-arm.cc (working copy) |
@@ -389,7 +389,7 @@ |
// floating point registers VFP3 must be supported. If core registers are |
// requested when VFP3 is supported d6 and d7 will still be scratched. If |
// either r0 or r1 is not a number (not smi and not heap number object) the |
- // not_number label is jumped to. |
+ // not_number label is jumped to with r0 and r1 intact. |
static void LoadOperands(MacroAssembler* masm, |
FloatingPointHelper::Destination destination, |
Register heap_number_map, |
@@ -417,11 +417,11 @@ |
if (CpuFeatures::IsSupported(VFP3)) { |
CpuFeatures::Scope scope(VFP3); |
__ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); |
- __ vmov(s15, scratch1); |
- __ vcvt_f64_s32(d7, s15); |
+ __ vmov(d7.high(), scratch1); |
+ __ vcvt_f64_s32(d7, d7.high()); |
__ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); |
- __ vmov(s13, scratch1); |
- __ vcvt_f64_s32(d6, s13); |
+ __ vmov(d6.high(), scratch1); |
+ __ vcvt_f64_s32(d6, d6.high()); |
if (destination == kCoreRegisters) { |
__ vmov(r2, r3, d7); |
__ vmov(r0, r1, d6); |
@@ -476,7 +476,7 @@ |
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); |
// Handle loading a double from a heap number. |
- if (CpuFeatures::IsSupported(VFP3)) { |
+ if (CpuFeatures::IsSupported(VFP3) && destination == kVFPRegisters) { |
CpuFeatures::Scope scope(VFP3); |
// Load the double from tagged HeapNumber to double register. |
__ sub(scratch1, object, Operand(kHeapObjectTag)); |
@@ -492,16 +492,17 @@ |
__ bind(&is_smi); |
if (CpuFeatures::IsSupported(VFP3)) { |
CpuFeatures::Scope scope(VFP3); |
- // Convert smi to double. |
+ // Convert smi to double using VFP instructions. |
__ SmiUntag(scratch1, object); |
__ vmov(dst.high(), scratch1); |
__ vcvt_f64_s32(dst, dst.high()); |
if (destination == kCoreRegisters) { |
+ // Load the converted smi to dst1 and dst2 in double format. |
__ vmov(dst1, dst2, dst); |
} |
} else { |
ASSERT(destination == kCoreRegisters); |
- // Write Smi to dst1 and dst2 double format. |
+ // Write smi to dst1 and dst2 double format. |
__ mov(scratch1, Operand(object)); |
ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); |
__ push(lr); |
@@ -2501,6 +2502,33 @@ |
// We fall through here if we multiplied a negative number with 0, because |
// that would mean we should produce -0. |
break; |
+ case Token::DIV: |
+ // Check for power of two on the right hand side. |
+ __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); |
+ // Check for positive and no remainder (scratch1 contains right - 1). |
+ __ orr(scratch2, scratch1, Operand(0x80000000u)); |
+ __ tst(left, scratch2); |
+ __ b(ne, ¬_smi_result); |
+ |
+ // Perform division by shifting. |
+ __ CountLeadingZeros(scratch1, scratch1, scratch2); |
+ __ rsb(scratch1, scratch1, Operand(31)); |
+ __ mov(right, Operand(left, LSR, scratch1)); |
+ __ Ret(); |
+ break; |
+ case Token::MOD: |
+ // Check for two positive smis. |
+ __ orr(scratch1, left, Operand(right)); |
+ __ tst(scratch1, Operand(0x80000000u | kSmiTagMask)); |
+ __ b(ne, ¬_smi_result); |
+ |
+ // Check for power of two on the right hand side. |
+ __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); |
+ |
+ // Perform modulus by masking. |
+ __ and_(right, left, Operand(scratch1)); |
+ __ Ret(); |
+ break; |
default: |
UNREACHABLE(); |
} |
@@ -2520,6 +2548,9 @@ |
case Token::MUL: |
__ vmul(d5, d6, d7); |
break; |
+ case Token::DIV: |
+ __ vdiv(d5, d6, d7); |
+ break; |
default: |
UNREACHABLE(); |
} |
@@ -2535,7 +2566,11 @@ |
SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { |
Label not_smis; |
- ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); |
+ ASSERT(op_ == Token::ADD || |
+ op_ == Token::SUB || |
+ op_ == Token::MUL || |
+ op_ == Token::DIV || |
+ op_ == Token::MOD); |
Register left = r1; |
Register right = r0; |
@@ -2548,13 +2583,14 @@ |
__ tst(scratch1, Operand(kSmiTagMask)); |
__ b(ne, ¬_smis); |
+ // If the smi-smi operation results in a smi return is generated. |
GenerateSmiSmiOperation(masm); |
// If heap number results are possible generate the result in an allocated |
// heap number. |
if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { |
FloatingPointHelper::Destination destination = |
- CpuFeatures::IsSupported(VFP3) && Token::MOD != op_ ? |
+ CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ? |
FloatingPointHelper::kVFPRegisters : |
FloatingPointHelper::kCoreRegisters; |
@@ -2562,9 +2598,9 @@ |
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
// Allocate new heap number for result. |
- Register heap_number = r5; |
+ Register result = r5; |
__ AllocateHeapNumber( |
- heap_number, scratch1, scratch2, heap_number_map, gc_required); |
+ result, scratch1, scratch2, heap_number_map, gc_required); |
// Load the smis. |
FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); |
@@ -2577,7 +2613,7 @@ |
CpuFeatures::Scope scope(VFP3); |
GenerateVFPOperation(masm); |
- __ sub(r0, heap_number, Operand(kHeapObjectTag)); |
+ __ sub(r0, result, Operand(kHeapObjectTag)); |
__ vstr(d5, r0, HeapNumber::kValueOffset); |
__ add(r0, r0, Operand(kHeapObjectTag)); |
__ Ret(); |
@@ -2598,13 +2634,13 @@ |
// 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(scratch1, heap_number, Operand(kHeapObjectTag)); |
+ __ sub(scratch1, result, Operand(kHeapObjectTag)); |
__ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); |
#else |
// Double returned in registers 0 and 1. |
- __ Strd(r0, r1, FieldMemOperand(heap_number, HeapNumber::kValueOffset)); |
+ __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset)); |
#endif |
- __ mov(r0, Operand(heap_number)); |
+ __ mov(r0, Operand(result)); |
// And we are done. |
__ pop(pc); |
} |
@@ -2616,7 +2652,11 @@ |
void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
Label not_smis, call_runtime; |
- ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); |
+ ASSERT(op_ == Token::ADD || |
+ op_ == Token::SUB || |
+ op_ == Token::MUL || |
+ op_ == Token::DIV || |
+ op_ == Token::MOD); |
if (result_type_ == TRBinaryOpIC::UNINITIALIZED || |
result_type_ == TRBinaryOpIC::SMI) { |
@@ -2648,7 +2688,11 @@ |
void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { |
- ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); |
+ ASSERT(op_ == Token::ADD || |
+ op_ == Token::SUB || |
+ op_ == Token::MUL || |
+ op_ == Token::DIV || |
+ op_ == Token::MOD); |
ASSERT(operands_type_ == TRBinaryOpIC::INT32); |
@@ -2657,7 +2701,11 @@ |
void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { |
- ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); |
+ ASSERT(op_ == Token::ADD || |
+ op_ == Token::SUB || |
+ op_ == Token::MUL || |
+ op_ == Token::DIV || |
+ op_ == Token::MOD); |
Register scratch1 = r7; |
Register scratch2 = r9; |
@@ -2668,10 +2716,17 @@ |
Register heap_number_map = r6; |
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
+ // Get a heap number object for the result - might be left or right if one |
+ // of these are overwritable. Uses a callee-save register to keep the value |
+ // across the C call which we might use below. |
+ Register result = r5; |
+ GenerateHeapResultAllocation( |
+ masm, result, heap_number_map, scratch1, scratch2, &call_runtime); |
+ |
// Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on |
// whether VFP3 is available. |
FloatingPointHelper::Destination destination = |
- CpuFeatures::IsSupported(VFP3) ? |
+ CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ? |
FloatingPointHelper::kVFPRegisters : |
FloatingPointHelper::kCoreRegisters; |
FloatingPointHelper::LoadOperands(masm, |
@@ -2685,13 +2740,8 @@ |
CpuFeatures::Scope scope(VFP3); |
GenerateVFPOperation(masm); |
- // Get a heap number object for the result - might be left or right if one |
- // of these are overwritable. |
- GenerateHeapResultAllocation( |
- masm, r4, heap_number_map, scratch1, scratch2, &call_runtime); |
- |
// Fill the result into the allocated heap number and return. |
- __ sub(r0, r4, Operand(kHeapObjectTag)); |
+ __ sub(r0, result, Operand(kHeapObjectTag)); |
__ vstr(d5, r0, HeapNumber::kValueOffset); |
__ add(r0, r0, Operand(kHeapObjectTag)); |
__ Ret(); |
@@ -2701,30 +2751,23 @@ |
// r0/r1: Left operand |
// r2/r3: Right operand |
- // Get a heap number object for the result - might be left or right if one |
- // of these are overwritable. Uses a callee-save register to keep the value |
- // across the c call. |
- GenerateHeapResultAllocation( |
- masm, r4, heap_number_map, scratch1, scratch2, &call_runtime); |
- |
__ push(lr); // For returning later (no GC after this point). |
__ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments. |
- // Call C routine that may not cause GC or other trouble. r4 is callee |
- // saved. |
+ // Call C routine that may not cause GC or other trouble. result (r5) is |
+ // callee saved. |
__ CallCFunction(ExternalReference::double_fp_operation(op_), 4); |
- |
// Fill the result into the allocated 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(scratch1, r4, Operand(kHeapObjectTag)); |
+ __ sub(scratch1, result, Operand(kHeapObjectTag)); |
__ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); |
#else |
// Double returned in registers 0 and 1. |
- __ Strd(r0, r1, FieldMemOperand(r4, HeapNumber::kValueOffset)); |
+ __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset)); |
#endif |
- __ mov(r0, Operand(r4)); |
+ __ mov(r0, Operand(result)); |
__ pop(pc); // Return to the pushed lr. |
} |
@@ -2737,7 +2780,11 @@ |
void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { |
- ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); |
+ ASSERT(op_ == Token::ADD || |
+ op_ == Token::SUB || |
+ op_ == Token::MUL || |
+ op_ == Token::DIV || |
+ op_ == Token::MOD); |
Label call_runtime; |
@@ -2796,6 +2843,12 @@ |
case Token::MUL: |
__ InvokeBuiltin(Builtins::MUL, JUMP_JS); |
break; |
+ case Token::DIV: |
+ __ InvokeBuiltin(Builtins::DIV, JUMP_JS); |
+ break; |
+ case Token::MOD: |
+ __ InvokeBuiltin(Builtins::MOD, JUMP_JS); |
+ break; |
default: |
UNREACHABLE(); |
} |