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

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

Issue 8821019: Porting Math.pow changes to x64. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: . 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
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 1973 matching lines...) Expand 10 before | Expand all | Expand 10 after
1984 __ Integer32ToSmi(second, smi_result); 1984 __ Integer32ToSmi(second, smi_result);
1985 if (on_success != NULL) { 1985 if (on_success != NULL) {
1986 __ jmp(on_success); 1986 __ jmp(on_success);
1987 } else { 1987 } else {
1988 __ bind(&done); 1988 __ bind(&done);
1989 } 1989 }
1990 } 1990 }
1991 1991
1992 1992
1993 void MathPowStub::Generate(MacroAssembler* masm) { 1993 void MathPowStub::Generate(MacroAssembler* masm) {
1994 // Registers are used as follows: 1994 // Choose register conforming to calling convention (when bailing out).
1995 // rdx = base 1995 #ifdef _WIN64
1996 // rax = exponent 1996 const Register exponent = rdx;
1997 // rcx = temporary, result 1997 #else
1998 1998 const Register exponent = rdi;
1999 Label allocate_return, call_runtime; 1999 #endif
2000 2000 const Register base = rax;
2001 // Load input parameters. 2001 const Register scratch = rcx;
2002 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); 2002 const XMMRegister double_result = xmm3;
2003 __ movq(rax, Operand(rsp, 1 * kPointerSize)); 2003 const XMMRegister double_base = xmm2;
2004 2004 const XMMRegister double_exponent = xmm1;
2005 // Save 1 in xmm3 - we need this several times later on. 2005 const XMMRegister double_scratch = xmm4;
2006 __ Set(rcx, 1); 2006
2007 __ cvtlsi2sd(xmm3, rcx); 2007 Label double_int_runtime, generic_runtime, done;
2008 2008 Label exponent_not_smi, int_exponent;
2009 Label exponent_nonsmi; 2009
2010 Label base_nonsmi; 2010 // Save 1 in double_result - we need this several times later on.
2011 // If the exponent is a heap number go to that specific case. 2011 __ mov(scratch, Immediate(1));
2012 __ JumpIfNotSmi(rax, &exponent_nonsmi); 2012 __ cvtlsi2sd(double_result, scratch);
2013 __ JumpIfNotSmi(rdx, &base_nonsmi); 2013
2014 2014 if (exponent_type_ == ON_STACK) {
2015 // Optimized version when both exponent and base are smis. 2015 Label base_is_smi, unpack_exponent;
2016 Label powi; 2016 // The exponent and base are supplied as arguments on the stack.
2017 __ SmiToInteger32(rdx, rdx); 2017 // This can only happen if the stub is called from non-optimized code.
2018 __ cvtlsi2sd(xmm0, rdx); 2018 // Load input parameters from stack.
2019 __ jmp(&powi); 2019 __ movq(base, Operand(rsp, 2 * kPointerSize));
2020 // Exponent is a smi and base is a heapnumber. 2020 __ movq(exponent, Operand(rsp, 1 * kPointerSize));
2021 __ bind(&base_nonsmi); 2021 __ JumpIfSmi(base, &base_is_smi, Label::kNear);
2022 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), 2022 __ CompareRoot(FieldOperand(base, HeapObject::kMapOffset),
2023 Heap::kHeapNumberMapRootIndex); 2023 Heap::kHeapNumberMapRootIndex);
2024 __ j(not_equal, &call_runtime); 2024 __ j(not_equal, &generic_runtime);
2025 2025
2026 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 2026 __ movsd(double_base, FieldOperand(base, HeapNumber::kValueOffset));
2027 2027 __ jmp(&unpack_exponent, Label::kNear);
2028 // Optimized version of pow if exponent is a smi. 2028
2029 // xmm0 contains the base. 2029 __ bind(&base_is_smi);
2030 __ bind(&powi); 2030 __ SmiToInteger32(base, base);
2031 __ SmiToInteger32(rax, rax); 2031 __ cvtlsi2sd(double_base, base);
2032 2032 __ bind(&unpack_exponent);
2033 // Save exponent in base as we need to check if exponent is negative later. 2033
2034 // We know that base and exponent are in different registers. 2034 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
2035 __ movq(rdx, rax); 2035 __ SmiToInteger32(exponent, exponent);
2036 __ jmp(&int_exponent);
2037
2038 __ bind(&exponent_not_smi);
2039 __ CompareRoot(FieldOperand(exponent, HeapObject::kMapOffset),
2040 Heap::kHeapNumberMapRootIndex);
2041 __ j(not_equal, &generic_runtime);
2042 __ movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
2043 } else if (exponent_type_ == TAGGED) {
2044 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear);
2045 __ SmiToInteger32(exponent, exponent);
2046 __ jmp(&int_exponent);
2047
2048 __ bind(&exponent_not_smi);
2049 __ movsd(double_exponent, FieldOperand(exponent, HeapNumber::kValueOffset));
2050 }
2051
2052 if (exponent_type_ != INTEGER) {
2053 Label fast_power;
2054 // Detect integer exponents stored as double.
2055 __ cvttsd2si(exponent, double_exponent);
2056 // Skip to runtime if possibly NaN (indicated by the indefinite integer).
2057 __ cmpl(exponent, Immediate(0x80000000u));
2058 __ j(equal, &generic_runtime);
2059 __ cvtlsi2sd(double_scratch, exponent);
2060 // Already ruled out NaNs for exponent.
2061 __ ucomisd(double_exponent, double_scratch);
2062 __ j(equal, &int_exponent);
2063
2064 if (exponent_type_ == ON_STACK) {
2065 // Detect square root case. Crankshaft detects constant +/-0.5 at
2066 // compile time and uses DoMathPowHalf instead. We then skip this check
2067 // for non-constant cases of +/-0.5 as these hardly occur.
2068 Label continue_sqrt, continue_rsqrt, not_plus_half;
2069 // Test for 0.5.
2070 // Load double_scratch with 0.5.
2071 __ movq(scratch, V8_UINT64_C(0x3FE0000000000000), RelocInfo::NONE);
2072 __ movq(double_scratch, scratch);
2073 // Already ruled out NaNs for exponent.
2074 __ ucomisd(double_scratch, double_exponent);
2075 __ j(not_equal, &not_plus_half, Label::kNear);
2076
2077 // Calculates square root of base. Check for the special case of
2078 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
2079 // According to IEEE-754, double-precision -Infinity has the highest
2080 // 12 bits set and the lowest 52 bits cleared.
2081 __ movq(scratch, V8_UINT64_C(0xFFF0000000000000), RelocInfo::NONE);
2082 __ movq(double_scratch, scratch);
2083 __ ucomisd(double_scratch, double_base);
2084 // Comparing -Infinity with NaN results in "unordered", which sets the
2085 // zero flag as if both were equal. However, it also sets the carry flag.
2086 __ j(not_equal, &continue_sqrt, Label::kNear);
2087 __ j(carry, &continue_sqrt, Label::kNear);
2088
2089 // Set result to Infinity in the special case.
2090 __ xorps(double_result, double_result);
2091 __ subsd(double_result, double_scratch);
2092 __ jmp(&done);
2093
2094 __ bind(&continue_sqrt);
2095 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2096 __ xorps(double_scratch, double_scratch);
2097 __ addsd(double_scratch, double_base); // Convert -0 to 0.
2098 __ sqrtsd(double_result, double_scratch);
2099 __ jmp(&done);
2100
2101 // Test for -0.5.
2102 __ bind(&not_plus_half);
2103 // Load double_scratch with -0.5 by substracting 1.
2104 __ subsd(double_scratch, double_result);
2105 // Already ruled out NaNs for exponent.
2106 __ ucomisd(double_scratch, double_exponent);
2107 __ j(not_equal, &fast_power, Label::kNear);
2108
2109 // Calculates reciprocal of square root of base. Check for the special
2110 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
2111 // According to IEEE-754, double-precision -Infinity has the highest
2112 // 12 bits set and the lowest 52 bits cleared.
2113 __ movq(scratch, V8_UINT64_C(0xFFF0000000000000), RelocInfo::NONE);
2114 __ movq(double_scratch, scratch);
2115 __ ucomisd(double_scratch, double_base);
2116 // Comparing -Infinity with NaN results in "unordered", which sets the
2117 // zero flag as if both were equal. However, it also sets the carry flag.
2118 __ j(not_equal, &continue_rsqrt, Label::kNear);
2119 __ j(carry, &continue_rsqrt, Label::kNear);
2120
2121 // Set result to 0 in the special case.
2122 __ xorps(double_result, double_result);
2123 __ jmp(&done);
2124
2125 __ bind(&continue_rsqrt);
2126 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2127 __ xorps(double_exponent, double_exponent);
2128 __ addsd(double_exponent, double_base); // Convert -0 to +0.
2129 __ sqrtsd(double_exponent, double_exponent);
2130 __ divsd(double_result, double_exponent);
2131 __ jmp(&done);
2132 }
2133
2134 // Using FPU instructions to calculate power.
2135 Label fast_power_failed;
2136 __ bind(&fast_power);
2137 __ fnclex(); // Clear flags to catch exceptions later.
2138 // Transfer (B)ase and (E)xponent onto the FPU register stack.
2139 __ subq(rsp, Immediate(kDoubleSize));
2140 __ movsd(Operand(rsp, 0), double_exponent);
2141 __ fld_d(Operand(rsp, 0)); // E
2142 __ movsd(Operand(rsp, 0), double_base);
2143 __ fld_d(Operand(rsp, 0)); // B, E
2144
2145 // Exponent is in st(1) and base is in st(0)
2146 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B)
2147 // FYL2X calculates st(1) * log2(st(0))
2148 __ fyl2x(); // X
2149 __ fld(0); // X, X
2150 __ frndint(); // rnd(X), X
2151 __ fsub(1); // rnd(X), X-rnd(X)
2152 __ fxch(1); // X - rnd(X), rnd(X)
2153 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
2154 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
2155 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
2156 __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
2157 // FSCALE calculates st(0) * 2^st(1)
2158 __ fscale(); // 2^X, rnd(X)
2159 __ fstp(1);
2160 // Bail out to runtime in case of exceptions in the status word.
2161 __ fnstsw_ax();
2162 __ testb(rax, Immediate(0x5F)); // Check for all but precision exception.
2163 __ j(not_zero, &fast_power_failed, Label::kNear);
2164 __ fstp_d(Operand(rsp, 0));
2165 __ movsd(double_result, Operand(rsp, 0));
2166 __ addq(rsp, Immediate(kDoubleSize));
2167 __ jmp(&done);
2168
2169 __ bind(&fast_power_failed);
2170 __ fninit();
2171 __ addq(rsp, Immediate(kDoubleSize));
2172 __ jmp(&generic_runtime);
2173 }
2174
2175 // Calculate power with integer exponent.
2176 __ bind(&int_exponent);
2177 const XMMRegister double_scratch2 = double_exponent;
2178 // Back up exponent as we need to check if exponent is negative later.
2179 __ movq(scratch, exponent); // Back up exponent.
2180 __ movsd(double_scratch, double_base); // Back up base.
2181 __ movsd(double_scratch2, double_result); // Load double_exponent with 1.
2036 2182
2037 // Get absolute value of exponent. 2183 // Get absolute value of exponent.
2038 Label no_neg; 2184 Label no_neg, while_true, no_multiply;
2039 __ cmpl(rax, Immediate(0)); 2185 __ cmpl(scratch, Immediate(0));
2040 __ j(greater_equal, &no_neg, Label::kNear); 2186 __ j(positive, &no_neg, Label::kNear);
2041 __ negl(rax); 2187 __ negl(scratch);
2042 __ bind(&no_neg); 2188 __ bind(&no_neg);
2043 2189
2044 // Load xmm1 with 1.
2045 __ movaps(xmm1, xmm3);
2046 Label while_true;
2047 Label no_multiply;
2048
2049 __ bind(&while_true); 2190 __ bind(&while_true);
2050 __ shrl(rax, Immediate(1)); 2191 __ shrl(scratch, Immediate(1));
2051 __ j(not_carry, &no_multiply, Label::kNear); 2192 __ j(not_carry, &no_multiply, Label::kNear);
2052 __ mulsd(xmm1, xmm0); 2193 __ mulsd(double_result, double_scratch);
2053 __ bind(&no_multiply); 2194 __ bind(&no_multiply);
2054 __ mulsd(xmm0, xmm0); 2195
2196 __ mulsd(double_scratch, double_scratch);
2055 __ j(not_zero, &while_true); 2197 __ j(not_zero, &while_true);
2056 2198
2057 // Base has the original value of the exponent - if the exponent is 2199 // scratch has the original value of the exponent - if the exponent is
2058 // negative return 1/result. 2200 // negative, return 1/result.
2059 __ testl(rdx, rdx); 2201 __ testl(exponent, exponent);
2060 __ j(positive, &allocate_return); 2202 __ j(greater, &done);
2061 // Special case if xmm1 has reached infinity. 2203 __ divsd(double_scratch2, double_result);
2062 __ divsd(xmm3, xmm1); 2204 __ movsd(double_result, double_scratch2);
2063 __ movaps(xmm1, xmm3); 2205 // Test whether result is zero. Bail out to check for subnormal result.
2064 __ xorps(xmm0, xmm0); 2206 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
2065 __ ucomisd(xmm0, xmm1); 2207 __ xorps(double_scratch2, double_scratch2);
2066 __ j(equal, &call_runtime); 2208 __ ucomisd(double_scratch2, double_result);
2067 2209 __ j(equal, &double_int_runtime);
2068 __ jmp(&allocate_return); 2210
2069 2211 // Returning or bailing out.
2070 // Exponent (or both) is a heapnumber - no matter what we should now work 2212 if (exponent_type_ == ON_STACK) {
2071 // on doubles. 2213 // The stub is called from non-optimized code, which expects the result
2072 __ bind(&exponent_nonsmi); 2214 // as heap number in eax.
2073 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 2215 __ bind(&done);
2074 Heap::kHeapNumberMapRootIndex); 2216 __ AllocateHeapNumber(rax, rcx, &generic_runtime);
2075 __ j(not_equal, &call_runtime); 2217 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), double_result);
2076 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); 2218 __ ret(2 * kPointerSize);
2077 // Test if exponent is nan. 2219
2078 __ ucomisd(xmm1, xmm1); 2220 // The arguments are still on the stack.
2079 __ j(parity_even, &call_runtime); 2221 __ bind(&generic_runtime);
2080 2222 __ bind(&double_int_runtime);
2081 Label base_not_smi, handle_special_cases; 2223 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
2082 __ JumpIfNotSmi(rdx, &base_not_smi, Label::kNear); 2224 } else {
2083 __ SmiToInteger32(rdx, rdx); 2225 __ jmp(&done);
2084 __ cvtlsi2sd(xmm0, rdx); 2226
2085 __ jmp(&handle_special_cases, Label::kNear); 2227 Label return_from_runtime;
2086 2228 StubRuntimeCallHelper callhelper;
2087 __ bind(&base_not_smi); 2229 __ bind(&generic_runtime);
2088 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), 2230 // Move base to the correct argument register. Exponent is already in xmm1.
2089 Heap::kHeapNumberMapRootIndex); 2231 __ movsd(xmm0, double_base);
2090 __ j(not_equal, &call_runtime); 2232 ASSERT(exponent.is(xmm1));
2091 __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset)); 2233 {
2092 __ andl(rcx, Immediate(HeapNumber::kExponentMask)); 2234 AllowExternalCallThatCantCauseGC scope(masm);
2093 __ cmpl(rcx, Immediate(HeapNumber::kExponentMask)); 2235 __ PrepareCallCFunction(2);
2094 // base is NaN or +/-Infinity 2236 __ CallCFunction(
2095 __ j(greater_equal, &call_runtime); 2237 ExternalReference::power_double_double_function(masm->isolate()), 2);
2096 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); 2238 }
2097 2239 __ jmp(&return_from_runtime, Label::kNear);
2098 // base is in xmm0 and exponent is in xmm1. 2240
2099 __ bind(&handle_special_cases); 2241 __ bind(&double_int_runtime);
2100 Label not_minus_half; 2242 // Move base to the correct argument register.
2101 // Test for -0.5. 2243 __ movsd(xmm0, double_base);
2102 // Load xmm2 with -0.5. 2244 // Exponent is already in the correct argument register:
2103 __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE); 2245 // edi (not rdi) on Linux and edx on Windows.
2104 __ movq(xmm2, rcx); 2246 {
2105 // xmm2 now has -0.5. 2247 AllowExternalCallThatCantCauseGC scope(masm);
2106 __ ucomisd(xmm2, xmm1); 2248 __ PrepareCallCFunction(2);
2107 __ j(not_equal, &not_minus_half, Label::kNear); 2249 __ CallCFunction(
2108 2250 ExternalReference::power_double_int_function(masm->isolate()), 2);
2109 // Calculates reciprocal of square root. 2251 }
2110 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 2252
2111 __ xorps(xmm1, xmm1); 2253 __ bind(&return_from_runtime);
2112 __ addsd(xmm1, xmm0); 2254 // Return value is in xmm0.
2113 __ sqrtsd(xmm1, xmm1); 2255 __ movsd(double_result, xmm0);
2114 __ divsd(xmm3, xmm1); 2256 // Restore context register.
2115 __ movaps(xmm1, xmm3); 2257 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2116 __ jmp(&allocate_return); 2258
2117 2259 __ bind(&done);
2118 // Test for 0.5. 2260 __ ret(0);
2119 __ bind(&not_minus_half); 2261 }
2120 // Load xmm2 with 0.5.
2121 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
2122 __ addsd(xmm2, xmm3);
2123 // xmm2 now has 0.5.
2124 __ ucomisd(xmm2, xmm1);
2125 __ j(not_equal, &call_runtime);
2126 // Calculates square root.
2127 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2128 __ xorps(xmm1, xmm1);
2129 __ addsd(xmm1, xmm0); // Convert -0 to 0.
2130 __ sqrtsd(xmm1, xmm1);
2131
2132 __ bind(&allocate_return);
2133 __ AllocateHeapNumber(rcx, rax, &call_runtime);
2134 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm1);
2135 __ movq(rax, rcx);
2136 __ ret(2 * kPointerSize);
2137
2138 __ bind(&call_runtime);
2139 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
2140 } 2262 }
2141 2263
2142 2264
2143 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 2265 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
2144 // The key is in rdx and the parameter count is in rax. 2266 // The key is in rdx and the parameter count is in rax.
2145 2267
2146 // The displacement is used for skipping the frame pointer on the 2268 // The displacement is used for skipping the frame pointer on the
2147 // stack. It is the offset of the last parameter (if any) relative 2269 // stack. It is the offset of the last parameter (if any) relative
2148 // to the frame pointer. 2270 // to the frame pointer.
2149 static const int kDisplacement = 1 * kPointerSize; 2271 static const int kDisplacement = 1 * kPointerSize;
(...skipping 3943 matching lines...) Expand 10 before | Expand all | Expand 10 after
6093 xmm0, 6215 xmm0,
6094 &slow_elements); 6216 &slow_elements);
6095 __ ret(0); 6217 __ ret(0);
6096 } 6218 }
6097 6219
6098 #undef __ 6220 #undef __
6099 6221
6100 } } // namespace v8::internal 6222 } } // namespace v8::internal
6101 6223
6102 #endif // V8_TARGET_ARCH_X64 6224 #endif // V8_TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698