Revision: 7028
Author: [email protected]
Date: Wed Mar  2 06:40:38 2011
Log: ARM: Implement untagged input for TranscendentalCacheStub.

Review URL: http://codereview.chromium.org/6591073
http://code.google.com/p/v8/source/detail?r=7028

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

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Wed Mar 2 01:31:42 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Wed Mar 2 06:40:38 2011
@@ -3716,32 +3716,47 @@


 void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
-  // Argument is a number and is on stack and in r0.
-  Label runtime_call;
+  // Untagged case: double input in d2, double result goes
+  //   into d2.
+  // Tagged case: tagged input on top of stack and in r0,
+  //   tagged result (heap number) goes into r0.
+
   Label input_not_smi;
   Label loaded;
+  Label calculate;
+  Label invalid_cache;
+  const Register scratch0 = r9;
+  const Register scratch1 = r7;
+  const Register cache_entry = r0;
+  const bool tagged = (argument_type_ == TAGGED);

   if (CpuFeatures::IsSupported(VFP3)) {
-    // Load argument and check if it is a smi.
-    __ JumpIfNotSmi(r0, &input_not_smi);
-
     CpuFeatures::Scope scope(VFP3);
-    // Input is a smi. Convert to double and load the low and high words
-    // of the double into r2, r3.
-    __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
-    __ b(&loaded);
-
-    __ bind(&input_not_smi);
-    // Check if input is a HeapNumber.
-    __ CheckMap(r0,
-                r1,
-                Heap::kHeapNumberMapRootIndex,
-                &runtime_call,
-                true);
-    // Input is a HeapNumber. Load it to a double register and store the
-    // low and high words into r2, r3.
-    __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
-
+    if (tagged) {
+      // Argument is a number and is on stack and in r0.
+      // Load argument and check if it is a smi.
+      __ JumpIfNotSmi(r0, &input_not_smi);
+
+      // Input is a smi. Convert to double and load the low and high words
+      // of the double into r2, r3.
+      __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
+      __ b(&loaded);
+
+      __ bind(&input_not_smi);
+      // Check if input is a HeapNumber.
+      __ CheckMap(r0,
+                  r1,
+                  Heap::kHeapNumberMapRootIndex,
+                  &calculate,
+                  true);
+      // Input is a HeapNumber. Load it to a double register and store the
+      // low and high words into r2, r3.
+      __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+      __ vmov(r2, r3, d0);
+    } else {
+      // Input is untagged double in d2. Output goes to d2.
+      __ vmov(r2, r3, d2);
+    }
     __ bind(&loaded);
     // r2 = low 32 bits of double value
     // r3 = high 32 bits of double value
@@ -3756,14 +3771,15 @@
     // r2 = low 32 bits of double value.
     // r3 = high 32 bits of double value.
     // r1 = TranscendentalCache::hash(double value).
-    __ mov(r0,
+    __ mov(cache_entry,
Operand(ExternalReference::transcendental_cache_array_address()));
     // r0 points to cache array.
- __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0])));
+    __ ldr(cache_entry, MemOperand(cache_entry,
+        type_ * sizeof(TranscendentalCache::caches_[0])));
     // r0 points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
-    __ cmp(r0, Operand(0, RelocInfo::NONE));
-    __ b(eq, &runtime_call);
+    __ cmp(cache_entry, Operand(0, RelocInfo::NONE));
+    __ b(eq, &invalid_cache);

 #ifdef DEBUG
     // Check that the layout of cache elements match expectations.
@@ -3782,21 +3798,109 @@

     // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
     __ add(r1, r1, Operand(r1, LSL, 1));
-    __ add(r0, r0, Operand(r1, LSL, 2));
+    __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
     // Check if cache matches: Double value is stored in uint32_t[2] array.
-    __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit());
+    __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
     __ cmp(r2, r4);
-    __ b(ne, &runtime_call);
+    __ b(ne, &calculate);
     __ cmp(r3, r5);
