Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: src/arm/code-stubs-arm.cc

Issue 6591073: ARM: Implement untagged input for TranscendentalCacheStub. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix lint. Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/code-stubs-arm.h ('k') | src/arm/codegen-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 3698 matching lines...) Expand 10 before | Expand all | Expand 10 after
3709 } 3709 }
3710 } 3710 }
3711 3711
3712 3712
3713 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 3713 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
3714 __ Push(r1, r0); 3714 __ Push(r1, r0);
3715 } 3715 }
3716 3716
3717 3717
3718 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { 3718 void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
3719 // Argument is a number and is on stack and in r0. 3719 // Untagged case: double input in d2, double result goes
3720 Label runtime_call; 3720 // into d2.
3721 // Tagged case: tagged input on top of stack and in r0,
3722 // tagged result (heap number) goes into r0.
3723
3721 Label input_not_smi; 3724 Label input_not_smi;
3722 Label loaded; 3725 Label loaded;
3726 Label calculate;
3727 Label invalid_cache;
3728 const Register scratch0 = r9;
3729 const Register scratch1 = r7;
3730 const Register cache_entry = r0;
3731 const bool tagged = (argument_type_ == TAGGED);
3723 3732
3724 if (CpuFeatures::IsSupported(VFP3)) { 3733 if (CpuFeatures::IsSupported(VFP3)) {
3725 // Load argument and check if it is a smi. 3734 CpuFeatures::Scope scope(VFP3);
3726 __ JumpIfNotSmi(r0, &input_not_smi); 3735 if (tagged) {
3736 // Argument is a number and is on stack and in r0.
3737 // Load argument and check if it is a smi.
3738 __ JumpIfNotSmi(r0, &input_not_smi);
3727 3739
3728 CpuFeatures::Scope scope(VFP3); 3740 // Input is a smi. Convert to double and load the low and high words
3729 // Input is a smi. Convert to double and load the low and high words 3741 // of the double into r2, r3.
3730 // of the double into r2, r3. 3742 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2);
3731 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); 3743 __ b(&loaded);
3732 __ b(&loaded);
3733 3744
3734 __ bind(&input_not_smi); 3745 __ bind(&input_not_smi);
3735 // Check if input is a HeapNumber. 3746 // Check if input is a HeapNumber.
3736 __ CheckMap(r0, 3747 __ CheckMap(r0,
3737 r1, 3748 r1,
3738 Heap::kHeapNumberMapRootIndex, 3749 Heap::kHeapNumberMapRootIndex,
3739 &runtime_call, 3750 &calculate,
3740 true); 3751 true);
3741 // Input is a HeapNumber. Load it to a double register and store the 3752 // Input is a HeapNumber. Load it to a double register and store the
3742 // low and high words into r2, r3. 3753 // low and high words into r2, r3.
3743 __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); 3754 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
3744 3755 __ vmov(r2, r3, d0);
3756 } else {
3757 // Input is untagged double in d2. Output goes to d2.
3758 __ vmov(r2, r3, d2);
3759 }
3745 __ bind(&loaded); 3760 __ bind(&loaded);
3746 // r2 = low 32 bits of double value 3761 // r2 = low 32 bits of double value
3747 // r3 = high 32 bits of double value 3762 // r3 = high 32 bits of double value
3748 // Compute hash (the shifts are arithmetic): 3763 // Compute hash (the shifts are arithmetic):
3749 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 3764 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
3750 __ eor(r1, r2, Operand(r3)); 3765 __ eor(r1, r2, Operand(r3));
3751 __ eor(r1, r1, Operand(r1, ASR, 16)); 3766 __ eor(r1, r1, Operand(r1, ASR, 16));
3752 __ eor(r1, r1, Operand(r1, ASR, 8)); 3767 __ eor(r1, r1, Operand(r1, ASR, 8));
3753 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); 3768 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
3754 __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); 3769 __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1));
3755 3770
3756 // r2 = low 32 bits of double value. 3771 // r2 = low 32 bits of double value.
3757 // r3 = high 32 bits of double value. 3772 // r3 = high 32 bits of double value.
3758 // r1 = TranscendentalCache::hash(double value). 3773 // r1 = TranscendentalCache::hash(double value).
3759 __ mov(r0, 3774 __ mov(cache_entry,
3760 Operand(ExternalReference::transcendental_cache_array_address())); 3775 Operand(ExternalReference::transcendental_cache_array_address()));
3761 // r0 points to cache array. 3776 // r0 points to cache array.
3762 __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0]))); 3777 __ ldr(cache_entry, MemOperand(cache_entry,
3778 type_ * sizeof(TranscendentalCache::caches_[0])));
3763 // r0 points to the cache for the type type_. 3779 // r0 points to the cache for the type type_.
3764 // If NULL, the cache hasn't been initialized yet, so go through runtime. 3780 // If NULL, the cache hasn't been initialized yet, so go through runtime.
3765 __ cmp(r0, Operand(0, RelocInfo::NONE)); 3781 __ cmp(cache_entry, Operand(0, RelocInfo::NONE));
3766 __ b(eq, &runtime_call); 3782 __ b(eq, &invalid_cache);
3767 3783
3768 #ifdef DEBUG 3784 #ifdef DEBUG
3769 // Check that the layout of cache elements match expectations. 3785 // Check that the layout of cache elements match expectations.
3770 { TranscendentalCache::Element test_elem[2]; 3786 { TranscendentalCache::Element test_elem[2];
3771 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 3787 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
3772 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 3788 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
3773 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 3789 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
3774 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 3790 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
3775 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 3791 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
3776 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 3792 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
3777 CHECK_EQ(0, elem_in0 - elem_start); 3793 CHECK_EQ(0, elem_in0 - elem_start);
3778 CHECK_EQ(kIntSize, elem_in1 - elem_start); 3794 CHECK_EQ(kIntSize, elem_in1 - elem_start);
3779 CHECK_EQ(2 * kIntSize, elem_out - elem_start); 3795 CHECK_EQ(2 * kIntSize, elem_out - elem_start);
3780 } 3796 }
3781 #endif 3797 #endif
3782 3798
3783 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. 3799 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12].
3784 __ add(r1, r1, Operand(r1, LSL, 1)); 3800 __ add(r1, r1, Operand(r1, LSL, 1));
3785 __ add(r0, r0, Operand(r1, LSL, 2)); 3801 __ add(cache_entry, cache_entry, Operand(r1, LSL, 2));
3786 // Check if cache matches: Double value is stored in uint32_t[2] array. 3802 // Check if cache matches: Double value is stored in uint32_t[2] array.
3787 __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit()); 3803 __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit());
3788 __ cmp(r2, r4); 3804 __ cmp(r2, r4);
3789 __ b(ne, &runtime_call); 3805 __ b(ne, &calculate);
3790 __ cmp(r3, r5); 3806 __ cmp(r3, r5);
3791 __ b(ne, &runtime_call); 3807 __ b(ne, &calculate);
3792 // Cache hit. Load result, pop argument and return. 3808 // Cache hit. Load result, cleanup and return.
3793 __ mov(r0, Operand(r6)); 3809 if (tagged) {
3794 __ pop(); 3810 // Pop input value from stack and load result into r0.
3811 __ pop();
3812 __ mov(r0, Operand(r6));
3813 } else {
3814 // Load result into d2.
3815 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
3816 }
3817 __ Ret();
3818 } // if (CpuFeatures::IsSupported(VFP3))
3819
3820 __ bind(&calculate);
3821 if (tagged) {
3822 __ bind(&invalid_cache);
3823 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
3824 } else {
3825 if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE();
3826 CpuFeatures::Scope scope(VFP3);
3827
3828 Label no_update;
3829 Label skip_cache;
3830 const Register heap_number_map = r5;
3831
3832 // Call C function to calculate the result and update the cache.
3833 // Register r0 holds precalculated cache entry address; preserve
3834 // it on the stack and pop it into register cache_entry after the
3835 // call.
3836 __ push(cache_entry);
3837 GenerateCallCFunction(masm, scratch0);
3838 __ GetCFunctionDoubleResult(d2);
3839
3840 // Try to update the cache. If we cannot allocate a
3841 // heap number, we return the result without updating.
3842 __ pop(cache_entry);
3843 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
3844 __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update);
3845 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset));
3846 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit());
3847 __ Ret();
3848
3849 __ bind(&invalid_cache);
3850 // The cache is invalid. Call runtime which will recreate the
3851 // cache.
3852 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex);
3853 __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache);
3854 __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
3855 __ EnterInternalFrame();
3856 __ push(r0);
3857 __ CallRuntime(RuntimeFunction(), 1);
3858 __ LeaveInternalFrame();
3859 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset));
3860 __ Ret();
3861
3862 __ bind(&skip_cache);
3863 // Call C function to calculate the result and answer directly
3864 // without updating the cache.
3865 GenerateCallCFunction(masm, scratch0);
3866 __ GetCFunctionDoubleResult(d2);
3867 __ bind(&no_update);
3868
3869 // We return the value in d2 without adding it to the cache, but
3870 // we cause a scavenging GC so that future allocations will succeed.
3871 __ EnterInternalFrame();
3872
3873 // Allocate an aligned object larger than a HeapNumber.
3874 ASSERT(4 * kPointerSize >= HeapNumber::kSize);
3875 __ mov(scratch0, Operand(4 * kPointerSize));
Søren Thygesen Gjesse 2011/03/04 07:44:18 Why not HeapNumber::kSize instead of 4 * kPointerS
3876 __ push(scratch0);
3877 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
3878 __ LeaveInternalFrame();
3795 __ Ret(); 3879 __ Ret();
3796 } 3880 }
3797
3798 __ bind(&runtime_call);
3799 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
3800 } 3881 }
3801 3882
3802 3883
3884 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm,
3885 Register scratch) {
3886 __ push(lr);
3887 __ PrepareCallCFunction(2, scratch);
3888 __ vmov(r0, r1, d2);
3889 switch (type_) {
3890 case TranscendentalCache::SIN:
3891 __ CallCFunction(ExternalReference::math_sin_double_function(), 2);
3892 break;
3893 case TranscendentalCache::COS:
3894 __ CallCFunction(ExternalReference::math_cos_double_function(), 2);
3895 break;
3896 case TranscendentalCache::LOG:
3897 __ CallCFunction(ExternalReference::math_log_double_function(), 2);
3898 break;
3899 default:
3900 UNIMPLEMENTED();
3901 break;
3902 }
3903 __ pop(lr);
3904 }
3905
3906
3803 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 3907 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
3804 switch (type_) { 3908 switch (type_) {
3805 // Add more cases when necessary. 3909 // Add more cases when necessary.
3806 case TranscendentalCache::SIN: return Runtime::kMath_sin; 3910 case TranscendentalCache::SIN: return Runtime::kMath_sin;
3807 case TranscendentalCache::COS: return Runtime::kMath_cos; 3911 case TranscendentalCache::COS: return Runtime::kMath_cos;
3808 case TranscendentalCache::LOG: return Runtime::kMath_log; 3912 case TranscendentalCache::LOG: return Runtime::kMath_log;
3809 default: 3913 default:
3810 UNIMPLEMENTED(); 3914 UNIMPLEMENTED();
3811 return Runtime::kAbort; 3915 return Runtime::kAbort;
3812 } 3916 }
(...skipping 2961 matching lines...) Expand 10 before | Expand all | Expand 10 after
6774 __ strb(untagged_value, MemOperand(external_pointer, untagged_key)); 6878 __ strb(untagged_value, MemOperand(external_pointer, untagged_key));
6775 __ Ret(); 6879 __ Ret();
6776 } 6880 }
6777 6881
6778 6882
6779 #undef __ 6883 #undef __
6780 6884
6781 } } // namespace v8::internal 6885 } } // namespace v8::internal
6782 6886
6783 #endif // V8_TARGET_ARCH_ARM 6887 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/code-stubs-arm.h ('k') | src/arm/codegen-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698