author | Kevin Stangl <kevin.stangl@gmail.com> |
Wed, 05 Jun 2013 11:36:09 -0700 | |
changeset 134120 | c21ef4ecb7f429e41960b0bae96995603a4e40a2 |
parent 134119 | 73ef965a7b666fb4877c082115fbebf48c99def2 |
child 134121 | 14b5a5165e47bcf8a0857df6be5125626197c9c3 |
push id | 29061 |
push user | sean.stangl@gmail.com |
push date | Wed, 05 Jun 2013 18:36:39 +0000 |
treeherder | mozilla-inbound@c21ef4ecb7f4 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | sstangl |
bugs | 879564 |
milestone | 24.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
|
--- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -2628,16 +2628,31 @@ CodeGenerator::visitNewSlots(LNewSlots * masm.testPtr(output, output); if (!bailoutIf(Assembler::Zero, lir->snapshot())) return false; return true; } +bool CodeGenerator::visitAtan2D(LAtan2D *lir) +{ + Register temp = ToRegister(lir->temp()); + FloatRegister y = ToFloatRegister(lir->y()); + FloatRegister x = ToFloatRegister(lir->x()); + + masm.setupUnalignedABICall(2, temp); + masm.passABIArg(y); + masm.passABIArg(x); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaAtan2), MacroAssembler::DOUBLE); + + JS_ASSERT(ToFloatRegister(lir->output()) == ReturnFloatReg); + return true; +} + bool CodeGenerator::visitNewParallelArray(LNewParallelArray *lir) { Register objReg = ToRegister(lir->output()); JSObject *templateObject = lir->mir()->templateObject(); OutOfLineNewParallelArray *ool = new OutOfLineNewParallelArray(lir); if (!addOutOfLineCode(ool))
--- a/js/src/ion/CodeGenerator.h +++ b/js/src/ion/CodeGenerator.h @@ -149,16 +149,17 @@ class CodeGenerator : public CodeGenerat Register scratch, const TypedOrValueRegister &output); bool visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV *ins); bool visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT *ins); bool emitSetPropertyPolymorphic(LInstruction *lir, Register obj, Register scratch, const ConstantOrRegister &value); bool visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV *ins); bool visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT *ins); bool visitAbsI(LAbsI *lir); + bool visitAtan2D(LAtan2D *lir); bool visitPowI(LPowI *lir); bool visitPowD(LPowD *lir); bool visitRandom(LRandom *lir); bool visitMathFunctionD(LMathFunctionD *ins); bool visitModD(LModD *ins); bool visitMinMaxI(LMinMaxI *lir); bool visitBinaryV(LBinaryV *lir); bool emitCompareS(LInstruction *lir, JSOp op, Register left, Register right,
--- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -459,16 +459,17 @@ class IonBuilder : public MIRGenerator InliningStatus inlineArrayPush(CallInfo &callInfo); InliningStatus inlineArrayConcat(CallInfo &callInfo); // Math natives. InliningStatus inlineMathAbs(CallInfo &callInfo); InliningStatus inlineMathFloor(CallInfo &callInfo); InliningStatus inlineMathRound(CallInfo &callInfo); InliningStatus inlineMathSqrt(CallInfo &callInfo); + InliningStatus inlineMathAtan2(CallInfo &callInfo); InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max); InliningStatus inlineMathPow(CallInfo &callInfo); InliningStatus inlineMathRandom(CallInfo &callInfo); InliningStatus inlineMathImul(CallInfo &callInfo); InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function); // String natives. InliningStatus inlineStringObject(CallInfo &callInfo);
--- a/js/src/ion/LIR-Common.h +++ b/js/src/ion/LIR-Common.h @@ -2060,16 +2060,43 @@ class LSqrtD : public LInstructionHelper { public: LIR_HEADER(SqrtD) LSqrtD(const LAllocation &num) { setOperand(0, num); } }; +class LAtan2D : public LCallInstructionHelper<1, 2, 1> +{ + public: + LIR_HEADER(Atan2D) + LAtan2D(const LAllocation &y, const LAllocation &x, const LDefinition &temp) { + setOperand(0, y); + setOperand(1, x); + setTemp(0, temp); + } + + const LAllocation *y() { + return getOperand(0); + } + + const LAllocation *x() { + 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> { public: LIR_HEADER(PowI) LPowI(const LAllocation &value, const LAllocation &power, const LDefinition &temp) { setOperand(0, value); setOperand(1, power);
--- a/js/src/ion/LOpcodes.h +++ b/js/src/ion/LOpcodes.h @@ -87,16 +87,17 @@ _(EmulatesUndefinedAndBranch) \ _(MinMaxI) \ _(MinMaxD) \ _(NegI) \ _(NegD) \ _(AbsI) \ _(AbsD) \ _(SqrtD) \ + _(Atan2D) \ _(PowI) \ _(PowD) \ _(Random) \ _(MathFunctionD) \ _(NotI) \ _(NotD) \ _(NotO) \ _(NotV) \
--- a/js/src/ion/Lowering.cpp +++ b/js/src/ion/Lowering.cpp @@ -1054,16 +1054,29 @@ LIRGenerator::visitSqrt(MSqrt *ins) { MDefinition *num = ins->num(); JS_ASSERT(num->type() == MIRType_Double); LSqrtD *lir = new LSqrtD(useRegisterAtStart(num)); return defineReuseInput(lir, ins, 0); } bool +LIRGenerator::visitAtan2(MAtan2 *ins) +{ + MDefinition *y = ins->y(); + JS_ASSERT(y->type() == MIRType_Double); + + MDefinition *x = ins->x(); + JS_ASSERT(x->type() == MIRType_Double); + + LAtan2D *lir = new LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x), tempFixed(CallTempReg0)); + return defineReturn(lir, ins); +} + +bool LIRGenerator::visitPow(MPow *ins) { MDefinition *input = ins->input(); JS_ASSERT(input->type() == MIRType_Double); MDefinition *power = ins->power(); JS_ASSERT(power->type() == MIRType_Int32 || power->type() == MIRType_Double);
--- a/js/src/ion/Lowering.h +++ b/js/src/ion/Lowering.h @@ -128,16 +128,17 @@ class LIRGenerator : public LIRGenerator bool visitLsh(MLsh *ins); bool visitRsh(MRsh *ins); bool visitUrsh(MUrsh *ins); bool visitFloor(MFloor *ins); bool visitRound(MRound *ins); bool visitMinMax(MMinMax *ins); bool visitAbs(MAbs *ins); bool visitSqrt(MSqrt *ins); + bool visitAtan2(MAtan2 *ins); bool visitPow(MPow *ins); bool visitRandom(MRandom *ins); bool visitMathFunction(MMathFunction *ins); bool visitAdd(MAdd *ins); bool visitSub(MSub *ins); bool visitMul(MMul *ins); bool visitDiv(MDiv *ins); bool visitMod(MMod *ins);
--- a/js/src/ion/MCallOptimize.cpp +++ b/js/src/ion/MCallOptimize.cpp @@ -37,16 +37,18 @@ IonBuilder::inlineNativeCall(CallInfo &c if (native == js_math_abs) return inlineMathAbs(callInfo); if (native == js_math_floor) return inlineMathFloor(callInfo); if (native == js_math_round) return inlineMathRound(callInfo); if (native == js_math_sqrt) return inlineMathSqrt(callInfo); + if (native == math_atan2) + return inlineMathAtan2(callInfo); if (native == js_math_max) return inlineMathMinMax(callInfo, true /* max */); if (native == js_math_min) return inlineMathMinMax(callInfo, false /* max */); if (native == js_math_pow) return inlineMathPow(callInfo); if (native == js_math_random) return inlineMathRandom(callInfo); @@ -584,16 +586,42 @@ IonBuilder::inlineMathSqrt(CallInfo &cal MSqrt *sqrt = MSqrt::New(callInfo.getArg(0)); current->add(sqrt); current->push(sqrt); return InliningStatus_Inlined; } IonBuilder::InliningStatus +IonBuilder::inlineMathAtan2(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(); + + MAtan2 *atan2 = MAtan2::New(callInfo.getArg(0), callInfo.getArg(1)); + current->add(atan2); + current->push(atan2); + return InliningStatus_Inlined; +} + +IonBuilder::InliningStatus IonBuilder::inlineMathPow(CallInfo &callInfo) { if (callInfo.constructing()) return InliningStatus_NotInlined; if (callInfo.argc() != 2) return InliningStatus_NotInlined;
--- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -3065,16 +3065,55 @@ class MSqrt return congruentIfOperandsEqual(ins); } AliasSet getAliasSet() const { return AliasSet::None(); } }; +// Inline implementation of atan2 (arctangent of y/x). +class MAtan2 + : public MBinaryInstruction, + public MixPolicy<DoublePolicy<0>, DoublePolicy<1> > +{ + MAtan2(MDefinition *y, MDefinition *x) + : MBinaryInstruction(y, x) + { + setResultType(MIRType_Double); + setMovable(); + } + + public: + INSTRUCTION_HEADER(Atan2) + static MAtan2 *New(MDefinition *y, MDefinition *x) { + return new MAtan2(y, x); + } + + MDefinition *y() const { + return getOperand(0); + } + + MDefinition *x() const { + return getOperand(1); + } + + TypePolicy *typePolicy() { + return this; + } + + bool congruentTo(MDefinition *const &ins) const { + return congruentIfOperandsEqual(ins); + } + + AliasSet getAliasSet() const { + return AliasSet::None(); + } +}; + // Inline implementation of Math.pow(). class MPow : public MBinaryInstruction, public PowPolicy { MPow(MDefinition *input, MDefinition *power, MIRType powerType) : MBinaryInstruction(input, power), PowPolicy(powerType)
--- a/js/src/ion/MOpcodes.h +++ b/js/src/ion/MOpcodes.h @@ -50,16 +50,17 @@ namespace ion { _(BitOr) \ _(BitXor) \ _(Lsh) \ _(Rsh) \ _(Ursh) \ _(MinMax) \ _(Abs) \ _(Sqrt) \ + _(Atan2) \ _(Pow) \ _(PowHalf) \ _(Random) \ _(MathFunction) \ _(Add) \ _(Sub) \ _(Mul) \ _(Div) \
--- a/js/src/ion/ParallelArrayAnalysis.cpp +++ b/js/src/ion/ParallelArrayAnalysis.cpp @@ -146,16 +146,17 @@ class ParallelArrayVisitor : public MIns SAFE_OP(BitOr) SAFE_OP(BitXor) SAFE_OP(Lsh) SAFE_OP(Rsh) SPECIALIZED_OP(Ursh, PERMIT_NUMERIC) SPECIALIZED_OP(MinMax, PERMIT_NUMERIC) SAFE_OP(Abs) SAFE_OP(Sqrt) + UNSAFE_OP(Atan2) SAFE_OP(MathFunction) SPECIALIZED_OP(Add, PERMIT_NUMERIC) SPECIALIZED_OP(Sub, PERMIT_NUMERIC) SPECIALIZED_OP(Mul, PERMIT_NUMERIC) SPECIALIZED_OP(Div, PERMIT_NUMERIC) SPECIALIZED_OP(Mod, PERMIT_NUMERIC) UNSAFE_OP(Concat) UNSAFE_OP(CharCodeAt)
--- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -207,43 +207,43 @@ js::math_atan(JSContext *cx, unsigned ar if (!mathCache) return JS_FALSE; z = math_atan_impl(mathCache, x); vp->setDouble(z); return JS_TRUE; } double -js::ecmaAtan2(double x, double y) +js::ecmaAtan2(double y, double x) { #if defined(_MSC_VER) /* * MSVC's atan2 does not yield the result demanded by ECMA when both x * and y are infinite. * - The result is a multiple of pi/4. - * - The sign of x determines the sign of the result. - * - The sign of y determines the multiplicator, 1 or 3. + * - The sign of y determines the sign of the result. + * - The sign of x determines the multiplicator, 1 or 3. */ - if (IsInfinite(x) && IsInfinite(y)) { - double z = js_copysign(M_PI / 4, x); - if (y < 0) + if (IsInfinite(y) && IsInfinite(x)) { + double z = js_copysign(M_PI / 4, y); + if (x < 0) z *= 3; return z; } #endif #if defined(SOLARIS) && defined(__GNUC__) - if (x == 0) { - if (IsNegativeZero(y)) - return js_copysign(M_PI, x); - if (y == 0) - return x; + if (y == 0) { + if (IsNegativeZero(x)) + return js_copysign(M_PI, y); + if (x == 0) + return y; } #endif - return atan2(x, y); + return atan2(y, x); } JSBool js::math_atan2(JSContext *cx, unsigned argc, Value *vp) { double x, y, z; if (argc <= 1) {