-    __ b(ne, &runtime_call);
-    // Cache hit. Load result, pop argument and return.
-    __ mov(r0, Operand(r6));
-    __ pop();
+    __ b(ne, &calculate);
+    // Cache hit. Load result, cleanup and return.
+    if (tagged) {
+      // Pop input value from stack and load result into r0.
+      __ pop();
+      __ mov(r0, Operand(r6));
+    } else {
+      // Load result into d2.
+       __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
+    }
+    __ Ret();
+  }  // if (CpuFeatures::IsSupported(VFP3))
+
+  __ bind(&calculate);
+  if (tagged) {
+    __ bind(&invalid_cache);
+ __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+  } else {
+    if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE();
+    CpuFeatures::Scope scope(VFP3);
+
+    Label no_update;
+    Label skip_cache;
+    const Register heap_number_map = r5;
+
+    // Call C function to calculate the result and update the cache.
+    // Register r0 holds precalculated cache entry address; preserve
+    // it on the stack and pop it into register cache_entry after the
+    // call.
+    __ push(cache_entry);
+    GenerateCallCFunction(masm, scratch0);
+    __ GetCFunctionDoubleResult(d2);
+
+    // Try to update the cache. If we cannot allocate a
+    // heap number, we return the result without updating.
+    __ pop(cache_entry);
+    __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update);
+    __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
+    __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit());
+    __ Ret();
+
+    __ bind(&invalid_cache);
+    // The cache is invalid. Call runtime which will recreate the
+    // cache.
+    __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache);
+    __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
+    __ EnterInternalFrame();
+    __ push(r0);
+    __ CallRuntime(RuntimeFunction(), 1);
+    __ LeaveInternalFrame();
+    __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
+    __ Ret();
+
+    __ bind(&skip_cache);
+    // Call C function to calculate the result and answer directly
+    // without updating the cache.
+    GenerateCallCFunction(masm, scratch0);
+    __ GetCFunctionDoubleResult(d2);
+    __ bind(&no_update);
+
+    // We return the value in d2 without adding it to the cache, but
+    // we cause a scavenging GC so that future allocations will succeed.
+    __ EnterInternalFrame();
+
+    // Allocate an aligned object larger than a HeapNumber.
+    ASSERT(4 * kPointerSize >= HeapNumber::kSize);
+    __ mov(scratch0, Operand(4 * kPointerSize));
+    __ push(scratch0);
+    __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
+    __ LeaveInternalFrame();
     __ Ret();
   }
-
-  __ bind(&runtime_call);
-  __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+}
+
+
+void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
+                                                    Register scratch) {
+  __ push(lr);
+  __ PrepareCallCFunction(2, scratch);
+  __ vmov(r0, r1, d2);
+  switch (type_) {
+    case TranscendentalCache::SIN:
+      __ CallCFunction(ExternalReference::math_sin_double_function(), 2);
+      break;
+    case TranscendentalCache::COS:
+      __ CallCFunction(ExternalReference::math_cos_double_function(), 2);
+      break;
+    case TranscendentalCache::LOG:
+      __ CallCFunction(ExternalReference::math_log_double_function(), 2);
+      break;
+    default:
+      UNIMPLEMENTED();
+      break;
+  }
+  __ pop(lr);
 }


