Bug 967709 - SpiderMonkey: Revert the fast_sincos implementation for now. r=me

This commit is contained in:
Dan Gohman 2014-04-23 14:44:01 -07:00
parent a9dec9ad29
commit 118e8f6ba8
4 changed files with 42 additions and 149 deletions

View File

@ -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<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:

View File

@ -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;
}

View File

@ -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<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
@ -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;
}

View File

@ -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);