Bug 967709 - SpiderMonkey: Revert the fast_sincos implementation for now. r=me
authorDan Gohman <sunfish@mozilla.com>
Wed, 23 Apr 2014 14:44:01 -0700
changeset 198314 ba2e9970b80f05a995276cc9805d5a4f5305b7a1
parent 198313 2084e0ea923c2e8b0635cd6c3302f39b2565fbfa
child 198315 c81b25ae61c051c4045a558ab37a910acb6d3482
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs967709
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 967709 - SpiderMonkey: Revert the fast_sincos implementation for now. r=me
js/src/jit/AsmJSModule.cpp
js/src/jit/CodeGenerator.cpp
js/src/jsmath.cpp
js/src/jsmath.h
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -228,19 +228,19 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
       case AsmJSImm_aeabi_idivmod:
         return RedirectCall(FuncCast(__aeabi_idivmod), Args_General2);
       case AsmJSImm_aeabi_uidivmod:
         return RedirectCall(FuncCast(__aeabi_uidivmod), Args_General2);
 #endif
       case AsmJSImm_ModD:
         return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
       case AsmJSImm_SinD:
-        return RedirectCall(FuncCast<double (double)>(math_sin_impl), Args_Double_Double);
+        return RedirectCall(FuncCast<double (double)>(sin), Args_Double_Double);
       case AsmJSImm_CosD:
-        return RedirectCall(FuncCast<double (double)>(math_cos_impl), Args_Double_Double);
+        return RedirectCall(FuncCast<double (double)>(cos), Args_Double_Double);
       case AsmJSImm_TanD:
         return RedirectCall(FuncCast<double (double)>(tan), Args_Double_Double);
       case AsmJSImm_ASinD:
         return RedirectCall(FuncCast<double (double)>(asin), Args_Double_Double);
       case AsmJSImm_ACosD:
         return RedirectCall(FuncCast<double (double)>(acos), Args_Double_Double);
       case AsmJSImm_ATanD:
         return RedirectCall(FuncCast<double (double)>(atan), Args_Double_Double);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4343,30 +4343,35 @@ bool
 CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
 {
     Register temp = ToRegister(ins->temp());
     FloatRegister input = ToFloatRegister(ins->input());
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
     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;
     switch (ins->mir()->function()) {
       case MMathFunction::Log:
         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));
         break;
       case MMathFunction::Tan:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_tan));
         break;
       case MMathFunction::ATan:
@@ -4414,39 +4419,29 @@ CodeGenerator::visitMathFunctionD(LMathF
       case MMathFunction::Trunc:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_trunc));
         break;
       case MMathFunction::Cbrt:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cbrt));
         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");
     }
 
 #   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;
 }
 
 bool
 CodeGenerator::visitMathFunctionF(LMathFunctionF *ins)
 {
     Register temp = ToRegister(ins->temp());
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -327,165 +327,47 @@ js::math_clz32(JSContext *cx, unsigned a
         args.rval().setInt32(32);
         return true;
     }
 
     args.rval().setInt32(mozilla::CountLeadingZeroes32(n));
     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)
-{
-    // 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)
+double
+js::math_cos_impl(MathCache *cache, double x)
 {
-    // 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<uint32_t>(absx * m_4_pi);
-
-    // Integer and fractional part modulo one octant.
-    uint32_t quad_index = ((i + 1) >> 1) & 3;
-    double y = static_cast<double>(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
 js::math_cos(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     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;
 }
 
 #ifdef _WIN32
 #define EXP_IF_OUT_OF_RANGE(x)                  \
     if (!IsNaN(x)) {                            \
         if (x == PositiveInfinity<double>())    \
@@ -926,36 +808,46 @@ js::math_round(JSContext *cx, unsigned a
         return false;
 
     double z = math_round_impl(x);
     args.rval().setNumber(z);
     return true;
 }
 
 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
 js::math_sin(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     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;
 }
 
 bool
 js_math_sqrt(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -123,23 +123,29 @@ math_log_impl(MathCache *cache, double x
 
 extern double
 math_log_uncached(double x);
 
 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);
 
 extern double
 math_exp_impl(MathCache *cache, double x);
 
 extern double