| Index: src/ia32/code-stubs-ia32.cc
|
| diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
|
| index 4633400688d3f3864d1324967522f28e8888dad1..208bd91a0db7cc6a74fc879e681a8bece0e930e6 100644
|
| --- a/src/ia32/code-stubs-ia32.cc
|
| +++ b/src/ia32/code-stubs-ia32.cc
|
| @@ -695,228 +695,6 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
| }
|
|
|
|
|
| -void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
|
| - // TAGGED case:
|
| - // Input:
|
| - // esp[4]: tagged number input argument (should be number).
|
| - // esp[0]: return address.
|
| - // Output:
|
| - // eax: tagged double result.
|
| - // UNTAGGED case:
|
| - // Input::
|
| - // esp[0]: return address.
|
| - // xmm1: untagged double input argument
|
| - // Output:
|
| - // xmm1: untagged double result.
|
| -
|
| - Label runtime_call;
|
| - Label runtime_call_clear_stack;
|
| - Label skip_cache;
|
| - const bool tagged = (argument_type_ == TAGGED);
|
| - if (tagged) {
|
| - // Test that eax is a number.
|
| - Label input_not_smi;
|
| - Label loaded;
|
| - __ mov(eax, Operand(esp, kPointerSize));
|
| - __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear);
|
| - // Input is a smi. Untag and load it onto the FPU stack.
|
| - // Then load the low and high words of the double into ebx, edx.
|
| - STATIC_ASSERT(kSmiTagSize == 1);
|
| - __ sar(eax, 1);
|
| - __ sub(esp, Immediate(2 * kPointerSize));
|
| - __ mov(Operand(esp, 0), eax);
|
| - __ fild_s(Operand(esp, 0));
|
| - __ fst_d(Operand(esp, 0));
|
| - __ pop(edx);
|
| - __ pop(ebx);
|
| - __ jmp(&loaded, Label::kNear);
|
| - __ bind(&input_not_smi);
|
| - // Check if input is a HeapNumber.
|
| - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
| - Factory* factory = masm->isolate()->factory();
|
| - __ cmp(ebx, Immediate(factory->heap_number_map()));
|
| - __ j(not_equal, &runtime_call);
|
| - // Input is a HeapNumber. Push it on the FPU stack and load its
|
| - // low and high words into ebx, edx.
|
| - __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
|
| - __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
|
| - __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
|
| -
|
| - __ bind(&loaded);
|
| - } else { // UNTAGGED.
|
| - CpuFeatureScope scope(masm, SSE2);
|
| - if (CpuFeatures::IsSupported(SSE4_1)) {
|
| - CpuFeatureScope sse4_scope(masm, SSE4_1);
|
| - __ pextrd(edx, xmm1, 0x1); // copy xmm1[63..32] to edx.
|
| - } else {
|
| - __ pshufd(xmm0, xmm1, 0x1);
|
| - __ movd(edx, xmm0);
|
| - }
|
| - __ movd(ebx, xmm1);
|
| - }
|
| -
|
| - // ST[0] or xmm1 == double value
|
| - // ebx = low 32 bits of double value
|
| - // edx = high 32 bits of double value
|
| - // Compute hash (the shifts are arithmetic):
|
| - // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
|
| - __ mov(ecx, ebx);
|
| - __ xor_(ecx, edx);
|
| - __ mov(eax, ecx);
|
| - __ sar(eax, 16);
|
| - __ xor_(ecx, eax);
|
| - __ mov(eax, ecx);
|
| - __ sar(eax, 8);
|
| - __ xor_(ecx, eax);
|
| - ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize));
|
| - __ and_(ecx,
|
| - Immediate(TranscendentalCache::SubCache::kCacheSize - 1));
|
| -
|
| - // ST[0] or xmm1 == double value.
|
| - // ebx = low 32 bits of double value.
|
| - // edx = high 32 bits of double value.
|
| - // ecx = TranscendentalCache::hash(double value).
|
| - ExternalReference cache_array =
|
| - ExternalReference::transcendental_cache_array_address(masm->isolate());
|
| - __ mov(eax, Immediate(cache_array));
|
| - int cache_array_index =
|
| - type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]);
|
| - __ mov(eax, Operand(eax, cache_array_index));
|
| - // Eax points to the cache for the type type_.
|
| - // If NULL, the cache hasn't been initialized yet, so go through runtime.
|
| - __ test(eax, eax);
|
| - __ j(zero, &runtime_call_clear_stack);
|
| -#ifdef DEBUG
|
| - // Check that the layout of cache elements match expectations.
|
| - { TranscendentalCache::SubCache::Element test_elem[2];
|
| - char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
|
| - char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
|
| - char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
|
| - char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
|
| - char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
|
| - CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
|
| - CHECK_EQ(0, elem_in0 - elem_start);
|
| - CHECK_EQ(kIntSize, elem_in1 - elem_start);
|
| - CHECK_EQ(2 * kIntSize, elem_out - elem_start);
|
| - }
|
| -#endif
|
| - // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
|
| - __ lea(ecx, Operand(ecx, ecx, times_2, 0));
|
| - __ lea(ecx, Operand(eax, ecx, times_4, 0));
|
| - // Check if cache matches: Double value is stored in uint32_t[2] array.
|
| - Label cache_miss;
|
| - __ cmp(ebx, Operand(ecx, 0));
|
| - __ j(not_equal, &cache_miss, Label::kNear);
|
| - __ cmp(edx, Operand(ecx, kIntSize));
|
| - __ j(not_equal, &cache_miss, Label::kNear);
|
| - // Cache hit!
|
| - Counters* counters = masm->isolate()->counters();
|
| - __ IncrementCounter(counters->transcendental_cache_hit(), 1);
|
| - __ mov(eax, Operand(ecx, 2 * kIntSize));
|
| - if (tagged) {
|
| - __ fstp(0);
|
| - __ ret(kPointerSize);
|
| - } else { // UNTAGGED.
|
| - CpuFeatureScope scope(masm, SSE2);
|
| - __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
| - __ Ret();
|
| - }
|
| -
|
| - __ bind(&cache_miss);
|
| - __ IncrementCounter(counters->transcendental_cache_miss(), 1);
|
| - // Update cache with new value.
|
| - // We are short on registers, so use no_reg as scratch.
|
| - // This gives slightly larger code.
|
| - if (tagged) {
|
| - __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
|
| - } else { // UNTAGGED.
|
| - CpuFeatureScope scope(masm, SSE2);
|
| - __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
|
| - __ sub(esp, Immediate(kDoubleSize));
|
| - __ movsd(Operand(esp, 0), xmm1);
|
| - __ fld_d(Operand(esp, 0));
|
| - __ add(esp, Immediate(kDoubleSize));
|
| - }
|
| - GenerateOperation(masm, type_);
|
| - __ mov(Operand(ecx, 0), ebx);
|
| - __ mov(Operand(ecx, kIntSize), edx);
|
| - __ mov(Operand(ecx, 2 * kIntSize), eax);
|
| - __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
|
| - if (tagged) {
|
| - __ ret(kPointerSize);
|
| - } else { // UNTAGGED.
|
| - CpuFeatureScope scope(masm, SSE2);
|
| - __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
| - __ Ret();
|
| -
|
| - // Skip cache and return answer directly, only in untagged case.
|
| - __ bind(&skip_cache);
|
| - __ sub(esp, Immediate(kDoubleSize));
|
| - __ movsd(Operand(esp, 0), xmm1);
|
| - __ fld_d(Operand(esp, 0));
|
| - GenerateOperation(masm, type_);
|
| - __ fstp_d(Operand(esp, 0));
|
| - __ movsd(xmm1, Operand(esp, 0));
|
| - __ add(esp, 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.
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - // Allocate an unused object bigger than a HeapNumber.
|
| - __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
|
| - __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
|
| - }
|
| - __ Ret();
|
| - }
|
| -
|
| - // Call runtime, doing whatever allocation and cleanup is necessary.
|
| - if (tagged) {
|
| - __ bind(&runtime_call_clear_stack);
|
| - __ fstp(0);
|
| - __ bind(&runtime_call);
|
| - ExternalReference runtime =
|
| - ExternalReference(RuntimeFunction(), masm->isolate());
|
| - __ TailCallExternalReference(runtime, 1, 1);
|
| - } else { // UNTAGGED.
|
| - CpuFeatureScope scope(masm, SSE2);
|
| - __ bind(&runtime_call_clear_stack);
|
| - __ bind(&runtime_call);
|
| - __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
|
| - __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
|
| - {
|
| - FrameScope scope(masm, StackFrame::INTERNAL);
|
| - __ push(eax);
|
| - __ CallRuntime(RuntimeFunction(), 1);
|
| - }
|
| - __ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
| - __ Ret();
|
| - }
|
| -}
|
| -
|
| -
|
| -Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
|
| - switch (type_) {
|
| - case TranscendentalCache::LOG: return Runtime::kMath_log;
|
| - default:
|
| - UNIMPLEMENTED();
|
| - return Runtime::kAbort;
|
| - }
|
| -}
|
| -
|
| -
|
| -void TranscendentalCacheStub::GenerateOperation(
|
| - MacroAssembler* masm, TranscendentalCache::Type type) {
|
| - // Only free register is edi.
|
| - // Input value is on FP stack, and also in ebx/edx.
|
| - // Input value is possibly in xmm1.
|
| - // Address of result (a newly allocated HeapNumber) may be in eax.
|
| - ASSERT(type == TranscendentalCache::LOG);
|
| - __ fldln2();
|
| - __ fxch();
|
| - __ fyl2x();
|
| -}
|
| -
|
| -
|
| void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
|
| Register number) {
|
| Label load_smi, done;
|
|
|