mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-11 22:41:02 +00:00
Bug 967709 - SpiderMonkey: Revert the fast_sincos implementation for now. r=me
This commit is contained in:
parent
a9dec9ad29
commit
118e8f6ba8
@ -233,9 +233,9 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
|
|||||||
case AsmJSImm_ModD:
|
case AsmJSImm_ModD:
|
||||||
return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
|
return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
|
||||||
case AsmJSImm_SinD:
|
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:
|
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:
|
case AsmJSImm_TanD:
|
||||||
return RedirectCall(FuncCast<double (double)>(tan), Args_Double_Double);
|
return RedirectCall(FuncCast<double (double)>(tan), Args_Double_Double);
|
||||||
case AsmJSImm_ASinD:
|
case AsmJSImm_ASinD:
|
||||||
|
@ -4348,6 +4348,13 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
|
|||||||
|
|
||||||
const MathCache *mathCache = ins->mir()->cache();
|
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)
|
# define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
|
||||||
|
|
||||||
void *funptr = nullptr;
|
void *funptr = nullptr;
|
||||||
@ -4356,12 +4363,10 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
|
|||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log));
|
funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log));
|
||||||
break;
|
break;
|
||||||
case MMathFunction::Sin:
|
case MMathFunction::Sin:
|
||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_sin_impl);
|
funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sin));
|
||||||
mathCache = nullptr;
|
|
||||||
break;
|
break;
|
||||||
case MMathFunction::Cos:
|
case MMathFunction::Cos:
|
||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_cos_impl);
|
funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cos));
|
||||||
mathCache = nullptr;
|
|
||||||
break;
|
break;
|
||||||
case MMathFunction::Exp:
|
case MMathFunction::Exp:
|
||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_exp));
|
funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_exp));
|
||||||
@ -4419,15 +4424,12 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
|
|||||||
break;
|
break;
|
||||||
case MMathFunction::Floor:
|
case MMathFunction::Floor:
|
||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_floor_impl);
|
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_floor_impl);
|
||||||
mathCache = nullptr;
|
|
||||||
break;
|
break;
|
||||||
case MMathFunction::Ceil:
|
case MMathFunction::Ceil:
|
||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_ceil_impl);
|
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_ceil_impl);
|
||||||
mathCache = nullptr;
|
|
||||||
break;
|
break;
|
||||||
case MMathFunction::Round:
|
case MMathFunction::Round:
|
||||||
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl);
|
funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl);
|
||||||
mathCache = nullptr;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
MOZ_ASSUME_UNREACHABLE("Unknown math function");
|
MOZ_ASSUME_UNREACHABLE("Unknown math function");
|
||||||
@ -4435,13 +4437,6 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
|
|||||||
|
|
||||||
# undef MAYBE_CACHED
|
# 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);
|
masm.callWithABI(funptr, MoveOp::DOUBLE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -332,138 +332,16 @@ js::math_clz32(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
double
|
||||||
* Fast sine and cosine approximation code, based on the sin [0] and cos [1]
|
js::math_cos_impl(MathCache *cache, double x)
|
||||||
* 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
|
return cache->lookup(cos, x);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
js::math_cos_impl(double x)
|
js::math_cos_uncached(double x)
|
||||||
{
|
{
|
||||||
return fast_sincos(x).c;
|
return cos(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -480,7 +358,11 @@ js::math_cos(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
if (!ToNumber(cx, args[0], &x))
|
if (!ToNumber(cx, args[0], &x))
|
||||||
return false;
|
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);
|
args.rval().setDouble(z);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -931,9 +813,15 @@ js::math_round(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
double
|
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
|
bool
|
||||||
@ -950,7 +838,11 @@ js::math_sin(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
if (!ToNumber(cx, args[0], &x))
|
if (!ToNumber(cx, args[0], &x))
|
||||||
return false;
|
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);
|
args.rval().setDouble(z);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -128,13 +128,19 @@ extern bool
|
|||||||
math_sin(JSContext *cx, unsigned argc, js::Value *vp);
|
math_sin(JSContext *cx, unsigned argc, js::Value *vp);
|
||||||
|
|
||||||
extern double
|
extern double
|
||||||
math_sin_impl(double x);
|
math_sin_impl(MathCache *cache, double x);
|
||||||
|
|
||||||
|
extern double
|
||||||
|
math_sin_uncached(double x);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
math_cos(JSContext *cx, unsigned argc, js::Value *vp);
|
math_cos(JSContext *cx, unsigned argc, js::Value *vp);
|
||||||
|
|
||||||
extern double
|
extern double
|
||||||
math_cos_impl(double x);
|
math_cos_impl(MathCache *cache, double x);
|
||||||
|
|
||||||
|
extern double
|
||||||
|
math_cos_uncached(double x);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
math_exp(JSContext *cx, unsigned argc, js::Value *vp);
|
math_exp(JSContext *cx, unsigned argc, js::Value *vp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user