Bug 931328 - IonMonkey: Inline Math.hypot(x, y). r=jandem, r=jorendorff

--HG--
rename : js/src/tests/ecma_6/Math/hypot-approx.js => js/src/jit-test/tests/basic/hypot-approx.js
rename : js/src/tests/ecma_6/Math/hypot-exact.js => js/src/jit-test/tests/basic/hypot-exact.js
This commit is contained in:
Sankha Narayan Guria 2013-10-31 19:36:13 +05:30
parent ab4757d9ff
commit 5ee728634b
15 changed files with 193 additions and 40 deletions

View File

@ -1,3 +1,5 @@
loadRelativeToScript("../../../tests/ecma_6/Math/shell.js");
for (var i = -20; i < 20; i++) {
assertEq(Math.hypot(+0, i), Math.abs(i));
assertEq(Math.hypot(-0, i), Math.abs(i));
@ -21,5 +23,3 @@ assertNear(Math.hypot(1e3, 1e-3, 1e3, 1e-3), 1414.2135623738021555);
for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
reportCompare(0, 0, "ok");

View File

@ -55,6 +55,3 @@ assertEq(Math.hypot(+0, +0, -0), +0);
// The length property of the hypot function is 2.
assertEq(Math.hypot.length, 2);
reportCompare(0, 0, "ok");

View File

@ -3001,6 +3001,21 @@ bool CodeGenerator::visitAtan2D(LAtan2D *lir)
return true;
}
bool CodeGenerator::visitHypot(LHypot *lir)
{
Register temp = ToRegister(lir->temp());
FloatRegister x = ToFloatRegister(lir->x());
FloatRegister y = ToFloatRegister(lir->y());
masm.setupUnalignedABICall(2, temp);
masm.passABIArg(x);
masm.passABIArg(y);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MacroAssembler::DOUBLE);
JS_ASSERT(ToFloatRegister(lir->output()) == ReturnFloatReg);
return true;
}
bool
CodeGenerator::visitNewParallelArray(LNewParallelArray *lir)
{

View File

@ -179,6 +179,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT *ins);
bool visitAbsI(LAbsI *lir);
bool visitAtan2D(LAtan2D *lir);
bool visitHypot(LHypot *lir);
bool visitPowI(LPowI *lir);
bool visitPowD(LPowD *lir);
bool visitRandom(LRandom *lir);

View File

@ -563,6 +563,7 @@ class IonBuilder : public MIRGenerator
InliningStatus inlineMathRound(CallInfo &callInfo);
InliningStatus inlineMathSqrt(CallInfo &callInfo);
InliningStatus inlineMathAtan2(CallInfo &callInfo);
InliningStatus inlineMathHypot(CallInfo &callInfo);
InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max);
InliningStatus inlineMathPow(CallInfo &callInfo);
InliningStatus inlineMathRandom(CallInfo &callInfo);

View File

