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