OLD | NEW |
---|---|
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 Loading... | |
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, ¬_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(¬_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, ¬_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(¬_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 Loading... | |
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 |
OLD | NEW |