=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.h Thu Feb 24 07:39:09 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.h Wed Mar 2 06:40:38 2011
@@ -38,13 +38,22 @@
 // TranscendentalCache runtime function.
 class TranscendentalCacheStub: public CodeStub {
  public:
-  explicit TranscendentalCacheStub(TranscendentalCache::Type type)
-      : type_(type) {}
+  enum ArgumentType {
+    TAGGED = 0 << TranscendentalCache::kTranscendentalTypeBits,
+    UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
+  };
+
+  TranscendentalCacheStub(TranscendentalCache::Type type,
+                          ArgumentType argument_type)
+      : type_(type), argument_type_(argument_type) { }
   void Generate(MacroAssembler* masm);
  private:
   TranscendentalCache::Type type_;
+  ArgumentType argument_type_;
+  void GenerateCallCFunction(MacroAssembler* masm, Register scratch);
+
   Major MajorKey() { return TranscendentalCache; }
-  int MinorKey() { return type_; }
+  int MinorKey() { return type_ | argument_type_; }
   Runtime::FunctionId RuntimeFunction();
 };

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Tue Mar  1 20:53:43 2011
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Wed Mar  2 06:40:38 2011
@@ -5659,7 +5659,8 @@
   ASSERT_EQ(args->length(), 1);
   Load(args->at(0));
   if (CpuFeatures::IsSupported(VFP3)) {
-    TranscendentalCacheStub stub(TranscendentalCache::SIN);
+    TranscendentalCacheStub stub(TranscendentalCache::SIN,
+                                 TranscendentalCacheStub::TAGGED);
     frame_->SpillAllButCopyTOSToR0();
     frame_->CallStub(&stub, 1);
   } else {
@@ -5673,7 +5674,8 @@
   ASSERT_EQ(args->length(), 1);
   Load(args->at(0));
   if (CpuFeatures::IsSupported(VFP3)) {
-    TranscendentalCacheStub stub(TranscendentalCache::COS);
+    TranscendentalCacheStub stub(TranscendentalCache::COS,
+                                 TranscendentalCacheStub::TAGGED);
     frame_->SpillAllButCopyTOSToR0();
     frame_->CallStub(&stub, 1);
   } else {
@@ -5687,7 +5689,8 @@
   ASSERT_EQ(args->length(), 1);
   Load(args->at(0));
   if (CpuFeatures::IsSupported(VFP3)) {
-    TranscendentalCacheStub stub(TranscendentalCache::LOG);
+    TranscendentalCacheStub stub(TranscendentalCache::LOG,
+                                 TranscendentalCacheStub::TAGGED);
     frame_->SpillAllButCopyTOSToR0();
     frame_->CallStub(&stub, 1);
   } else {
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Mar 1 20:53:43 2011 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Mar 2 06:40:38 2011
@@ -3038,7 +3038,8 @@

 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
   // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::SIN);
+  TranscendentalCacheStub stub(TranscendentalCache::SIN,
+                               TranscendentalCacheStub::TAGGED);
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallStub(&stub);
@@ -3048,7 +3049,8 @@

 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
   // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::COS);
+  TranscendentalCacheStub stub(TranscendentalCache::COS,
+                               TranscendentalCacheStub::TAGGED);
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallStub(&stub);
@@ -3058,7 +3060,8 @@

 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
   // Load the argument on the stack and call the stub.
-  TranscendentalCacheStub stub(TranscendentalCache::LOG);
+  TranscendentalCacheStub stub(TranscendentalCache::LOG,
+                               TranscendentalCacheStub::TAGGED);
   ASSERT(args->length() == 1);
   VisitForStackValue(args->at(0));
   __ CallStub(&stub);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Tue Mar  1 07:37:24 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Wed Mar  2 06:40:38 2011
@@ -1210,33 +1210,30 @@

LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
   BuiltinFunctionId op = instr->op();
-  LOperand* input = UseRegisterAtStart(instr->value());
-  LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
-  LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
-  switch (op) {
-    case kMathAbs:
- return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
-    case kMathFloor:
-      return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
-    case kMathSqrt:
-      return DefineSameAsFirst(result);
-    case kMathRound:
-      return AssignEnvironment(DefineAsRegister(result));
-    case kMathPowHalf:
-      Abort("MathPowHalf LUnaryMathOperation not implemented");
-      return NULL;
-    case kMathLog:
-      Abort("MathLog LUnaryMathOperation not implemented");
-      return NULL;
-    case kMathCos:
-      Abort("MathCos LUnaryMathOperation not implemented");
-      return NULL;
-    case kMathSin:
-      Abort("MathSin LUnaryMathOperation not implemented");
-      return NULL;
-    default:
-      UNREACHABLE();
-      return NULL;
+  if (op == kMathLog || op == kMathSin || op == kMathCos) {
+    LOperand* input = UseFixedDouble(instr->value(), d2);
+    LUnaryMathOperation* result = new LUnaryMathOperation(input, NULL);
+    return MarkAsCall(DefineFixedDouble(result, d2), instr);
+  } else {
+    LOperand* input = UseRegisterAtStart(instr->value());
+    LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
+    LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
+    switch (op) {
+      case kMathAbs:
+ return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+      case kMathFloor:
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+      case kMathSqrt:
+        return DefineSameAsFirst(result);
+      case kMathRound:
+        return AssignEnvironment(DefineAsRegister(result));
+      case kMathPowHalf:
+        Abort("MathPowHalf LUnaryMathOperation not implemented");
+        return NULL;
+      default:
+        UNREACHABLE();
+        return NULL;
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Mar 2 01:31:42 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Mar 2 06:40:38 2011
@@ -766,7 +766,8 @@
     }
     case CodeStub::TranscendentalCache: {
       __ ldr(r0, MemOperand(sp, 0));
-      TranscendentalCacheStub stub(instr->transcendental_type());
+      TranscendentalCacheStub stub(instr->transcendental_type(),
+                                   TranscendentalCacheStub::TAGGED);
       CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
       break;
     }
@@ -2698,6 +2699,30 @@
   // Store the result in the result register.
   __ GetCFunctionDoubleResult(result_reg);
 }
+
+
+void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
+  ASSERT(ToDoubleRegister(instr->result()).is(d2));
+  TranscendentalCacheStub stub(TranscendentalCache::LOG,
+                               TranscendentalCacheStub::UNTAGGED);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+  ASSERT(ToDoubleRegister(instr->result()).is(d2));
+  TranscendentalCacheStub stub(TranscendentalCache::COS,
+                               TranscendentalCacheStub::UNTAGGED);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+  ASSERT(ToDoubleRegister(instr->result()).is(d2));
+  TranscendentalCacheStub stub(TranscendentalCache::SIN,
+                               TranscendentalCacheStub::UNTAGGED);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}


 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
@@ -2714,6 +2739,15 @@
     case kMathSqrt:
       DoMathSqrt(instr);
       break;
+    case kMathCos:
+      DoMathCos(instr);
+      break;
+    case kMathSin:
+      DoMathSin(instr);
+      break;
+    case kMathLog:
+      DoMathLog(instr);
+      break;
     default:
       Abort("Unimplemented type of LUnaryMathOperation.");
       UNREACHABLE();
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Wed Mar 2 01:31:42 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Wed Mar 2 06:40:38 2011
@@ -209,6 +209,9 @@
   void DoMathFloor(LUnaryMathOperation* instr);
   void DoMathRound(LUnaryMathOperation* instr);
   void DoMathSqrt(LUnaryMathOperation* instr);
+  void DoMathLog(LUnaryMathOperation* instr);
+  void DoMathCos(LUnaryMathOperation* instr);
+  void DoMathSin(LUnaryMathOperation* instr);

   // Support for recording safepoint and position information.
   void RecordSafepoint(LPointerMap* pointers,
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Mar 2 01:31:42 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Mar 2 06:40:38 2011
@@ -1246,6 +1246,8 @@
   ASSERT(!result.is(scratch1));
   ASSERT(!result.is(scratch2));
   ASSERT(!scratch1.is(scratch2));
+  ASSERT(!scratch1.is(ip));
+  ASSERT(!scratch2.is(ip));

   // Make object size into bytes.
   if ((flags & SIZE_IN_WORDS) != 0) {
=======================================
--- /branches/bleeding_edge/src/assembler.cc    Thu Feb 24 02:29:01 2011
+++ /branches/bleeding_edge/src/assembler.cc    Wed Mar  2 06:40:38 2011
@@ -814,6 +814,39 @@
 static double mod_two_doubles(double x, double y) {
   return modulo(x, y);
 }
+
+
+static double math_sin_double(double x) {
+  return sin(x);
+}
+
+
+static double math_cos_double(double x) {
+  return cos(x);
+}
+
+
+static double math_log_double(double x) {
+  return log(x);
+}
+
+
+ExternalReference ExternalReference::math_sin_double_function() {
+  return ExternalReference(Redirect(FUNCTION_ADDR(math_sin_double),
+                                    FP_RETURN_CALL));
+}
+
+
+ExternalReference ExternalReference::math_cos_double_function() {
+  return ExternalReference(Redirect(FUNCTION_ADDR(math_cos_double),
+                                    FP_RETURN_CALL));
+}
+
+
+ExternalReference ExternalReference::math_log_double_function() {
+  return ExternalReference(Redirect(FUNCTION_ADDR(math_log_double),
+                                    FP_RETURN_CALL));
+}


 // Helper function to compute x^y, where y is known to be an
=======================================
--- /branches/bleeding_edge/src/assembler.h     Thu Feb 24 07:39:09 2011
+++ /branches/bleeding_edge/src/assembler.h     Wed Mar  2 06:40:38 2011
@@ -591,6 +591,10 @@
   static ExternalReference address_of_minus_zero();
   static ExternalReference address_of_negative_infinity();

+  static ExternalReference math_sin_double_function();
+  static ExternalReference math_cos_double_function();
+  static ExternalReference math_log_double_function();
+
   Address address() const {return reinterpret_cast<Address>(address_);}

 #ifdef ENABLE_DEBUGGER_SUPPORT
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.h Mon Feb 14 13:21:33 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.h Wed Mar 2 06:40:38 2011
@@ -45,8 +45,8 @@
     UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
   };

-  explicit TranscendentalCacheStub(TranscendentalCache::Type type,
-                                   ArgumentType argument_type)
+  TranscendentalCacheStub(TranscendentalCache::Type type,
+                          ArgumentType argument_type)
       : type_(type), argument_type_(argument_type) {}
   void Generate(MacroAssembler* masm);
  private:

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

Reply via email to