Revision: 6560
Author: [email protected]
Date: Tue Feb  1 08:38:25 2011
Log: ARM: Add multiplication and modulus to the type recording binary operation stub.

For now the smi part only handles power of two right hand side operands.

Fixed a bug when loading floating point value into core registers with VFP supported.
Review URL: http://codereview.chromium.org/6312059
http://code.google.com/p/v8/source/detail?r=6560

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Jan 28 09:24:10 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Feb 1 08:38:25 2011
@@ -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, &not_smi_result);
+      // Check for positive and no remainder (scratch1 contains right - 1).
+      __ orr(scratch2, scratch1, Operand(0x80000000u));
+      __ tst(left, scratch2);
+      __ b(ne, &not_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, &not_smi_result);
+
+      // Check for power of two on the right hand side.
+      __ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_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, &not_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();
   }
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Jan 28 06:18:26 2011 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Feb 1 08:38:25 2011
@@ -1550,7 +1550,11 @@
 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
                                      OverwriteMode mode) {
   __ pop(r1);
-  if (op == Token::ADD || op == Token::SUB || op == Token::MUL) {
+  if (op == Token::ADD ||
+      op == Token::SUB ||
+      op == Token::MUL ||
+      op == Token::DIV ||
+      op == Token::MOD) {
     TypeRecordingBinaryOpStub stub(op, mode);
     __ CallStub(&stub);
   } else {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Jan 31 02:16:28 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Feb 1 08:38:25 2011
@@ -1053,11 +1053,8 @@
   }

   // Check for power of two on the right hand side.
-  __ sub(scratch, right, Operand(1), SetCC);
-  __ b(mi, &call_stub);
-  __ tst(scratch, right);
-  __ b(ne, &call_stub);
-  // Perform modulo operation.
+  __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
+  // Perform modulo operation (scratch contains right - 1).
   __ and_(result, scratch, Operand(left));

   __ bind(&call_stub);
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Jan 31 02:16:28 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Feb 1 08:38:25 2011
@@ -1952,6 +1952,17 @@
     bind(&ok);
   }
 }
+
+
+void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
+    Register reg,
+    Register scratch,
+    Label* not_power_of_two_or_zero) {
+  sub(scratch, reg, Operand(1), SetCC);
+  b(mi, not_power_of_two_or_zero);
+  tst(scratch, reg);
+  b(ne, not_power_of_two_or_zero);
+}


 void MacroAssembler::JumpIfNotBothSmi(Register reg1,
@@ -2102,7 +2113,7 @@
 void MacroAssembler::CountLeadingZeros(Register zeros,   // Answer.
                                        Register source,  // Input.
                                        Register scratch) {
-  ASSERT(!zeros.is(source) || !source.is(zeros));
+  ASSERT(!zeros.is(source) || !source.is(scratch));
   ASSERT(!zeros.is(scratch));
   ASSERT(!scratch.is(ip));
   ASSERT(!source.is(ip));
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Jan 31 02:16:28 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Feb 1 08:38:25 2011
@@ -705,6 +705,17 @@
   bool generating_stub() { return generating_stub_; }
   void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
   bool allow_stub_calls() { return allow_stub_calls_; }
+
+ // ---------------------------------------------------------------------------
+  // Number utilities
+
+  // Check whether the value of reg is a power of two and not zero. If not
+ // control continues at the label not_power_of_two. If reg is a power of two + // the register scratch contains the value of (reg - 1) when control falls
+  // through.
+  void JumpIfNotPowerOfTwoOrZero(Register reg,
+                                 Register scratch,
+                                 Label* not_power_of_two_or_zero);

// ---------------------------------------------------------------------------
   // Smi utilities

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to