| 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();
|
| }
|
|
|