From 118e8f6ba89437aa9100b51a605db2d4fec72270 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 23 Apr 2014 14:44:01 -0700 Subject: [PATCH] Bug 967709 - SpiderMonkey: Revert the fast_sincos implementation for now. r=me --- js/src/jit/AsmJSModule.cpp | 4 +- js/src/jit/CodeGenerator.cpp | 23 ++---- js/src/jsmath.cpp | 154 ++++++----------------------------- js/src/jsmath.h | 10 ++- 4 files changed, 42 insertions(+), 149 deletions(-) diff --git a/js/src/jit/AsmJSModule.cpp b/js/src/jit/AsmJSModule.cpp index 2e9de679561d..103eba2c8ee9 100644 --- a/js/src/jit/AsmJSModule.cpp +++ b/js/src/jit/AsmJSModule.cpp @@ -233,9 +233,9 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx) case AsmJSImm_ModD: return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble); case AsmJSImm_SinD: - return RedirectCall(FuncCast(math_sin_impl), Args_Double_Double); + return RedirectCall(FuncCast(sin), Args_Double_Double); case AsmJSImm_CosD: - return RedirectCall(FuncCast(math_cos_impl), Args_Double_Double); + return RedirectCall(FuncCast(cos), Args_Double_Double); case AsmJSImm_TanD: return RedirectCall(FuncCast(tan), Args_Double_Double); case AsmJSImm_ASinD: diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index e3a78c700a1d..a48a7c768ca7 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -4348,6 +4348,13 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins) const MathCache *mathCache = ins->mir()->cache(); + masm.setupUnalignedABICall(mathCache ? 2 : 1, temp); + if (mathCache) { + masm.movePtr(ImmPtr(mathCache), temp); + masm.passABIArg(temp); + } + masm.passABIArg(input, MoveOp::DOUBLE); + # define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached) void *funptr = nullptr; @@ -4356,12 +4363,10 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins) funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log)); break; case MMathFunction::Sin: - funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_sin_impl); - mathCache = nullptr; + funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sin)); break; case MMathFunction::Cos: - funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_cos_impl); - mathCache = nullptr; + funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cos)); break; case MMathFunction::Exp: funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_exp)); @@ -4419,15 +4424,12 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins) break; case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_floor_impl); - mathCache = nullptr; break; case MMathFunction::Ceil: funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_ceil_impl); - mathCache = nullptr; break; case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl); - mathCache = nullptr; break; default: MOZ_ASSUME_UNREACHABLE("Unknown math function"); @@ -4435,13 +4437,6 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins) # undef MAYBE_CACHED - masm.setupUnalignedABICall(mathCache ? 2 : 1, temp); - if (mathCache) { - masm.movePtr(ImmPtr(mathCache), temp); - masm.passABIArg(temp); - } - masm.passABIArg(input, MoveOp::DOUBLE); - masm.callWithABI(funptr, MoveOp::DOUBLE); return true; } diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 05998b7dcf32..1c6e320b841b 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -332,138 +332,16 @@ js::math_clz32(JSContext *cx, unsigned argc, Value *vp) return true; } -/* - * Fast sine and cosine approximation code, based on the sin [0] and cos [1] - * implementations [2] in the cephes library [3]. - * Some of the optimization ideas are inspired by the fast_sincos in VDT [4]. - * - * This implementation satisfies the requirements for sin and cos in JS [5]. - * However, it does not take the standard's recommendation to use fdlibm [6], - * nor does it take advantage of the standard's intent to permit JS to use the - * system C math library. - * - * The code carefully avoids branching, to avoid the cost of mispredictions - * either on random input sets or on input sets straddling a boundary condition - * in the algorithm. It contains only one branch, which is for testing for - * unusual inputs (infinities, NaNs, and extremely large values), and it - * should be very predictable. - * - * This implementation computes both a sin and cos value even when only one - * of the two is needed. While creating specialized routines for computing just - * sin or just cost would allow them to do less work, the speed benefits would - * be expected to be marginal, and not worth the extra code it would take, given - * that we'll still want the ability to compute sin and cos together anyway. - * - * [0] http://netlib.org/cephes/doubldoc.html#sin - * [1] http://netlib.org/cephes/doubldoc.html#cos - * [2] http://netlib.org/cephes/cmath.tgz - * [3] http://netlib.org/cephes/ - * [4] https://svnweb.cern.ch/trac/vdt - * [5] http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2 - * [6] http://netlib.org/fdlibm - */ - -static double polevl_sin(double z, double zz) +double +js::math_cos_impl(MathCache *cache, double x) { - // Constants generated using Mathematica's GeneralMiniMaxApproximation - double ans = 1.59046813973877163292e-10; // 6152825598094877 / exp2(85) - ans *= zz; - ans += -2.50509001624159785668e-08; // -7571170002733246 / exp2(78) - ans *= zz; - ans += 2.75573146431678644161e-06; // 6506786951439440 / exp2(71) - ans *= zz; - ans += -1.98412698327005105692e-04; // -7320136534024805 / exp2(65) - ans *= zz; - ans += 8.33333333332626768897e-03; // 4803839602524456 / exp2(59) - ans *= zz; - ans += -1.66666666666666490881e-01; // -6004799503160655 / exp2(55) - ans *= zz * z; - ans += z; - return ans; -} - -static double polevl_cos(double zz) -{ - // Constants generated using Mathematica's GeneralMiniMaxApproximation. - // This set uses one less coefficient than usual implementations to - // increase performance, raising the maximum approximation error to 2 bits. - double ans = 2.06467337476762997948e-9; - ans *= zz; - ans += -2.75555495413759160741e-7; - ans *= zz; - ans += 2.48015808595638122085e-5; - ans *= zz; - ans += -1.38888888779622760722e-3; - ans *= zz; - ans += 4.16666666665987187046e-2; - ans *= zz; - ans += -4.99999999999999888978e-1; - ans *= zz; - ans += 1.0; - return ans; -} - -namespace { -struct sincos_result { double s, c; }; -} - -static sincos_result fast_sincos(double x) -{ - // Make argument non-negative but save the sign. - double orig_sign = js_copysign(1.0, x); - double absx = fabs(x); - - // The optimized algorithm below doesn't currently support values of x beyond - // pow(2, 32) - 2. If x is beyond the range we support, fall back to the libm - // implementation. This check also handles the Infinity and NaN input cases. - // abs(x) < (221069929647945 / pow(2,16)) - if (MOZ_UNLIKELY(!(absx < 3.37325942455970764160e9))) { - sincos_result result = { - sin(x), - cos(x) - }; - return result; - } - - static const double m_4_pi = 1.27323954473516276487; // 4.0 / M_PI - uint32_t i = static_cast(absx * m_4_pi); - - // Integer and fractional part modulo one octant. - uint32_t quad_index = ((i + 1) >> 1) & 3; - double y = static_cast(i + (i & 1)); - - // Extended precision modular arithmetic - double e0 = y * -7.85398006439208984375e-1; // 1647099 / pow(2,21) - double e1 = y * -1.56958208208379801363e-7; // 1380619 / pow(2,43) - double e2 = y * -3.11168608594830669189e-14; // 4930663418217751 / pow(2,97) - double z = absx + e0 + e1 + e2; - - // Compute the sin/cos in quadrant 0. - double zz = z * z; - double q0_sin = polevl_sin(z, zz); - double q0_cos = polevl_cos(zz); - - // Reflect the result into the correct quadrant. - const double reflect[4] = { - q0_sin, q0_cos, -q0_sin, -q0_cos - }; - - // Adjust the sine value by the sign of the input. - // Missed optimization: C++ doesn't provide convenient access to - // floating-point xor; hand-written assembler could change the copysign - // above to use 0.0 instead of 1.0, and then just xor the sign with p[0] - // here instead of multiplying. - sincos_result result = { - reflect[quad_index] * orig_sign, - reflect[(quad_index + 1) & 3] - }; - return result; + return cache->lookup(cos, x); } double -js::math_cos_impl(double x) +js::math_cos_uncached(double x) { - return fast_sincos(x).c; + return cos(x); } bool @@ -480,7 +358,11 @@ js::math_cos(JSContext *cx, unsigned argc, Value *vp) if (!ToNumber(cx, args[0], &x)) return false; - double z = math_cos_impl(x); + MathCache *mathCache = cx->runtime()->getMathCache(cx); + if (!mathCache) + return false; + + double z = math_cos_impl(mathCache, x); args.rval().setDouble(z); return true; } @@ -931,9 +813,15 @@ js::math_round(JSContext *cx, unsigned argc, Value *vp) } double -js::math_sin_impl(double x) +js::math_sin_impl(MathCache *cache, double x) { - return fast_sincos(x).s; + return cache->lookup(sin, x); +} + +double +js::math_sin_uncached(double x) +{ + return sin(x); } bool @@ -950,7 +838,11 @@ js::math_sin(JSContext *cx, unsigned argc, Value *vp) if (!ToNumber(cx, args[0], &x)) return false; - double z = math_sin_impl(x); + MathCache *mathCache = cx->runtime()->getMathCache(cx); + if (!mathCache) + return false; + + double z = math_sin_impl(mathCache, x); args.rval().setDouble(z); return true; } diff --git a/js/src/jsmath.h b/js/src/jsmath.h index 29cddc41842b..2e0c5746d63b 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -128,13 +128,19 @@ extern bool math_sin(JSContext *cx, unsigned argc, js::Value *vp); extern double -math_sin_impl(double x); +math_sin_impl(MathCache *cache, double x); + +extern double +math_sin_uncached(double x); extern bool math_cos(JSContext *cx, unsigned argc, js::Value *vp); extern double -math_cos_impl(double x); +math_cos_impl(MathCache *cache, double x); + +extern double +math_cos_uncached(double x); extern bool math_exp(JSContext *cx, unsigned argc, js::Value *vp);