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