ARM: Implement untagged input for TranscendentalCacheStub.

Review URL: http://codereview.chromium.org/6591073

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7028 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d6a041b8
......@@ -3716,32 +3716,47 @@ void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
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 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
// 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 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
// 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);
}
......
......@@ -38,13 +38,22 @@ namespace internal {
// 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();
};
......
......@@ -5659,7 +5659,8 @@ void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
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 @@ void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
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 @@ void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
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 {
......
......@@ -3038,7 +3038,8 @@ void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
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::EmitMathSin(ZoneList<Expression*>* args) {
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::EmitMathCos(ZoneList<Expression*>* args) {
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);
......
......@@ -1210,33 +1210,30 @@ LInstruction* LChunkBuilder::DoCallConstantFunction(
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;
}
}
}
......
......@@ -766,7 +766,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
}
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;
}
......@@ -2700,6 +2701,30 @@ void LCodeGen::DoPower(LPower* instr) {
}
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) {
switch (instr->op()) {
case kMathAbs:
......@@ -2714,6 +2739,15 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
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();
......
......@@ -209,6 +209,9 @@ class LCodeGen BASE_EMBEDDED {
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,
......
......@@ -1246,6 +1246,8 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
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) {
......
......@@ -816,6 +816,39 @@ static double mod_two_doubles(double x, double 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
// integer. Uses binary decomposition to limit the number of
// multiplications; see the discussion in "Hacker's Delight" by Henry
......
......@@ -591,6 +591,10 @@ class ExternalReference BASE_EMBEDDED {
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
......
......@@ -45,8 +45,8 @@ class TranscendentalCacheStub: public CodeStub {
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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment