| 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 2928 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2939 | 2939 |
| 2940 void MathPowStub::Generate(MacroAssembler* masm) { | 2940 void MathPowStub::Generate(MacroAssembler* masm) { |
| 2941 CpuFeatures::Scope use_sse2(SSE2); | 2941 CpuFeatures::Scope use_sse2(SSE2); |
| 2942 Factory* factory = masm->isolate()->factory(); | 2942 Factory* factory = masm->isolate()->factory(); |
| 2943 Label double_int_runtime, generic_runtime, done; | 2943 Label double_int_runtime, generic_runtime, done; |
| 2944 Label base_is_smi, unpack_exponent, exponent_not_smi, int_exponent; | 2944 Label base_is_smi, unpack_exponent, exponent_not_smi, int_exponent; |
| 2945 // Save 1 in xmm3 - we need this several times later on. | 2945 // Save 1 in xmm3 - we need this several times later on. |
| 2946 __ mov(ecx, Immediate(1)); | 2946 __ mov(ecx, Immediate(1)); |
| 2947 __ cvtsi2sd(xmm3, ecx); | 2947 __ cvtsi2sd(xmm3, ecx); |
| 2948 | 2948 |
| 2949 switch (exponent_type_) { | 2949 if (exponent_type_ == ON_STACK) { |
| 2950 case ON_STACK: | 2950 // The exponent (and base) are supplied as arguments on the stack. |
| 2951 // The exponent (and base) are supplied as arguments on the stack. | 2951 // This can only happen if the stub is called from non-optimized code. |
| 2952 // This can only happen if the stub is called from non-optimized code. | 2952 // Load input parameters from stack |
| 2953 // Load input parameters from stack | 2953 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2954 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2954 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 2955 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 2955 // edx: base (smi or heap number) |
| 2956 // edx: base (smi or heap number) | 2956 // eax: exponent (smi or heap number) |
| 2957 // eax: exponent (smi or heap number) | 2957 __ JumpIfSmi(edx, &base_is_smi, Label::kNear); |
| 2958 __ JumpIfSmi(edx, &base_is_smi, Label::kNear); | 2958 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2959 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2959 factory->heap_number_map()); |
| 2960 factory->heap_number_map()); | 2960 __ j(not_equal, &generic_runtime); |
| 2961 __ j(not_equal, &generic_runtime); | |
| 2962 | 2961 |
| 2963 // Check base for NaN or +/-Infinity | 2962 __ movdbl(xmm1, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 2964 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 2963 __ jmp(&unpack_exponent, Label::kNear); |
| 2965 __ and_(ecx, HeapNumber::kExponentMask); | |
| 2966 __ cmp(ecx, Immediate(HeapNumber::kExponentMask)); | |
| 2967 __ j(equal, &generic_runtime); | |
| 2968 __ movdbl(xmm1, FieldOperand(edx, HeapNumber::kValueOffset)); | |
| 2969 __ jmp(&unpack_exponent, Label::kNear); | |
| 2970 | 2964 |
| 2971 __ bind(&base_is_smi); | 2965 __ bind(&base_is_smi); |
| 2972 __ SmiUntag(edx); | 2966 __ SmiUntag(edx); |
| 2973 __ cvtsi2sd(xmm1, edx); | 2967 __ cvtsi2sd(xmm1, edx); |
| 2974 __ bind(&unpack_exponent); | 2968 __ bind(&unpack_exponent); |
| 2975 | 2969 |
| 2976 __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear); | 2970 __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear); |
| 2977 __ SmiUntag(eax); | 2971 __ SmiUntag(eax); |
| 2978 __ jmp(&int_exponent); | 2972 __ jmp(&int_exponent); |
| 2979 | 2973 |
| 2980 __ bind(&exponent_not_smi); | 2974 __ bind(&exponent_not_smi); |
| 2981 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 2975 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 2982 factory->heap_number_map()); | 2976 factory->heap_number_map()); |
| 2983 __ j(not_equal, &generic_runtime); | 2977 __ j(not_equal, &generic_runtime); |
| 2984 __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset)); | 2978 __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2985 break; | 2979 } else if (exponent_type_ == TAGGED) { |
| 2980 // xmm1: base as double |
| 2981 // eax: exponent (smi or heap number) |
| 2982 __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear); |
| 2983 __ SmiUntag(eax); |
| 2984 __ jmp(&int_exponent); |
| 2986 | 2985 |
| 2987 case TAGGED: | 2986 __ bind(&exponent_not_smi); |
| 2988 // xmm1: base as double | 2987 __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2989 // eax: exponent (smi or heap number) | |
| 2990 __ JumpIfNotSmi(eax, &exponent_not_smi, Label::kNear); | |
| 2991 __ SmiUntag(eax); | |
| 2992 __ jmp(&int_exponent); | |
| 2993 | |
| 2994 __ bind(&exponent_not_smi); | |
| 2995 __ movdbl(xmm2, FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 2996 // Fall through intended | |
| 2997 case INTEGER: | |
| 2998 // xmm1: base as double | |
| 2999 // eax: exponent as untagged integer | |
| 3000 case DOUBLE: | |
| 3001 // xmm1: base as double | |
| 3002 // xmm2: exponent as double | |
| 3003 // Check base in xmm1 for NaN or +/-Infinity | |
| 3004 const int kExponentShift = kBitsPerByte * | |
| 3005 (HeapNumber::kExponentOffset - HeapNumber::kMantissaOffset); | |
| 3006 __ movsd(xmm4, xmm1); | |
| 3007 __ psrlq(xmm4, kExponentShift); | |
| 3008 __ movd(ecx, xmm4); | |
| 3009 __ and_(ecx, HeapNumber::kExponentMask); | |
| 3010 __ cmp(ecx, Immediate(HeapNumber::kExponentMask)); | |
| 3011 __ j(equal, &generic_runtime); | |
| 3012 break; | |
| 3013 } | 2988 } |
| 3014 | 2989 |
| 3015 if (exponent_type_ != INTEGER) { | 2990 if (exponent_type_ != INTEGER) { |
| 3016 Label not_minus_half, fast_power; | 2991 Label fast_power; |
| 3017 // xmm1: base as double that is not +/- Infinity or NaN | 2992 // xmm1: base as double that is not +/- Infinity or NaN |
| 3018 // xmm2: exponent as double | 2993 // xmm2: exponent as double |
| 3019 // Detect integer exponents stored as double. | 2994 // Detect integer exponents stored as double. |
| 3020 __ cvttsd2si(eax, Operand(xmm2)); | 2995 __ cvttsd2si(eax, Operand(xmm2)); |
| 3021 // Skip to runtime if possibly NaN (indicated by the indefinite integer). | 2996 // Skip to runtime if possibly NaN (indicated by the indefinite integer). |
| 3022 __ cmp(eax, Immediate(0x80000000u)); | 2997 __ cmp(eax, Immediate(0x80000000u)); |
| 3023 __ j(equal, &generic_runtime); | 2998 __ j(equal, &generic_runtime); |
| 3024 __ cvtsi2sd(xmm4, eax); | 2999 __ cvtsi2sd(xmm4, eax); |
| 3025 __ ucomisd(xmm2, xmm4); | 3000 __ ucomisd(xmm2, xmm4); |
| 3026 __ j(equal, &int_exponent); | 3001 __ j(equal, &int_exponent); |
| 3027 | 3002 |
| 3028 if (exponent_type_ == ON_STACK) { | 3003 if (exponent_type_ == ON_STACK) { |
| 3029 // Detect square root case. Crankshaft detects constant +/-0.5 at | 3004 // Detect square root case. Crankshaft detects constant +/-0.5 at |
| 3030 // compile time and uses DoMathPowHalf instead. We then skip this check | 3005 // compile time and uses DoMathPowHalf instead. We then skip this check |
| 3031 // for non-constant cases of +/-0.5 as these hardly occur. | 3006 // for non-constant cases of +/-0.5 as these hardly occur. |
| 3007 Label continue_sqrt, continue_rsqrt, not_plus_half; |
| 3008 // Test for 0.5. |
| 3009 // Load xmm4 with 0.5. |
| 3010 __ mov(ecx, Immediate(0x3F000000u)); |
| 3011 __ movd(xmm4, ecx); |
| 3012 __ cvtss2sd(xmm4, xmm4); |
| 3013 // xmm3 now has 0.5. |
| 3014 __ ucomisd(xmm4, xmm2); |
| 3015 __ j(not_equal, ¬_plus_half, Label::kNear); |
| 3016 |
| 3017 // Calculates square root. Check for the special case of |
| 3018 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). |
| 3019 // According to IEEE-754, single-precision -Infinity has the highest |
| 3020 // 9 bits set and the lowest 23 bits cleared. |
| 3021 __ mov(ecx, 0xFF800000u); |
| 3022 __ movd(xmm4, ecx); |
| 3023 __ cvtss2sd(xmm4, xmm4); |
| 3024 __ ucomisd(xmm1, xmm4); |
| 3025 __ j(not_equal, &continue_sqrt, Label::kNear); |
| 3026 |
| 3027 // Set result to Infinity in the special case. |
| 3028 __ xorps(xmm3, xmm3); |
| 3029 __ subsd(xmm3, xmm4); |
| 3030 __ jmp(&done); |
| 3031 |
| 3032 __ bind(&continue_sqrt); |
| 3033 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. |
| 3034 __ xorps(xmm4, xmm4); |
| 3035 __ addsd(xmm4, xmm1); // Convert -0 to +0. |
| 3036 __ sqrtsd(xmm3, xmm4); |
| 3037 __ jmp(&done); |
| 3032 | 3038 |
| 3033 // Test for -0.5. | 3039 // Test for -0.5. |
| 3034 // Load xmm4 with -0.5. | 3040 __ bind(¬_plus_half); |
| 3035 __ mov(ecx, Immediate(0xBF000000u)); | 3041 // Load xmm2 with -0.5. |
| 3042 // Since xmm3 is 1 and xmm4 is 0.5 this is simply xmm4 - xmm3. |
| 3043 __ subsd(xmm4, xmm3); |
| 3044 // xmm2 now has -0.5. |
| 3045 __ ucomisd(xmm4, xmm2); |
| 3046 __ j(not_equal, &fast_power, Label::kNear); |
| 3047 |
| 3048 // Calculates reciprocal of square root. Check for the special case of |
| 3049 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). |
| 3050 // According to IEEE-754, single-precision -Infinity has the highest |
| 3051 // 9 bits set and the lowest 23 bits cleared. |
| 3052 __ mov(ecx, 0xFF800000u); |
| 3036 __ movd(xmm4, ecx); | 3053 __ movd(xmm4, ecx); |
| 3037 __ cvtss2sd(xmm4, xmm4); | 3054 __ cvtss2sd(xmm4, xmm4); |
| 3038 // xmm3 now has -0.5. | 3055 __ ucomisd(xmm1, xmm4); |
| 3039 __ ucomisd(xmm4, xmm2); | 3056 __ j(not_equal, &continue_rsqrt, Label::kNear); |
| 3040 __ j(not_equal, ¬_minus_half, Label::kNear); | |
| 3041 | 3057 |
| 3042 // Calculates reciprocal of square root.eax | 3058 // Set result to 0 in the special case. |
| 3059 __ xorps(xmm3, xmm3); |
| 3060 __ jmp(&done); |
| 3061 |
| 3062 __ bind(&continue_rsqrt); |
| 3043 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | 3063 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. |
| 3044 __ xorps(xmm2, xmm2); | 3064 __ xorps(xmm2, xmm2); |
| 3045 __ addsd(xmm2, xmm1); | 3065 __ addsd(xmm2, xmm1); // Convert -0 to +0. |
| 3046 __ sqrtsd(xmm2, xmm2); | 3066 __ sqrtsd(xmm2, xmm2); |
| 3047 __ divsd(xmm3, xmm2); | 3067 __ divsd(xmm3, xmm2); |
| 3048 __ jmp(&done); | 3068 __ jmp(&done); |
| 3049 | |
| 3050 // Test for 0.5. | |
| 3051 __ bind(¬_minus_half); | |
| 3052 // Load xmm2 with 0.5. | |
| 3053 // Since xmm3 is 1 and xmm4 is -0.5 this is simply xmm4 + xmm3. | |
| 3054 __ addsd(xmm4, xmm3); | |
| 3055 // xmm2 now has 0.5. | |
| 3056 __ ucomisd(xmm4, xmm2); | |
| 3057 __ j(not_equal, &fast_power, Label::kNear); | |
| 3058 // Calculates square root. | |
| 3059 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | |
| 3060 __ xorps(xmm4, xmm4); | |
| 3061 __ addsd(xmm4, xmm1); | |
| 3062 __ sqrtsd(xmm3, xmm4); | |
| 3063 __ jmp(&done); | |
| 3064 } | 3069 } |
| 3065 | 3070 |
| 3066 // Using FPU instructions to calculate power. | 3071 // Using FPU instructions to calculate power. |
| 3067 Label fast_power_failed; | 3072 Label fast_power_failed; |
| 3068 __ bind(&fast_power); | 3073 __ bind(&fast_power); |
| 3069 __ fnclex(); // Clear flags to catch exceptions later. | 3074 __ fnclex(); // Clear flags to catch exceptions later. |
| 3070 // Transfer (B)ase and (E)xponent onto the FPU register stack. | 3075 // Transfer (B)ase and (E)xponent onto the FPU register stack. |
| 3071 __ sub(esp, Immediate(kDoubleSize)); | 3076 __ sub(esp, Immediate(kDoubleSize)); |
| 3072 __ movdbl(Operand(esp, 0), xmm2); | 3077 __ movdbl(Operand(esp, 0), xmm2); |
| 3073 __ fld_d(Operand(esp, 0)); // E | 3078 __ fld_d(Operand(esp, 0)); // E |
| (...skipping 4205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7279 false); | 7284 false); |
| 7280 __ pop(edx); | 7285 __ pop(edx); |
| 7281 __ ret(0); | 7286 __ ret(0); |
| 7282 } | 7287 } |
| 7283 | 7288 |
| 7284 #undef __ | 7289 #undef __ |
| 7285 | 7290 |
| 7286 } } // namespace v8::internal | 7291 } } // namespace v8::internal |
| 7287 | 7292 |
| 7288 #endif // V8_TARGET_ARCH_IA32 | 7293 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |