Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 4842) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -5087,18 +5087,28 @@ |
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
ASSERT_EQ(args->length(), 1); |
- // Load the argument on the stack and jump to the runtime. |
Load(args->at(0)); |
- frame_->CallRuntime(Runtime::kMath_sin, 1); |
+ if (CpuFeatures::IsSupported(VFP3)) { |
+ TranscendentalCacheStub stub(TranscendentalCache::SIN); |
+ frame_->SpillAllButCopyTOSToR0(); |
+ frame_->CallStub(&stub, 1); |
+ } else { |
+ frame_->CallRuntime(Runtime::kMath_sin, 1); |
+ } |
frame_->EmitPush(r0); |
} |
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { |
ASSERT_EQ(args->length(), 1); |
- // Load the argument on the stack and jump to the runtime. |
Load(args->at(0)); |
- frame_->CallRuntime(Runtime::kMath_cos, 1); |
+ if (CpuFeatures::IsSupported(VFP3)) { |
+ TranscendentalCacheStub stub(TranscendentalCache::COS); |
+ frame_->SpillAllButCopyTOSToR0(); |
+ frame_->CallStub(&stub, 1); |
+ } else { |
+ frame_->CallRuntime(Runtime::kMath_cos, 1); |
+ } |
frame_->EmitPush(r0); |
} |
@@ -7090,7 +7100,7 @@ |
CpuFeatures::Scope scope(VFP3); |
__ CheckMap(object, |
scratch1, |
- Factory::heap_number_map(), |
+ Heap::kHeapNumberMapRootIndex, |
not_found, |
true); |
@@ -8236,6 +8246,110 @@ |
} |
+void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
+ // Argument is a number and is on stack and in r0. |
+ Label runtime_call; |
+ Label input_not_smi; |
+ Label loaded; |
+ |
+ if (CpuFeatures::IsSupported(VFP3)) { |
+ // Load argument and check if it is a smi. |
+ __ BranchOnNotSmi(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)); |
+ |
+ __ bind(&loaded); |
+ // r2 = low 32 bits of double value |
+ // r3 = high 32 bits of double value |
+ // Compute hash: |
+ // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); |
+ __ eor(r1, r2, Operand(r2)); |
+ __ eor(r1, r1, Operand(r1, LSR, 16)); |
+ __ eor(r1, r1, Operand(r1, LSR, 8)); |
+ ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); |
+ if (CpuFeatures::IsSupported(ARMv7)) { |
+ const int kTranscendentalCacheSizeBits = 9; |
+ ASSERT_EQ(1 << kTranscendentalCacheSizeBits, |
+ TranscendentalCache::kCacheSize); |
+ __ ubfx(r1, r1, 0, kTranscendentalCacheSizeBits); |
+ } else { |
+ __ and_(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); |
+ } |
+ |
+ // r2 = low 32 bits of double value. |
+ // r3 = high 32 bits of double value. |
+ // r1 = TranscendentalCache::hash(double value). |
+ __ mov(r0, |
+ Operand(ExternalReference::transcendental_cache_array_address())); |
+ // r0 points to cache array. |
+ __ ldr(r0, MemOperand(r0, 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)); |
+ __ b(eq, &runtime_call); |
+ |
+#ifdef DEBUG |
+ // Check that the layout of cache elements match expectations. |
+ { TranscendentalCache::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 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)); |
+ // Check if cache matches: Double value is stored in uint32_t[2] array. |
+ __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit()); |
+ __ cmp(r2, r4); |
+ __ b(ne, &runtime_call); |
+ __ cmp(r3, r5); |
+ __ b(ne, &runtime_call); |
+ // Cache hit. Load result, pop argument and return. |
+ __ mov(r0, Operand(r6)); |
+ __ pop(); |
+ __ Ret(); |
+ } |
+ |
+ __ bind(&runtime_call); |
+ __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
+} |
+ |
+ |
+Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
+ switch (type_) { |
+ // Add more cases when necessary. |
+ case TranscendentalCache::SIN: return Runtime::kMath_sin; |
+ case TranscendentalCache::COS: return Runtime::kMath_cos; |
+ default: |
+ UNIMPLEMENTED(); |
+ return Runtime::kAbort; |
+ } |
+} |
+ |
+ |
void StackCheckStub::Generate(MacroAssembler* masm) { |
// Do tail-call to runtime routine. Runtime routines expect at least one |
// argument, so give it a Smi. |
@@ -9550,8 +9664,11 @@ |
// Index is not a smi. |
__ bind(&index_not_smi_); |
// If index is a heap number, try converting it to an integer. |
- __ CheckMap(index_, scratch_, |
- Factory::heap_number_map(), index_not_number_, true); |
+ __ CheckMap(index_, |
+ scratch_, |
+ Heap::kHeapNumberMapRootIndex, |
+ index_not_number_, |
+ true); |
call_helper.BeforeCall(masm); |
__ Push(object_, index_); |
__ push(index_); // Consumed by runtime conversion function. |