@ -2369,6 +2369,33 @@ class LAtan2D : public LCallInstructionHelper<1, 2, 1>
}
};
class LHypot : public LCallInstructionHelper<1, 2, 1>
{
public:
LIR_HEADER(Hypot)
LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp) {
setOperand(0, x);
setOperand(1, y);
setTemp(0, temp);
}
const LAllocation *x() {
return getOperand(0);
}
const LAllocation *y() {
return getOperand(1);
}
const LDefinition *temp() {
return getTemp(0);
}
const LDefinition *output() {
return getDef(0);
}
};
// Double raised to an integer power.
class LPowI : public LCallInstructionHelper<1, 2, 1>
{

View File

@ -105,6 +105,7 @@
_(SqrtD) \
_(SqrtF) \
_(Atan2D) \
_(Hypot) \
_(PowI) \
_(PowD) \
_(Random) \

View File

@ -1221,6 +1221,19 @@ LIRGenerator::visitAtan2(MAtan2 *ins)
return defineReturn(lir, ins);
}
bool
LIRGenerator::visitHypot(MHypot *ins)
{
MDefinition *x = ins->x();
JS_ASSERT(x->type() == MIRType_Double);
MDefinition *y = ins->y();
JS_ASSERT(y->type() == MIRType_Double);
LHypot *lir = new LHypot(useRegisterAtStart(x), useRegisterAtStart(y), tempFixed(CallTempReg0));
return defineReturn(lir, ins);
}
bool
LIRGenerator::visitPow(MPow *ins)
{

View File

@ -136,6 +136,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitAbs(MAbs *ins);
bool visitSqrt(MSqrt *ins);
bool visitAtan2(MAtan2 *ins);
bool visitHypot(MHypot *ins);
bool visitPow(MPow *ins);
bool visitRandom(MRandom *ins);
bool visitMathFunction(MMathFunction *ins);

View File

@ -47,6 +47,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
return inlineMathSqrt(callInfo);
if (native == math_atan2)
return inlineMathAtan2(callInfo);
if (native == js::math_hypot)
return inlineMathHypot(callInfo);
if (native == js_math_max)
return inlineMathMinMax(callInfo, true /* max */);
if (native == js_math_min)
@ -675,6 +677,32 @@ IonBuilder::inlineMathAtan2(CallInfo &callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineMathHypot(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 2)
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
MIRType argType0 = callInfo.getArg(0)->type();
MIRType argType1 = callInfo.getArg(1)->type();
if (!IsNumberType(argType0) || !IsNumberType(argType1))
return InliningStatus_NotInlined;
callInfo.unwrapArgs();
MHypot *hypot = MHypot::New(callInfo.getArg(0), callInfo.getArg(1));
current->add(hypot);
current->push(hypot);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineMathPow(CallInfo &callInfo)
{

View File

@ -3586,6 +3586,49 @@ class MAtan2
}
};
// Inline implementation of Math.hypot().
class MHypot
: public MBinaryInstruction,
public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >
{
MHypot(MDefinition *y, MDefinition *x)
: MBinaryInstruction(x, y)
{
setResultType(MIRType_Double);
setMovable();
}
public:
INSTRUCTION_HEADER(Hypot)
static MHypot *New(MDefinition *x, MDefinition *y) {
return new MHypot(y, x);
}
MDefinition *x() const {
return getOperand(0);
}
MDefinition *y() const {
return getOperand(1);
}
TypePolicy *typePolicy() {
return this;
}
bool congruentTo(MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool possiblyCalls() const {
return true;
}
};
// Inline implementation of Math.pow().
class MPow
: public MBinaryInstruction,

View File

@ -59,6 +59,7 @@ namespace jit {
_(Abs) \
_(Sqrt) \
_(Atan2) \
_(Hypot) \
_(Pow) \
_(PowHalf) \
_(Random) \

View File

@ -153,6 +153,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(Abs)
SAFE_OP(Sqrt)
UNSAFE_OP(Atan2)
UNSAFE_OP(Hypot)
CUSTOM_OP(MathFunction)
SPECIALIZED_OP(Add, PERMIT_NUMERIC)
SPECIALIZED_OP(Sub, PERMIT_NUMERIC)

View File

@ -1275,11 +1275,41 @@ js::math_atanh(JSContext *cx, unsigned argc, Value *vp)
return math_function<math_atanh_impl>(cx, argc, vp);
}
/* Consistency wrapper for platform deviations in hypot() */
double
js::ecmaHypot(double x, double y)
{
#ifdef XP_WIN
/*
* Workaround MS hypot bug, where hypot(Infinity, NaN or Math.MIN_VALUE)
* is NaN, not Infinity.
*/
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y)) {
return mozilla::PositiveInfinity();
}
#endif
return hypot(x, y);
}
bool
js::math_hypot(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// IonMonkey calls the system hypot function directly if two arguments are
// given. Do that here as well to get the same results.
if (args.length() == 2) {
double x, y;
if (!ToNumber(cx, args[0], &x))
return false;
if (!ToNumber(cx, args[1], &y))
return false;
double result = ecmaHypot(x, y);
args.rval().setNumber(result);
return true;
}
bool isInfinite = false;
bool isNaN = false;

View File

@ -162,6 +162,9 @@ math_asinh(JSContext *cx, unsigned argc, js::Value *vp);
extern bool
math_atanh(JSContext *cx, unsigned argc, js::Value *vp);
extern double
ecmaHypot(double x, double y);
extern bool
math_hypot(JSContext *cx, unsigned argc, Value *vp);
@ -243,91 +246,82 @@ ecmaPow(double x, double y);
extern bool
math_imul(JSContext *cx, unsigned argc, Value *vp);
extern double
extern double
math_log10_impl(MathCache *cache, double x);
extern double
extern double
math_log10_uncached(double x);
extern double
extern double
math_log2_impl(MathCache *cache, double x);
extern double
extern double
math_log2_uncached(double x);
extern double
extern double
math_log1p_impl(MathCache *cache, double x);
extern double
extern double
math_log1p_uncached(double x);
extern double
extern double
math_expm1_impl(MathCache *cache, double x);
extern double
extern double
math_expm1_uncached(double x);
extern double
extern double
math_cosh_impl(MathCache *cache, double x);
extern double
extern double
math_cosh_uncached(double x);
extern double
extern double
math_sinh_impl(MathCache *cache, double x);
extern double
extern double
math_sinh_uncached(double x);
extern double
extern double
math_tanh_impl(MathCache *cache, double x);
extern double
extern double
math_tanh_uncached(double x);
extern double
extern double
math_acosh_impl(MathCache *cache, double x);
extern double
extern double
math_acosh_uncached(double x);
extern double
extern double
math_asinh_impl(MathCache *cache, double x);
extern double
extern double
math_asinh_uncached(double x);
extern double
extern double
math_atanh_impl(MathCache *cache, double x);
extern double
extern double
math_atanh_uncached(double x);
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
#if 0
extern double
math_hypot_impl(double x, double y);
extern double
math_hypot_uncached(double x, double y);
#endif
extern double
extern double
math_trunc_impl(MathCache *cache, double x);
extern double
extern double
math_trunc_uncached(double x);
extern double
extern double
math_sign_impl(MathCache *cache, double x);
extern double
extern double
math_sign_uncached(double x);
extern double
extern double
math_cbrt_impl(MathCache *cache, double x);
extern double
extern double
math_cbrt_uncached(double x);
} /* namespace js */