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

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: added new instructions to disassembler. 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, double_double_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, &double_double_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, &double_double_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 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
2982 factory->heap_number_map());
2983 __ j(not_equal, &double_double_runtime);
2984 __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset));
2985 break;
2986 case INTEGER:
2987 // xmm1: base as double
2988 // eax: exponent as untagged integer
2989 case DOUBLE:
2990 // xmm1: base as double
2991 // xmm2: exponent as double
2992 // Check base for NaN or +/-Infinity
2993 if (CpuFeatures::IsSupported(SSE4_1)) {
2994 __ extractps(ecx, xmm1, 4 * kBitsPerByte);
2995 } else {
2996 __ movsd(xmm4, xmm1);
2997 __ psrlq(xmm4, 4 * kBitsPerByte);
2998 __ movd(ecx, xmm4);
2999 }
3000 __ and_(ecx, HeapNumber::kExponentMask);
3001 __ cmp(ecx, Immediate(HeapNumber::kExponentMask));
3002 __ j(greater_equal, &double_double_runtime);
3003 break;
3004 default:
3005 UNREACHABLE();
3006 }
3007 if (exponent_type_ != INTEGER) {
3008 Label not_minus_half, fast_power;
3009 // xmm1: base as double that is not +/- Infinity or NaN
3010 // xmm2: exponent as double
3011 // Detect integer exponents stored as double.
3012 __ cvttsd2si(eax, Operand(xmm2));
3013 __ cmp(eax, Immediate(0x80000000)); // Skip to runtime if possibly NaN.
3014 __ j(equal, &double_double_runtime);
3015 __ cvtsi2sd(xmm4, eax);
3016 __ ucomisd(xmm2, xmm4);
3017 __ j(equal, &int_exponent);
3018
3019 // Detect square root case.
3020 // Test for -0.5.
3021 // Load xmm4 with -0.5.
3022 __ mov(ecx, Immediate(0xBF000000));
3023 __ movd(xmm4, ecx);
3024 __ cvtss2sd(xmm4, xmm4);
3025 // xmm3 now has -0.5.
3026 __ ucomisd(xmm4, xmm2);
3027 __ j(not_equal, &not_minus_half, Label::kNear);
3028
3029 // Calculates reciprocal of square root.eax
3030 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3031 __ xorps(xmm2, xmm2);
3032 __ addsd(xmm2, xmm1);
3033 __ sqrtsd(xmm2, xmm2);
3034 __ divsd(xmm3, xmm2);
3035 __ jmp(&done);
3036 __ extractps(ecx, xmm1, 4 * kBitsPerByte);
3037 // Test for 0.5.
3038 __ bind(&not_minus_half);
3039 // Load xmm2 with 0.5.
3040 // Since xmm3 is 1 and xmm4 is -0.5 this is simply xmm4 + xmm3.
3041 __ addsd(xmm4, xmm3);
3042 // xmm2 now has 0.5.
3043 __ ucomisd(xmm4, xmm2);
3044 __ j(not_equal, &fast_power, Label::kNear);
3045 // Calculates square root.
3046 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
3047 __ xorps(xmm4, xmm4);
3048 __ addsd(xmm4, xmm1);
3049 __ sqrtsd(xmm3, xmm4);
3050 __ jmp(&done);
3051
3052 // Using FPU instructions to calculate power.
3053 Label fast_power_failed;
3054 __ bind(&fast_power);
3055 // Transfer (B)ase and (E)xponent onto the FPU register stack.
3056 __ sub(esp, Immediate(kDoubleSize));
3057 __ movdbl(Operand(esp, 0), xmm2);
3058 __ fld_d(Operand(esp, 0)); // E
3059 __ movdbl(Operand(esp, 0), xmm1);
3060 __ fld_d(Operand(esp, 0)); // B, E
3061
3062 // Exponent is in st(1) and base is in st(0)
3063 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
3064 // FYL2X calculates st(1) * log2(st(0))
3065 __ fyl2x(); // X
3066 __ fld(0); // X, X
3067 __ frndint(); // rnd(X), X
3068 __ fsub(1); // rnd(X), X-rnd(X)
3069 __ fxch(1); // X - rnd(X), rnd(X)
3070 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
3071 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
3072 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
3073 __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
3074 // FSCALE calculates st(0) * 2^st(1)
3075 __ fscale(); // 2^X, rnd(X)
3076 __ fstp(1);
3077 // Bail out to runtime in case of exceptions in the status word.
3078 __ fnstsw_ax();
Bill Hesse 2011/12/01 13:54:24 Where does the status word get cleared? How do we
3079 __ test_b(eax, 0x5F);
3080 __ j(not_zero, &fast_power_failed, Label::kNear);
3081 __ fstp_d(Operand(esp, 0));
3082 __ movdbl(xmm3, Operand(esp, 0));
3083 __ add(esp, Immediate(kDoubleSize));
3084 __ jmp(&done);
3085
3086 __ bind(&fast_power_failed);
3087 __ fninit();
3088 __ add(esp, Immediate(kDoubleSize));
3089 __ jmp(&double_double_runtime);
3090 }
3091
3092 // Calculate power with integer exponent.
3093 __ bind(&int_exponent);
3094 // xmm0: base as double that is not +/- Infinity or NaN
3095 // eax: exponent as untagged integer
2982 // Save exponent in base as we need to check if exponent is negative later. 3096 // 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. 3097 // We know that base and exponent are in different registers.
2984 __ mov(edx, eax); 3098 __ mov(ecx, eax); // Back up exponent.
3099 __ movsd(xmm4, xmm1); // Back up base.
3100 __ movsd(xmm2, xmm3); // Load xmm2 with 1.
2985 3101
2986 // Get absolute value of exponent. 3102 // Get absolute value of exponent.
2987 Label no_neg; 3103 Label no_neg, while_true, no_multiply;
2988 __ cmp(eax, 0); 3104 __ cmp(eax, 0);
2989 __ j(greater_equal, &no_neg, Label::kNear); 3105 __ j(greater_equal, &no_neg, Label::kNear);
2990 __ neg(eax); 3106 __ neg(eax);
2991 __ bind(&no_neg); 3107 __ bind(&no_neg);
2992 3108
2993 // Load xmm1 with 1.
2994 __ movsd(xmm1, xmm3);
2995 Label while_true;
2996 Label no_multiply;
2997
2998 __ bind(&while_true); 3109 __ bind(&while_true);
2999 __ shr(eax, 1); 3110 __ shr(eax, 1);
3000 __ j(not_carry, &no_multiply, Label::kNear); 3111 __ j(not_carry, &no_multiply, Label::kNear);
3001 __ mulsd(xmm1, xmm0); 3112 __ mulsd(xmm3, xmm1);
3002 __ bind(&no_multiply); 3113 __ bind(&no_multiply);
3003 __ mulsd(xmm0, xmm0); 3114 __ mulsd(xmm1, xmm1);
3004 __ j(not_zero, &while_true); 3115 __ j(not_zero, &while_true);
3005 3116
3006 // base has the original value of the exponent - if the exponent is 3117 // base has the original value of the exponent - if the exponent is
3007 // negative return 1/result. 3118 // negative return 1/result.
3008 __ test(edx, edx); 3119 __ test(ecx, ecx);
3009 __ j(positive, &allocate_return); 3120 __ j(positive, &done);
3010 // Special case if xmm1 has reached infinity. 3121 // Special case if xmm3 has reached infinity.
3011 __ mov(ecx, Immediate(0x7FB00000)); 3122 __ mov(eax, Immediate(0x7F800000));
3012 __ movd(xmm0, ecx); 3123 __ movd(xmm1, eax);
3013 __ cvtss2sd(xmm0, xmm0); 3124 __ cvtss2sd(xmm1, xmm1);
3014 __ ucomisd(xmm0, xmm1); 3125 __ ucomisd(xmm1, xmm3);
3015 __ j(equal, &call_runtime); 3126 __ j(equal, &double_int_runtime);
3016 __ divsd(xmm3, xmm1); 3127 __ divsd(xmm2, xmm3);
3017 __ movsd(xmm1, xmm3); 3128 __ movsd(xmm3, xmm2);
3018 __ jmp(&allocate_return); 3129
3019 3130 // Returning or bailing out.
3020 // exponent (or both) is a heapnumber - no matter what we should now work 3131 if (exponent_type_ == ON_STACK) {
3021 // on doubles. 3132 // We expect the result as heap number in eax.
3022 __ bind(&exponent_nonsmi); 3133 __ bind(&done);
3023 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 3134 // xmm1: result
3024 factory->heap_number_map()); 3135 __ AllocateHeapNumber(eax, ecx, edx, &double_double_runtime);
3025 __ j(not_equal, &call_runtime); 3136 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm3);
3026 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 3137 __ ret(2 * kPointerSize);
3027 // Test if exponent is nan. 3138
3028 __ ucomisd(xmm1, xmm1); 3139 // The arguments are still on the stack.
3029 __ j(parity_even, &call_runtime); 3140 __ bind(&double_double_runtime);
3030 3141 __ bind(&double_int_runtime);
3031 Label base_not_smi; 3142 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3032 Label handle_special_cases; 3143 } else {
3033 __ JumpIfNotSmi(edx, &base_not_smi, Label::kNear); 3144 __ jmp(&done);
3034 __ SmiUntag(edx); 3145
3035 __ cvtsi2sd(xmm0, edx); 3146 Label return_from_runtime;
3036 __ jmp(&handle_special_cases, Label::kNear); 3147 StubRuntimeCallHelper callhelper;
3037 3148 __ bind(&double_double_runtime);
3038 __ bind(&base_not_smi); 3149 // xmm1: base
3039 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 3150 // xmm2: exponent
3040 factory->heap_number_map()); 3151 {
3041 __ j(not_equal, &call_runtime); 3152 AllowExternalCallThatCantCauseGC scope(masm);
3042 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 3153 __ PrepareCallCFunction(4, eax);
3043 __ and_(ecx, HeapNumber::kExponentMask); 3154 __ movdbl(Operand(esp, 0 * kDoubleSize), xmm1);
3044 __ cmp(ecx, Immediate(HeapNumber::kExponentMask)); 3155 __ movdbl(Operand(esp, 1 * kDoubleSize), xmm2);
3045 // base is NaN or +/-Infinity 3156 __ CallCFunction(
3046 __ j(greater_equal, &call_runtime); 3157 ExternalReference::power_double_double_function(masm->isolate()), 4);
3047 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 3158 }
3048 3159 __ jmp(&return_from_runtime, Label::kNear);
3049 // base is in xmm0 and exponent is in xmm1. 3160
3050 __ bind(&handle_special_cases); 3161 __ bind(&double_int_runtime);
3051 Label not_minus_half; 3162 // xmm4: base
3052 // Test for -0.5. 3163 // ecx: exponent
3053 // Load xmm2 with -0.5. 3164 {
3054 __ mov(ecx, Immediate(0xBF000000)); 3165 __ PrepareCallCFunction(4, eax);
3055 __ movd(xmm2, ecx); 3166 __ movdbl(Operand(esp, 0 * kDoubleSize), xmm4);
3056 __ cvtss2sd(xmm2, xmm2); 3167 __ mov(Operand(esp, 1 * kDoubleSize), ecx);
3057 // xmm2 now has -0.5. 3168 AllowExternalCallThatCantCauseGC scope(masm);
3058 __ ucomisd(xmm2, xmm1); 3169 __ CallCFunction(
3059 __ j(not_equal, &not_minus_half, Label::kNear); 3170 ExternalReference::power_double_int_function(masm->isolate()), 4);
3060 3171 }
3061 // Calculates reciprocal of square root. 3172
3062 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 3173 __ bind(&return_from_runtime);
3063 __ xorps(xmm1, xmm1); 3174 // Return value is in st(0) on ia32.
3064 __ addsd(xmm1, xmm0); 3175 // Store it into the (fixed) result register.
3065 __ sqrtsd(xmm1, xmm1); 3176 __ sub(esp, Immediate(kDoubleSize));
3066 __ divsd(xmm3, xmm1); 3177 __ fstp_d(Operand(esp, 0));
3067 __ movsd(xmm1, xmm3); 3178 __ movdbl(xmm3, Operand(esp, 0));
3068 __ jmp(&allocate_return); 3179 __ add(esp, Immediate(kDoubleSize));
3069 3180
3070 // Test for 0.5. 3181 // We expect the result in xmm3.
3071 __ bind(&not_minus_half); 3182 __ bind(&done);
3072 // Load xmm2 with 0.5. 3183 __ ret(0);
3073 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. 3184 }
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 } 3185 }
3093 3186
3094 3187
3095 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 3188 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
3096 // The key is in edx and the parameter count is in eax. 3189 // The key is in edx and the parameter count is in eax.
3097 3190
3098 // The displacement is used for skipping the frame pointer on the 3191 // The displacement is used for skipping the frame pointer on the
3099 // stack. It is the offset of the last parameter (if any) relative 3192 // stack. It is the offset of the last parameter (if any) relative
3100 // to the frame pointer. 3193 // to the frame pointer.
3101 static const int kDisplacement = 1 * kPointerSize; 3194 static const int kDisplacement = 1 * kPointerSize;
(...skipping 4069 matching lines...) Expand 10 before | Expand all | Expand 10 after
7171 false); 7264 false);
7172 __ pop(edx); 7265 __ pop(edx);
7173 __ ret(0); 7266 __ ret(0);
7174 } 7267 }
7175 7268
7176 #undef __ 7269 #undef __
7177 7270
7178 } } // namespace v8::internal 7271 } } // namespace v8::internal
7179 7272
7180 #endif // V8_TARGET_ARCH_IA32 7273 #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