Bug 918613 - Specialize some Maths function calls for Float32 in Ion. r=sstangl
authorBenjamin Bouvier <benj@benj.me>
Thu, 17 Oct 2013 08:50:56 +0200
changeset 165920 e1226725f67428d10e85d9547d38de135ae866a4
parent 165919 98620827025cb10a85588266f0bc7048193cc898
child 165921 a88f40be25e7aa0f9c672f7e52e1bc2048cd4646
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs918613
milestone27.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 918613 - Specialize some Maths function calls for Float32 in Ion. r=sstangl
js/src/jit-test/tests/ion/testFloat32.js
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/TypePolicy.h
--- a/js/src/jit-test/tests/ion/testFloat32.js
+++ b/js/src/jit-test/tests/ion/testFloat32.js
@@ -131,16 +131,98 @@ test(refuseAddSeveral);
 function refuseAddFunctionCall() {
     function plusOne(x) { return Math.cos(x+1)*13.37; }
     var res = plusOne(f32[0]); // func call is not a consumer
     f32[0] = res;
     assertFloat32(res, false);
 }
 test(refuseAddFunctionCall);
 
+function acceptTrigo() {
+    var res = Math.cos(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, true);
+
+    var res = Math.sin(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, true);
+
+    var res = Math.tan(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, true);
+
+    var res = Math.acos(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, true);
+
+    var res = Math.asin(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, true);
+
+    res = Math.atan(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, true);
+}
+test(acceptTrigo);
+
+function refuseMath() {
+    var res = Math.log10(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.log2(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.log1p(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.expm1(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.cosh(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.sinh(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.tanh(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.acosh(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.asinh(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.atanh(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.cbrt(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.sign(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+
+    res = Math.trunc(f32[0]);
+    f32[0] = res;
+    assertFloat32(res, false);
+}
+test(refuseMath);
+
 function refuseLoop() {
     var res = f32[0],
         n = 10;
     while (n--) {
         res = res + 1; // this loop is equivalent to several additions => second addition is not a consumer
         assertFloat32(res, false);
     }
     assertFloat32(res, false);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3837,16 +3837,44 @@ CodeGenerator::visitMathFunctionD(LMathF
 
 #   undef MAYBE_CACHED
 
     masm.callWithABI(funptr, MacroAssembler::DOUBLE);
     return true;
 }
 
 bool
+CodeGenerator::visitMathFunctionF(LMathFunctionF *ins)
+{
+    Register temp = ToRegister(ins->temp());
+    FloatRegister input = ToFloatRegister(ins->input());
+    JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
+
+    masm.setupUnalignedABICall(1, temp);
+    masm.passABIArg(input);
+
+    void *funptr = NULL;
+    switch (ins->mir()->function()) {
+      case MMathFunction::Log:  funptr = JS_FUNC_TO_DATA_PTR(void *, logf);  break;
+      case MMathFunction::Sin:  funptr = JS_FUNC_TO_DATA_PTR(void *, sinf);  break;
+      case MMathFunction::Cos:  funptr = JS_FUNC_TO_DATA_PTR(void *, cosf);  break;
+      case MMathFunction::Exp:  funptr = JS_FUNC_TO_DATA_PTR(void *, expf);  break;
+      case MMathFunction::Tan:  funptr = JS_FUNC_TO_DATA_PTR(void *, tanf);  break;
+      case MMathFunction::ATan: funptr = JS_FUNC_TO_DATA_PTR(void *, atanf); break;
+      case MMathFunction::ASin: funptr = JS_FUNC_TO_DATA_PTR(void *, sinf);  break;
+      case MMathFunction::ACos: funptr = JS_FUNC_TO_DATA_PTR(void *, acosf); break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unknown or unsupported float32 math function");
+    }
+
+    masm.callWithABI(funptr, MacroAssembler::DOUBLE);
+    return true;
+}
+
+bool
 CodeGenerator::visitModD(LModD *ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->lhs());
     FloatRegister rhs = ToFloatRegister(ins->rhs());
     Register temp = ToRegister(ins->temp());
 
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -176,16 +176,17 @@ class CodeGenerator : public CodeGenerat
     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 visitMathFunctionF(LMathFunctionF *ins);
     bool visitModD(LModD *ins);
     bool visitMinMaxI(LMinMaxI *lir);
     bool visitBinaryV(LBinaryV *lir);
     bool emitCompareS(LInstruction *lir, JSOp op, Register left, Register right,
                       Register output, Register temp);
     bool visitCompareS(LCompareS *lir);
     bool visitCompareStrictS(LCompareStrictS *lir);
     bool visitCompareVM(LCompareVM *lir);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -2335,16 +2335,36 @@ class LMathFunctionD : public LCallInstr
     MMathFunction *mir() const {
         return mir_->toMathFunction();
     }
     const char *extraName() const {
         return MMathFunction::FunctionName(mir()->function());
     }
 };
 
+class LMathFunctionF : public LCallInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(MathFunctionF)
+    LMathFunctionF(const LAllocation &input, const LDefinition &temp) {
+        setOperand(0, input);
+        setTemp(0, temp);
+    }
+
+    const LDefinition *temp() {
+        return getTemp(0);
+    }
+    MMathFunction *mir() const {
+        return mir_->toMathFunction();
+    }
+    const char *extraName() const {
+        return MMathFunction::FunctionName(mir()->function());
+    }
+};
+
 // Adds two integers, returning an integer value.
 class LAddI : public LBinaryMath<0>
 {
     bool recoversInput_;
 
   public:
     LIR_HEADER(AddI)
 
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -99,16 +99,17 @@
     _(AbsI)                         \
     _(AbsD)                         \
     _(SqrtD)                        \
     _(Atan2D)                       \
     _(PowI)                         \
     _(PowD)                         \
     _(Random)                       \
     _(MathFunctionD)                \
+    _(MathFunctionF)                \
     _(NotI)                         \
     _(NotD)                         \
     _(NotO)                         \
     _(NotV)                         \
     _(AddI)                         \
     _(SubI)                         \
     _(MulI)                         \
     _(MathD)                        \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1209,21 +1209,28 @@ LIRGenerator::visitRandom(MRandom *ins)
 {
     LRandom *lir = new LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
     return defineReturn(lir, ins);
 }
 
 bool
 LIRGenerator::visitMathFunction(MMathFunction *ins)
 {
-    JS_ASSERT(ins->type() == MIRType_Double);
-    JS_ASSERT(ins->input()->type() == MIRType_Double);
-
-    // Note: useRegisterAtStart is safe here, the temp is not a FP register.
-    LMathFunctionD *lir = new LMathFunctionD(useRegisterAtStart(ins->input()),
+    JS_ASSERT(IsFloatingPointType(ins->type()));
+    JS_ASSERT_IF(ins->type() == MIRType_Double, ins->input()->type() == MIRType_Double);
+    JS_ASSERT_IF(ins->type() == MIRType_Float32, ins->input()->type() == MIRType_Float32);
+
+    if (ins->type() == MIRType_Double) {
+        // Note: useRegisterAtStart is safe here, the temp is not a FP register.
+        LMathFunctionD *lir = new LMathFunctionD(useRegisterAtStart(ins->input()),
+                                                 tempFixed(CallTempReg0));
+        return defineReturn(lir, ins);
+    }
+
+    LMathFunctionF *lir = new LMathFunctionF(useRegisterAtStart(ins->input()),
                                              tempFixed(CallTempReg0));
     return defineReturn(lir, ins);
 }
 
 // Try to mark an add or sub instruction as able to recover its input when
 // bailing out.
 template <typename S, typename T>
 static void
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1371,16 +1371,29 @@ MMod::foldsTo(bool useValueNumbers)
 }
 
 bool
 MMod::fallible()
 {
     return !isTruncated();
 }
 
+void
+MMathFunction::trySpecializeFloat32()
+{
+    if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
+        if (input()->type() == MIRType_Float32)
+            ConvertDefinitionToDouble<0>(input(), this);
+        return;
+    }
+
+    setResultType(MIRType_Float32);
+    setPolicyType(MIRType_Float32);
+}
+
 bool
 MAdd::fallible()
 {
     // the add is fallible if range analysis does not say that it is finite, AND
     // either the truncation analysis shows that there are non-truncated uses.
     if (isTruncated())
         return false;
     if (range() && range()->hasInt32Bounds())
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3592,17 +3592,17 @@ class MRandom : public MNullaryInstructi
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
 class MMathFunction
   : public MUnaryInstruction,
-    public DoublePolicy<0>
+    public FloatingPointPolicy<0>
 {
   public:
     enum Function {
         Log,
         Sin,
         Cos,
         Exp,
         Tan,
@@ -3629,16 +3629,17 @@ class MMathFunction
   private:
     Function function_;
     MathCache *cache_;
 
     MMathFunction(MDefinition *input, Function function, MathCache *cache)
       : MUnaryInstruction(input), function_(function), cache_(cache)
     {
         setResultType(MIRType_Double);
+        setPolicyType(MIRType_Double);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(MathFunction)
 
     // A nullptr cache means this function will neither access nor update the cache.
     static MMathFunction *New(MDefinition *input, Function function, MathCache *cache) {
@@ -3667,16 +3668,23 @@ class MMathFunction
 
     bool possiblyCalls() const {
         return true;
     }
 
     void printOpcode(FILE *fp) const;
 
     static const char *FunctionName(Function function);
+
+    bool isFloat32Commutative() const {
+        return function_ == Log || function_ == Sin || function_ == Cos
+               || function_ == Exp || function_ == Tan || function_ == ATan
+               || function_ == ASin || function_ == ACos;
+    }
+    void trySpecializeFloat32();
 };
 
 class MAdd : public MBinaryArithInstruction
 {
     // Is this instruction really an int at heart?
     MAdd(MDefinition *left, MDefinition *right)
       : MBinaryArithInstruction(left, right)
     {
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -154,17 +154,17 @@ class Float32Policy : public BoxInputsPo
     bool adjustInputs(MInstruction *def) {
         return staticAdjustInputs(def);
     }
 };
 
 // Expect a float32 OR a double for operand Op, but will prioritize Float32
 // if the result type is set as such. If the input is a Value, it is unboxed.
 template <unsigned Op>
-class RuntimePolicy : public TypePolicy
+class FloatingPointPolicy : public TypePolicy
 {
     MIRType policyType_;
 
   public:
     bool adjustInputs(MInstruction *def) {
         if (policyType_ == MIRType_Double)
             return DoublePolicy<Op>::staticAdjustInputs(def);
         return Float32Policy<Op>::staticAdjustInputs(def);