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

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

Issue 8749002: Implement Math.pow using FPU instructions and inline it in crankshaft (ia32). (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Also do NaN/infinity check on base for TAGGED case. Created 9 years 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/ia32/assembler-ia32.cc ('k') | src/ia32/disasm-ia32.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 2920 matching lines...) Expand 10 before | Expand all | Expand 10 after
2931 } 2931 }
2932 2932
2933 2933
2934 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, 2934 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm,
2935 Label* non_int32) { 2935 Label* non_int32) {
2936 return; 2936 return;
2937 } 2937 }
2938 2938
2939 2939
2940 void MathPowStub::Generate(MacroAssembler* masm) { 2940 void MathPowStub::Generate(MacroAssembler* masm) {
2941 // Registers are used as follows:
2942 // edx = base
2943 // eax = exponent
2944 // ecx = temporary, result
2945
2946 CpuFeatures::Scope use_sse2(SSE2); 2941 CpuFeatures::Scope use_sse2(SSE2);
2947 Label allocate_return, call_runtime; 2942 Factory* factory = masm->isolate()->factory();
2948 2943 Label double_int_runtime, generic_runtime, done;
2949 // Load input parameters. 2944 Label base_is_smi, unpack_exponent, exponent_not_smi, int_exponent;
2950 __ mov(edx, Operand(esp, 2 * kPointerSize));
2951 __ mov(eax, Operand(esp, 1 * kPointerSize));
2952
2953 // Save 1 in xmm3 - we need this several times later on. 2945 // Save 1 in xmm3 - we need this several times later on.
2954 __ mov(ecx, Immediate(1)); 2946 __ mov(ecx, Immediate(1));
2955 __ cvtsi2sd(xmm3, ecx); 2947 __ cvtsi2sd(xmm3, ecx);
2956 2948
2957 Label exponent_nonsmi; 2949 switch (exponent_type_) {
2958 Label base_nonsmi; 2950 case ON_STACK:
2959 // If the exponent is a heap number go to that specific case. 2951 // Load input parameters from stack
2960 __ JumpIfNotSmi(eax, &exponent_nonsmi); 2952 __ mov(edx, Operand(esp, 2 * kPointerSize));
2961 __ JumpIfNotSmi(edx, &base_nonsmi); 2953 __ mov(eax, Operand(esp, 1 * kPointerSize));
2962 2954 // edx: base (smi or heap number)
2963 // Optimized version when both exponent and base are smis. 2955 // eax: exponent (smi or heap number)
2964 Label powi; 2956 __ JumpIfSmi(edx, &base_is_smi, Label::kNear);
2965 __ SmiUntag(edx); 2957 __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
2966 __ cvtsi2sd(xmm0, edx); 2958 factory->heap_number_map());
2967 __ jmp(&powi); 2959 __ j(not_equal, &generic_runtime);
2968 // exponent is smi and base is a heapnumber. 2960
2969 __ bind(&base_nonsmi); 2961 // Check base for NaN or +/-Infinity
2970 Factory* factory = masm->isolate()->factory(); 2962 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
2971 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 2963 __ and_(ecx, HeapNumber::kExponentMask);
2972 factory->heap_number_map()); 2964 __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
2973 __ j(not_equal, &call_runtime); 2965 __ j(greater_equal, &generic_runtime);
2974 2966 __ movdbl(xmm1, FieldOperand(edx, HeapNumber::kValueOffset));
2975 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2967
2976 2968 __ jmp(&unpack_exponent, Label::kNear);
2977 // Optimized version of pow if exponent is a smi. 2969 __ bind(&base_is_smi);
2978 // xmm0 contains the base. 2970 __ SmiUntag(edx);
2979 __ bind(&powi); 2971 __ cvtsi2sd(xmm1, edx);
2980 __ SmiUntag(eax); 2972 __ bind(&unpack_exponent);
2981 2973 // Fall through is intended.
2974 case TAGGED:
2975 // xmm1: base as double
2976 // eax: exponent (smi or heap number)
2977 __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear);
2978 __ SmiUntag(eax);
2979 __ jmp(&int_exponent);
2980 __ bind(&exponent_not_smi);
2981 if (exponent_type_ == ON_STACK) {
2982 // Heap number check not necessary in optimized code as we will have
2983 // already deoptimized if eax was neither smi nor heap number.
2984 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
2985 factory->heap_number_map());
2986 __ j(not_equal, &generic_runtime);
2987 }
2988 __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset));
2989 break;
2990 case INTEGER:
2991 // xmm1: base as double
2992 // eax: exponent as untagged integer
2993 case DOUBLE:
2994 // xmm1: base as double
2995 // xmm2: exponent as double
2996 break;
2997 default:
2998 UNREACHABLE();
ulan 2011/12/01 18:11:26 Since you listed all the cases above, the default
2999 }
3000
3001 if (exponent_type_ != ON_STACK) {
3002 // Check base in xmm1 for NaN or +/-Infinity
3003 if (CpuFeatures::IsSupported(SSE4_1)) {
3004 __ extractps(ecx, xmm1, 4 * kBitsPerByte);
3005 } else {
3006 __ movsd(xmm4, xmm1);
3007 __ psrlq(xmm4, 4 * kBitsPerByte);
3008 __ movd(ecx, xmm4);
3009 }
3010 __ and_(ecx, HeapNumber::kExponentMask);
3011 __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
3012 __ j(greater_equal, &generic_runtime);
3013 }
3014
3015 if (exponent_type_ != INTEGER) {
3016 Label not_minus_half, fast_power;
3017 // xmm1: base as double that is not +/- Infinity or NaN
3018 // xmm2: exponent as double
3019 // Detect integer exponents stored as double.
3020 __ cvttsd2si(eax, Operand(xmm2));
3021 __ cmp(eax, Immediate(0x80000000)); // Skip to runtime if possibly NaN.
3022 __ j(equal, &generic_runtime);
3023 __ cvtsi2sd(xmm4, eax);
3024 __ ucomisd(xmm2, xmm4);
3025 __ j(equal, &int_exponent);
3026
3027 // Detect square root case.
3028 // Test for -0.5.
3029 // Load xmm4 with -0.5.
3030 __ mov(ecx, Immediate(0xBF000000));
3031 __ movd(xmm4, ecx);
3032 __ cvtss2sd(xmm4, xmm4);
3033 // xmm3 now has -0.5.
3034 __ ucomisd(xmm4, xmm2);
3035 __ j(not_equal, &not_minus_half, Label::kNear);
3036
3037 // Calculates reciprocal of square root.eax
3038 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3039 __ xorps(xmm2, xmm2);
3040 __ addsd(xmm2, xmm1);
3041 __ sqrtsd(xmm2, xmm2);
3042 __ divsd(xmm3, xmm2);
3043 __ jmp(&done);
3044 __ extractps(ecx, xmm1, 4 * kBitsPerByte);
3045 // Test for 0.5.
3046 __ bind(&not_minus_half);
3047 // Load xmm2 with 0.5.
3048 // Since xmm3 is 1 and xmm4 is -0.5 this is simply xmm4 + xmm3.
3049 __ addsd(xmm4, xmm3);
3050 // xmm2 now has 0.5.
3051 __ ucomisd(xmm4, xmm2);
3052 __ j(not_equal, &fast_power, Label::kNear);
3053 // Calculates square root.
3054 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3055 __ xorps(xmm4, xmm4);
3056 __ addsd(xmm4, xmm1);
3057 __ sqrtsd(xmm3, xmm4);
3058 __ jmp(&done);
3059
3060 // Using FPU instructions to calculate power.
3061 Label fast_power_failed;
3062 __ bind(&fast_power);
3063 __ fnclex(); // Clear flags to catch exceptions later.
3064 // Transfer (B)ase and (E)xponent onto the FPU register stack.
3065 __ sub(esp, Immediate(kDoubleSize));
3066 __ movdbl(Operand(esp, 0), xmm2);
3067 __ fld_d(Operand(esp, 0)); // E
3068 __ movdbl(Operand(esp, 0), xmm1);
3069 __ fld_d(Operand(esp, 0)); // B, E
3070
3071 // Exponent is in st(1) and base is in st(0)
3072 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
3073 // FYL2X calculates st(1) * log2(st(0))
3074 __ fyl2x(); // X
3075 __ fld(0); // X, X
3076 __ frndint(); // rnd(X), X
3077 __ fsub(1); // rnd(X), X-rnd(X)
3078 __ fxch(1); // X - rnd(X), rnd(X)
3079 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
3080 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
3081 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
3082 __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
3083 // FSCALE calculates st(0) * 2^st(1)
3084 __ fscale(); // 2^X, rnd(X)
3085 __ fstp(1);
3086 // Bail out to runtime in case of exceptions in the status word.
3087 __ fnstsw_ax();
3088 __ test_b(eax, 0x5F); // We check for all but precision exception.
3089 __ j(not_zero, &fast_power_failed, Label::kNear);
3090 __ fstp_d(Operand(esp, 0));
3091 __ movdbl(xmm3, Operand(esp, 0));
3092 __ add(esp, Immediate(kDoubleSize));
3093 __ jmp(&done);
3094
3095 __ bind(&fast_power_failed);
3096 __ fninit();
3097 __ add(esp, Immediate(kDoubleSize));
3098 __ jmp(&generic_runtime);
3099 }
3100
3101 // Calculate power with integer exponent.
3102 __ bind(&int_exponent);
3103 // xmm1: base as double that is not +/- Infinity or NaN
3104 // eax: exponent as untagged integer
2982 // Save exponent in base as we need to check if exponent is negative later. 3105 // Save exponent in base as we need to check if exponent is negative later.
2983 // We know that base and exponent are in different registers. 3106 // We know that base and exponent are in different registers.
2984 __ mov(edx, eax); 3107 __ mov(ecx, eax); // Back up exponent.
3108 __ movsd(xmm4, xmm1); // Back up base.
3109 __ movsd(xmm2, xmm3); // Load xmm2 with 1.
2985 3110
2986 // Get absolute value of exponent. 3111 // Get absolute value of exponent.
2987 Label no_neg; 3112 Label no_neg, while_true, no_multiply;
2988 __ cmp(eax, 0); 3113 __ cmp(eax, 0);
2989 __ j(greater_equal, &no_neg, Label::kNear); 3114 __ j(greater_equal, &no_neg, Label::kNear);
2990 __ neg(eax); 3115 __ neg(eax);
2991 __ bind(&no_neg); 3116 __ bind(&no_neg);
2992 3117
2993 // Load xmm1 with 1.
2994 __ movsd(xmm1, xmm3);
2995 Label while_true;
2996 Label no_multiply;
2997
2998 __ bind(&while_true); 3118 __ bind(&while_true);
2999 __ shr(eax, 1); 3119 __ shr(eax, 1);
3000 __ j(not_carry, &no_multiply, Label::kNear); 3120 __ j(not_carry, &no_multiply, Label::kNear);
3001 __ mulsd(xmm1, xmm0); 3121 __ mulsd(xmm3, xmm1);
3002 __ bind(&no_multiply); 3122 __ bind(&no_multiply);
3003 __ mulsd(xmm0, xmm0); 3123 __ mulsd(xmm1, xmm1);
3004 __ j(not_zero, &while_true); 3124 __ j(not_zero, &while_true);
3005 3125
3006 // base has the original value of the exponent - if the exponent is 3126 // base has the original value of the exponent - if the exponent is
3007 // negative return 1/result. 3127 // negative return 1/result.
3008 __ test(edx, edx); 3128 __ test(ecx, ecx);
3009 __ j(positive, &allocate_return); 3129 __ j(positive, &done);
3010 // Special case if xmm1 has reached infinity. 3130 __ divsd(xmm2, xmm3);
3011 __ mov(ecx, Immediate(0x7FB00000)); 3131 __ movsd(xmm3, xmm2);
3012 __ movd(xmm0, ecx); 3132 // Test whether result is zero. Bail out to check for subnormal result.
3013 __ cvtss2sd(xmm0, xmm0); 3133 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
3014 __ ucomisd(xmm0, xmm1); 3134 __ xorps(xmm2, xmm2);
3015 __ j(equal, &call_runtime); 3135 __ ucomisd(xmm2, xmm3);
3016 __ divsd(xmm3, xmm1); 3136 __ j(equal, &double_int_runtime);
3017 __ movsd(xmm1, xmm3); 3137
3018 __ jmp(&allocate_return); 3138 // Returning or bailing out.
3019 3139 if (exponent_type_ == ON_STACK) {
3020 // exponent (or both) is a heapnumber - no matter what we should now work 3140 // We expect the result as heap number in eax.
3021 // on doubles. 3141 __ bind(&done);
3022 __ bind(&exponent_nonsmi); 3142 // xmm1: result
3023 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 3143 __ AllocateHeapNumber(eax, ecx, edx, &generic_runtime);
3024 factory->heap_number_map()); 3144 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm3);
3025 __ j(not_equal, &call_runtime); 3145 __ ret(2 * kPointerSize);
3026 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 3146
3027 // Test if exponent is nan. 3147 // The arguments are still on the stack.
3028 __ ucomisd(xmm1, xmm1); 3148 __ bind(&generic_runtime);
3029 __ j(parity_even, &call_runtime); 3149 __ bind(&double_int_runtime);
3030 3150 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3031 Label base_not_smi; 3151 } else {
3032 Label handle_special_cases; 3152 __ jmp(&done);
3033 __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); 3153
3034 __ SmiUntag(edx); 3154 Label return_from_runtime;
3035 __ cvtsi2sd(xmm0, edx); 3155 StubRuntimeCallHelper callhelper;
3036 __ jmp(&handle_special_cases, Label::kNear); 3156 __ bind(&generic_runtime);
3037 3157 // xmm1: base
3038 __ bind(&base_not_smi); 3158 // xmm2: exponent
3039 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 3159 {
3040 factory->heap_number_map()); 3160 AllowExternalCallThatCantCauseGC scope(masm);
3041 __ j(not_equal, &call_runtime); 3161 __ PrepareCallCFunction(4, eax);
3042 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 3162 __ movdbl(Operand(esp, 0 * kDoubleSize), xmm1);
3043 __ and_(ecx, HeapNumber::kExponentMask); 3163 __ movdbl(Operand(esp, 1 * kDoubleSize), xmm2);
3044 __ cmp(ecx, Immediate(HeapNumber::kExponentMask)); 3164 __ CallCFunction(
3045 // base is NaN or +/-Infinity 3165 ExternalReference::power_double_double_function(masm->isolate()), 4);
3046 __ j(greater_equal, &call_runtime); 3166 }
3047 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 3167 __ jmp(&return_from_runtime, Label::kNear);
3048 3168
3049 // base is in xmm0 and exponent is in xmm1. 3169 __ bind(&double_int_runtime);
3050 __ bind(&handle_special_cases); 3170 // xmm4: base
3051 Label not_minus_half; 3171 // ecx: exponent
3052 // Test for -0.5. 3172 {
3053 // Load xmm2 with -0.5. 3173 __ PrepareCallCFunction(4, eax);
3054 __ mov(ecx, Immediate(0xBF000000)); 3174 __ movdbl(Operand(esp, 0 * kDoubleSize), xmm4);
3055 __ movd(xmm2, ecx); 3175 __ mov(Operand(esp, 1 * kDoubleSize), ecx);
3056 __ cvtss2sd(xmm2, xmm2); 3176 AllowExternalCallThatCantCauseGC scope(masm);
3057 // xmm2 now has -0.5. 3177 __ CallCFunction(
3058 __ ucomisd(xmm2, xmm1); 3178 ExternalReference::power_double_int_function(masm->isolate()), 4);
3059 __ j(not_equal, &not_minus_half, Label::kNear); 3179 }
3060 3180
3061 // Calculates reciprocal of square root. 3181 __ bind(&return_from_runtime);
3062 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 3182 // Return value is in st(0) on ia32.
3063 __ xorps(xmm1, xmm1); 3183 // Store it into the (fixed) result register.
3064 __ addsd(xmm1, xmm0); 3184 __ sub(esp, Immediate(kDoubleSize));
3065 __ sqrtsd(xmm1, xmm1); 3185 __ fstp_d(Operand(esp, 0));
3066 __ divsd(xmm3, xmm1); 3186 __ movdbl(xmm3, Operand(esp, 0));
3067 __ movsd(xmm1, xmm3); 3187 __ add(esp, Immediate(kDoubleSize));
3068 __ jmp(&allocate_return); 3188
3069 3189 // We expect the result in xmm3.
3070 // Test for 0.5. 3190 __ bind(&done);
3071 __ bind(&not_minus_half); 3191 __ ret(0);
3072 // Load xmm2 with 0.5. 3192 }
3073 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
3074 __ addsd(xmm2, xmm3);
3075 // xmm2 now has 0.5.
3076 __ ucomisd(xmm2, xmm1);
3077 __ j(not_equal, &call_runtime);
3078 // Calculates square root.
3079 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3080 __ xorps(xmm1, xmm1);
3081 __ addsd(xmm1, xmm0);
3082 __ sqrtsd(xmm1, xmm1);
3083
3084 __ bind(&allocate_return);
3085 __ AllocateHeapNumber(ecx, eax, edx, &call_runtime);
3086 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm1);
3087 __ mov(eax, ecx);
3088 __ ret(2 * kPointerSize);
3089
3090 __ bind(&call_runtime);
3091 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3092 } 3193 }
3093 3194
3094 3195
3095 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 3196 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
3096 // The key is in edx and the parameter count is in eax. 3197 // The key is in edx and the parameter count is in eax.
3097 3198
3098 // The displacement is used for skipping the frame pointer on the 3199 // The displacement is used for skipping the frame pointer on the
3099 // stack. It is the offset of the last parameter (if any) relative 3200 // stack. It is the offset of the last parameter (if any) relative
3100 // to the frame pointer. 3201 // to the frame pointer.
3101 static const int kDisplacement = 1 * kPointerSize; 3202 static const int kDisplacement = 1 * kPointerSize;
(...skipping 4069 matching lines...) Expand 10 before | Expand all | Expand 10 after
7171 false); 7272 false);
7172 __ pop(edx); 7273 __ pop(edx);
7173 __ ret(0); 7274 __ ret(0);
7174 } 7275 }
7175 7276
7176 #undef __ 7277 #undef __
7177 7278
7178 } } // namespace v8::internal 7279 } } // namespace v8::internal
7179 7280
7180 #endif // V8_TARGET_ARCH_IA32 7281 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/assembler-ia32.cc ('k') | src/ia32/disasm-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698