X64 Crankshaft: Add untagged version of TranscendentalCacheStub to x64, enable Cos, Sin, and Log in lithium.
Review URL: http://codereview.chromium.org/6580032 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6949 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
735dc96461
commit
3393fda0cf
@ -1506,40 +1506,59 @@ void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
|
||||
|
||||
|
||||
void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
||||
// Input on stack:
|
||||
// rsp[8]: argument (should be number).
|
||||
// rsp[0]: return address.
|
||||
// TAGGED case:
|
||||
// Input:
|
||||
// rsp[8]: argument (should be number).
|
||||
// rsp[0]: return address.
|
||||
// Output:
|
||||
// rax: tagged double result.
|
||||
// UNTAGGED case:
|
||||
// Input::
|
||||
// rsp[0]: return address.
|
||||
// xmm1: untagged double input argument
|
||||
// Output:
|
||||
// xmm1: untagged double result.
|
||||
|
||||
Label runtime_call;
|
||||
Label runtime_call_clear_stack;
|
||||
Label input_not_smi;
|
||||
NearLabel loaded;
|
||||
// Test that rax is a number.
|
||||
__ movq(rax, Operand(rsp, kPointerSize));
|
||||
__ JumpIfNotSmi(rax, &input_not_smi);
|
||||
// Input is a smi. Untag and load it onto the FPU stack.
|
||||
// Then load the bits of the double into rbx.
|
||||
__ SmiToInteger32(rax, rax);
|
||||
__ subq(rsp, Immediate(kPointerSize));
|
||||
__ cvtlsi2sd(xmm1, rax);
|
||||
__ movsd(Operand(rsp, 0), xmm1);
|
||||
__ movq(rbx, xmm1);
|
||||
__ movq(rdx, xmm1);
|
||||
__ fld_d(Operand(rsp, 0));
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(&loaded);
|
||||
Label skip_cache;
|
||||
const bool tagged = (argument_type_ == TAGGED);
|
||||
if (tagged) {
|
||||
NearLabel input_not_smi;
|
||||
NearLabel loaded;
|
||||
// Test that rax is a number.
|
||||
__ movq(rax, Operand(rsp, kPointerSize));
|
||||
__ JumpIfNotSmi(rax, &input_not_smi);
|
||||
// Input is a smi. Untag and load it onto the FPU stack.
|
||||
// Then load the bits of the double into rbx.
|
||||
__ SmiToInteger32(rax, rax);
|
||||
__ subq(rsp, Immediate(kDoubleSize));
|
||||
__ cvtlsi2sd(xmm1, rax);
|
||||
__ movsd(Operand(rsp, 0), xmm1);
|
||||
__ movq(rbx, xmm1);
|
||||
__ movq(rdx, xmm1);
|
||||
__ fld_d(Operand(rsp, 0));
|
||||
__ addq(rsp, Immediate(kDoubleSize));
|
||||
__ jmp(&loaded);
|
||||
|
||||
__ bind(&input_not_smi);
|
||||
// Check if input is a HeapNumber.
|
||||
__ Move(rbx, Factory::heap_number_map());
|
||||
__ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
|
||||
__ j(not_equal, &runtime_call);
|
||||
// Input is a HeapNumber. Push it on the FPU stack and load its
|
||||
// bits into rbx.
|
||||
__ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ movq(rdx, rbx);
|
||||
__ bind(&loaded);
|
||||
// ST[0] == double value
|
||||
__ bind(&input_not_smi);
|
||||
// Check if input is a HeapNumber.
|
||||
__ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex);
|
||||
__ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
|
||||
__ j(not_equal, &runtime_call);
|
||||
// Input is a HeapNumber. Push it on the FPU stack and load its
|
||||
// bits into rbx.
|
||||
__ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ movq(rdx, rbx);
|
||||
|
||||
__ bind(&loaded);
|
||||
} else { // UNTAGGED.
|
||||
__ movq(rbx, xmm1);
|
||||
__ movq(rdx, xmm1);
|
||||
}
|
||||
|
||||
// ST[0] == double value, if TAGGED.
|
||||
// rbx = bits of double value.
|
||||
// rdx = also bits of double value.
|
||||
// Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic):
|
||||
@ -1571,7 +1590,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
||||
// rax points to the cache for the type type_.
|
||||
// If NULL, the cache hasn't been initialized yet, so go through runtime.
|
||||
__ testq(rax, rax);
|
||||
__ j(zero, &runtime_call_clear_stack);
|
||||
__ j(zero, &runtime_call_clear_stack); // Only clears stack if TAGGED.
|
||||
#ifdef DEBUG
|
||||
// Check that the layout of cache elements match expectations.
|
||||
{ // NOLINT - doesn't like a single brace on a line.
|
||||
@ -1597,30 +1616,70 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
||||
__ j(not_equal, &cache_miss);
|
||||
// Cache hit!
|
||||
__ movq(rax, Operand(rcx, 2 * kIntSize));
|
||||
__ fstp(0); // Clear FPU stack.
|
||||
__ ret(kPointerSize);
|
||||
if (tagged) {
|
||||
__ fstp(0); // Clear FPU stack.
|
||||
__ ret(kPointerSize);
|
||||
} else { // UNTAGGED.
|
||||
__ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
__ bind(&cache_miss);
|
||||
// Update cache with new value.
|
||||
Label nan_result;
|
||||
GenerateOperation(masm, &nan_result);
|
||||
if (tagged) {
|
||||
__ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack);
|
||||
} else { // UNTAGGED.
|
||||
__ AllocateHeapNumber(rax, rdi, &skip_cache);
|
||||
__ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
|
||||
__ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
}
|
||||
GenerateOperation(masm);
|
||||
__ movq(Operand(rcx, 0), rbx);
|
||||
__ movq(Operand(rcx, 2 * kIntSize), rax);
|
||||
__ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ ret(kPointerSize);
|
||||
if (tagged) {
|
||||
__ ret(kPointerSize);
|
||||
} else { // UNTAGGED.
|
||||
__ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ Ret();
|
||||
|
||||
__ bind(&runtime_call_clear_stack);
|
||||
__ fstp(0);
|
||||
__ bind(&runtime_call);
|
||||
__ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
|
||||
// Skip cache and return answer directly, only in untagged case.
|
||||
__ bind(&skip_cache);
|
||||
__ subq(rsp, Immediate(kDoubleSize));
|
||||
__ movsd(Operand(rsp, 0), xmm1);
|
||||
__ fld_d(Operand(rsp, 0));
|
||||
GenerateOperation(masm);
|
||||
__ fstp_d(Operand(rsp, 0));
|
||||
__ movsd(xmm1, Operand(rsp, 0));
|
||||
__ addq(rsp, Immediate(kDoubleSize));
|
||||
// We return the value in xmm1 without adding it to the cache, but
|
||||
// we cause a scavenging GC so that future allocations will succeed.
|
||||
__ EnterInternalFrame();
|
||||
// Allocate an unused object bigger than a HeapNumber.
|
||||
__ Push(Smi::FromInt(2 * kDoubleSize));
|
||||
__ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
|
||||
__ LeaveInternalFrame();
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
__ bind(&nan_result);
|
||||
__ fstp(0); // Remove argument from FPU stack.
|
||||
__ LoadRoot(rax, Heap::kNanValueRootIndex);
|
||||
__ movq(Operand(rcx, 0), rbx);
|
||||
__ movq(Operand(rcx, 2 * kIntSize), rax);
|
||||
__ ret(kPointerSize);
|
||||
// Call runtime, doing whatever allocation and cleanup is necessary.
|
||||
if (tagged) {
|
||||
__ bind(&runtime_call_clear_stack);
|
||||
__ fstp(0);
|
||||
__ bind(&runtime_call);
|
||||
__ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
|
||||
} else { // UNTAGGED.
|
||||
__ bind(&runtime_call_clear_stack);
|
||||
__ bind(&runtime_call);
|
||||
__ AllocateHeapNumber(rax, rdi, &skip_cache);
|
||||
__ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
|
||||
__ EnterInternalFrame();
|
||||
__ push(rax);
|
||||
__ CallRuntime(RuntimeFunction(), 1);
|
||||
__ LeaveInternalFrame();
|
||||
__ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
|
||||
__ Ret();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1637,9 +1696,9 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
|
||||
}
|
||||
|
||||
|
||||
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm,
|
||||
Label* on_nan_result) {
|
||||
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
|
||||
// Registers:
|
||||
// rax: Newly allocated HeapNumber, which must be preserved.
|
||||
// rbx: Bits of input double. Must be preserved.
|
||||
// rcx: Pointer to cache entry. Must be preserved.
|
||||
// st(0): Input double
|
||||
@ -1661,9 +1720,18 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm,
|
||||
__ j(below, &in_range);
|
||||
// Check for infinity and NaN. Both return NaN for sin.
|
||||
__ cmpl(rdi, Immediate(0x7ff));
|
||||
__ j(equal, on_nan_result);
|
||||
NearLabel non_nan_result;
|
||||
__ j(not_equal, &non_nan_result);
|
||||
// Input is +/-Infinity or NaN. Result is NaN.
|
||||
__ fstp(0);
|
||||
__ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
|
||||
__ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
|
||||
__ jmp(&done);
|
||||
|
||||
__ bind(&non_nan_result);
|
||||
|
||||
// Use fpmod to restrict argument to the range +/-2*PI.
|
||||
__ movq(rdi, rax); // Save rax before using fnstsw_ax.
|
||||
__ fldpi();
|
||||
__ fadd(0);
|
||||
__ fld(1);
|
||||
@ -1696,6 +1764,7 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm,
|
||||
// FPU Stack: input % 2*pi, 2*pi,
|
||||
__ fstp(0);
|
||||
// FPU Stack: input % 2*pi
|
||||
__ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber.
|
||||
__ bind(&in_range);
|
||||
switch (type_) {
|
||||
case TranscendentalCache::SIN:
|
||||
|
@ -39,15 +39,23 @@ namespace internal {
|
||||
// TranscendentalCache runtime function.
|
||||
class TranscendentalCacheStub: public CodeStub {
|
||||
public:
|
||||
explicit TranscendentalCacheStub(TranscendentalCache::Type type)
|
||||
: type_(type) {}
|
||||
enum ArgumentType {
|
||||
TAGGED = 0,
|
||||
UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
|
||||
};
|
||||
|
||||
explicit TranscendentalCacheStub(TranscendentalCache::Type type,
|
||||
ArgumentType argument_type)
|
||||
: type_(type), argument_type_(argument_type) {}
|
||||
void Generate(MacroAssembler* masm);
|
||||
private:
|
||||
TranscendentalCache::Type type_;
|
||||
ArgumentType argument_type_;
|
||||
|
||||
Major MajorKey() { return TranscendentalCache; }
|
||||
int MinorKey() { return type_; }
|
||||
int MinorKey() { return type_ | argument_type_; }
|
||||
Runtime::FunctionId RuntimeFunction();
|
||||
void GenerateOperation(MacroAssembler* masm, Label* on_nan_result);
|
||||
void GenerateOperation(MacroAssembler* masm);
|
||||
};
|
||||
|
||||
|
||||
|
@ -7030,7 +7030,8 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
|
||||
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
|
||||
ASSERT_EQ(args->length(), 1);
|
||||
Load(args->at(0));
|
||||
TranscendentalCacheStub stub(TranscendentalCache::SIN);
|
||||
TranscendentalCacheStub stub(TranscendentalCache::SIN,
|
||||
TranscendentalCacheStub::TAGGED);
|
||||
Result result = frame_->CallStub(&stub, 1);
|
||||
frame_->Push(&result);
|
||||
}
|
||||
@ -7039,7 +7040,8 @@ void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
|
||||
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
|
||||
ASSERT_EQ(args->length(), 1);
|
||||
Load(args->at(0));
|
||||
TranscendentalCacheStub stub(TranscendentalCache::COS);
|
||||
TranscendentalCacheStub stub(TranscendentalCache::COS,
|
||||
TranscendentalCacheStub::TAGGED);
|
||||
Result result = frame_->CallStub(&stub, 1);
|
||||
frame_->Push(&result);
|
||||
}
|
||||
@ -7048,7 +7050,8 @@ void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
|
||||
void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
|
||||
ASSERT_EQ(args->length(), 1);
|
||||
Load(args->at(0));
|
||||
TranscendentalCacheStub stub(TranscendentalCache::LOG);
|
||||
TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
||||
TranscendentalCacheStub::TAGGED);
|
||||
Result result = frame_->CallStub(&stub, 1);
|
||||
frame_->Push(&result);
|
||||
}
|
||||
|
@ -2887,7 +2887,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);
|
||||
@ -2897,7 +2898,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);
|
||||
@ -2907,7 +2909,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);
|
||||
|
@ -711,7 +711,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
|
||||
break;
|
||||
}
|
||||
case CodeStub::TranscendentalCache: {
|
||||
TranscendentalCacheStub stub(instr->transcendental_type());
|
||||
TranscendentalCacheStub stub(instr->transcendental_type(),
|
||||
TranscendentalCacheStub::TAGGED);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
break;
|
||||
}
|
||||
@ -2466,17 +2467,26 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
|
||||
Abort("Unimplemented: %s", "DoMathLog");
|
||||
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
|
||||
TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
||||
TranscendentalCacheStub::UNTAGGED);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
|
||||
Abort("Unimplemented: %s", "DoMathCos");
|
||||
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
|
||||
TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
||||
TranscendentalCacheStub::UNTAGGED);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
|
||||
Abort("Unimplemented: %s", "DoMathSin");
|
||||
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
|
||||
TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
||||
TranscendentalCacheStub::UNTAGGED);
|
||||
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user