Bug 920046 - Specialize Math.round and Math.floor with double return type. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 25 Sep 2013 13:26:59 +0200
changeset 162472 abfcc2be169da91ffe32fc1f867f4879fc75d663
parent 162471 0fae05649fe849dd6277c920c467c8ff0580767d
child 162473 1080eec8fed174da0a0f78b0dd3bad11165846a0
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs920046
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 920046 - Specialize Math.round and Math.floor with double return type. r=bhackett
js/src/jit/AsmJSLink.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.h
js/src/jsinfer.cpp
js/src/jsmath.cpp
js/src/jsmath.h
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -141,18 +141,18 @@ ValidateMathBuiltin(JSContext *cx, AsmJS
     Native native = NULL;
     switch (global.mathBuiltin()) {
       case AsmJSMathBuiltin_sin: native = math_sin; break;
       case AsmJSMathBuiltin_cos: native = math_cos; break;
       case AsmJSMathBuiltin_tan: native = math_tan; break;
       case AsmJSMathBuiltin_asin: native = math_asin; break;
       case AsmJSMathBuiltin_acos: native = math_acos; break;
       case AsmJSMathBuiltin_atan: native = math_atan; break;
-      case AsmJSMathBuiltin_ceil: native = js_math_ceil; break;
-      case AsmJSMathBuiltin_floor: native = js_math_floor; break;
+      case AsmJSMathBuiltin_ceil: native = math_ceil; break;
+      case AsmJSMathBuiltin_floor: native = math_floor; break;
       case AsmJSMathBuiltin_exp: native = math_exp; break;
       case AsmJSMathBuiltin_log: native = math_log; break;
       case AsmJSMathBuiltin_pow: native = js_math_pow; break;
       case AsmJSMathBuiltin_sqrt: native = js_math_sqrt; break;
       case AsmJSMathBuiltin_abs: native = js_math_abs; break;
       case AsmJSMathBuiltin_atan2: native = math_atan2; break;
       case AsmJSMathBuiltin_imul: native = math_imul; break;
     }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3737,19 +3737,21 @@ bool
 CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
 {
     Register temp = ToRegister(ins->temp());
     FloatRegister input = ToFloatRegister(ins->input());
     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
 
     MathCache *mathCache = ins->mir()->cache();
 
-    masm.setupUnalignedABICall(2, temp);
-    masm.movePtr(ImmPtr(mathCache), temp);
-    masm.passABIArg(temp);
+    masm.setupUnalignedABICall(mathCache ? 2 : 1, temp);
+    if (mathCache) {
+        masm.movePtr(ImmPtr(mathCache), temp);
+        masm.passABIArg(temp);
+    }
     masm.passABIArg(input);
 
 #   define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
 
     void *funptr = NULL;
     switch (ins->mir()->function()) {
       case MMathFunction::Log:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log));
@@ -3809,16 +3811,22 @@ CodeGenerator::visitMathFunctionD(LMathF
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sign));
         break;
       case MMathFunction::Trunc:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_trunc));
         break;
       case MMathFunction::Cbrt:
         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cbrt));
         break;
+      case MMathFunction::Floor:
+        funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_floor_impl);
+        break;
+      case MMathFunction::Round:
+        funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl);
+        break;
       default:
         MOZ_ASSUME_UNREACHABLE("Unknown math function");
     }
 
 #   undef MAYBE_CACHED
 
     masm.callWithABI(funptr, MacroAssembler::DOUBLE);
     return true;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -33,19 +33,19 @@ IonBuilder::inlineNativeCall(CallInfo &c
     if (native == js::array_push)
         return inlineArrayPush(callInfo);
     if (native == js::array_concat)
         return inlineArrayConcat(callInfo);
 
     // Math natives.
     if (native == js_math_abs)
         return inlineMathAbs(callInfo);
-    if (native == js_math_floor)
+    if (native == js::math_floor)
         return inlineMathFloor(callInfo);
-    if (native == js_math_round)
+    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)
@@ -568,34 +568,41 @@ IonBuilder::inlineMathFloor(CallInfo &ca
 
     if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
     MIRType argType = callInfo.getArg(0)->type();
-    if (getInlineReturnType() != MIRType_Int32)
-        return InliningStatus_NotInlined;
+    MIRType returnType = getInlineReturnType();
 
     // Math.floor(int(x)) == int(x)
-    if (argType == MIRType_Int32) {
+    if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
         callInfo.unwrapArgs();
         current->push(callInfo.getArg(0));
         return InliningStatus_Inlined;
     }
 
-    if (argType == MIRType_Double) {
+    if (argType == MIRType_Double && returnType == MIRType_Int32) {
         callInfo.unwrapArgs();
         MFloor *ins = new MFloor(callInfo.getArg(0));
         current->add(ins);
         current->push(ins);
         return InliningStatus_Inlined;
     }
 
+    if (argType == MIRType_Double && returnType == MIRType_Double) {
+        callInfo.unwrapArgs();
+        MMathFunction *ins = MMathFunction::New(callInfo.getArg(0), MMathFunction::Floor, nullptr);
+        current->add(ins);
+        current->push(ins);
+        return InliningStatus_Inlined;
+    }
+
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineMathRound(CallInfo &callInfo)
 {
     if (callInfo.constructing())
         return InliningStatus_NotInlined;
@@ -616,16 +623,24 @@ IonBuilder::inlineMathRound(CallInfo &ca
     if (argType == MIRType_Double && returnType == MIRType_Int32) {
         callInfo.unwrapArgs();
         MRound *ins = new MRound(callInfo.getArg(0));
         current->add(ins);
         current->push(ins);
         return InliningStatus_Inlined;
     }
 
+    if (argType == MIRType_Double && returnType == MIRType_Double) {
+        callInfo.unwrapArgs();
+        MMathFunction *ins = MMathFunction::New(callInfo.getArg(0), MMathFunction::Round, nullptr);
+        current->add(ins);
+        current->push(ins);
+        return InliningStatus_Inlined;
+    }
+
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineMathSqrt(CallInfo &callInfo)
 {
     if (callInfo.constructing())
         return InliningStatus_NotInlined;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3596,17 +3596,19 @@ class MMathFunction
         CosH,
         SinH,
         TanH,
         ACosH,
         ASinH,
         ATanH,
         Sign,
         Trunc,
-        Cbrt
+        Cbrt,
+        Floor,
+        Round
     };
 
   private:
     Function function_;
     MathCache *cache_;
 
     MMathFunction(MDefinition *input, Function function, MathCache *cache)
       : MUnaryInstruction(input), function_(function), cache_(cache)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -82,16 +82,18 @@ types::TypeIdStringImpl(jsid id)
     return bufs[which];
 }
 #endif
 
 /////////////////////////////////////////////////////////////////////
 // Logging
 /////////////////////////////////////////////////////////////////////
 
+#ifdef DEBUG
+
 static bool InferSpewActive(SpewChannel channel)
 {
     static bool active[SPEW_COUNT];
     static bool checked = false;
     if (!checked) {
         checked = true;
         PodArrayZero(active);
         const char *env = getenv("INFERFLAGS");
@@ -104,18 +106,16 @@ static bool InferSpewActive(SpewChannel 
         if (strstr(env, "full")) {
             for (unsigned i = 0; i < SPEW_COUNT; i++)
                 active[i] = true;
         }
     }
     return active[channel];
 }
 
-#ifdef DEBUG
-
 static bool InferSpewColorable()
 {
     /* Only spew colors on xterm-color to not screw up emacs. */
     static bool colorable = false;
     static bool checked = false;
     if (!checked) {
         checked = true;
         const char *env = getenv("TERM");
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -303,40 +303,40 @@ js::math_atan2(JSContext *cx, unsigned a
         return false;
 
     double z = ecmaAtan2(x, y);
     args.rval().setDouble(z);
     return true;
 }
 
 double
-js_math_ceil_impl(double x)
+js::math_ceil_impl(double x)
 {
 #ifdef __APPLE__
     if (x < 0 && x > -1.0)
         return js_copysign(0, -1);
 #endif
     return ceil(x);
 }
 
 bool
-js_math_ceil(JSContext *cx, unsigned argc, Value *vp)
+js::math_ceil(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     if (!ToNumber(cx, args[0], &x))
         return false;
 
-    double z = js_math_ceil_impl(x);
+    double z = math_ceil_impl(x);
     args.rval().setNumber(z);
     return true;
 }
 
 double
 js::math_cos_impl(MathCache *cache, double x)
 {
     return cache->lookup(cos, x);
@@ -418,36 +418,36 @@ js::math_exp(JSContext *cx, unsigned arg
         return false;
 
     double z = math_exp_impl(mathCache, x);
     args.rval().setNumber(z);
     return true;
 }
 
 double
-js_math_floor_impl(double x)
+js::math_floor_impl(double x)
 {
     return floor(x);
 }
 
 bool
-js_math_floor(JSContext *cx, unsigned argc, Value *vp)
+js::math_floor(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     if (!ToNumber(cx, args[0], &x))
         return false;
 
-    double z = js_math_floor_impl(x);
+    double z = math_floor_impl(x);
     args.rval().setNumber(z);
     return true;
 }
 
 bool
 js::math_imul(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -765,43 +765,46 @@ bool
 js_math_random(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     double z = random_nextDouble(cx);
     args.rval().setDouble(z);
     return true;
 }
 
+double
+js::math_round_impl(double x)
+{
+    int32_t i;
+    if (DoubleIsInt32(x, &i))
+        return double(i);
+
+    /* Some numbers are so big that adding 0.5 would give the wrong number. */
+    if (ExponentComponent(x) >= 52)
+        return x;
+
+    return js_copysign(floor(x + 0.5), x);
+}
+
 bool /* ES5 15.8.2.15. */
-js_math_round(JSContext *cx, unsigned argc, Value *vp)
+js::math_round(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     double x;
     if (!ToNumber(cx, args[0], &x))
         return false;
 
-    int32_t i;
-    if (DoubleIsInt32(x, &i)) {
-        args.rval().setInt32(i);
-        return true;
-    }
-
-    /* Some numbers are so big that adding 0.5 would give the wrong number. */
-    if (ExponentComponent(x) >= 52) {
-        args.rval().setNumber(x);
-        return true;
-    }
-
-    args.rval().setNumber(js_copysign(floor(x + 0.5), x));
+    double z = math_round_impl(x);
+    args.rval().setNumber(z);
     return true;
 }
 
 double
 js::math_sin_impl(MathCache *cache, double x)
 {
     return cache->lookup(sin, x);
 }
@@ -1435,28 +1438,28 @@ static const JSFunctionSpec math_static_
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  math_toSource,        0, 0),
 #endif
     JS_FN("abs",            js_math_abs,          1, 0),
     JS_FN("acos",           math_acos,            1, 0),
     JS_FN("asin",           math_asin,            1, 0),
     JS_FN("atan",           math_atan,            1, 0),
     JS_FN("atan2",          math_atan2,           2, 0),
-    JS_FN("ceil",           js_math_ceil,         1, 0),
+    JS_FN("ceil",           math_ceil,            1, 0),
     JS_FN("cos",            math_cos,             1, 0),
     JS_FN("exp",            math_exp,             1, 0),
-    JS_FN("floor",          js_math_floor,        1, 0),
+    JS_FN("floor",          math_floor,           1, 0),
     JS_FN("imul",           math_imul,            2, 0),
     JS_FN("fround",         math_fround,          1, 0),
     JS_FN("log",            math_log,             1, 0),
     JS_FN("max",            js_math_max,          2, 0),
     JS_FN("min",            js_math_min,          2, 0),
     JS_FN("pow",            js_math_pow,          2, 0),
     JS_FN("random",         js_math_random,       0, 0),
-    JS_FN("round",          js_math_round,        1, 0),
+    JS_FN("round",          math_round,           1, 0),
     JS_FN("sin",            math_sin,             1, 0),
     JS_FN("sqrt",           js_math_sqrt,         1, 0),
     JS_FN("tan",            math_tan,             1, 0),
     JS_FN("log10",          math_log10,           1, 0),
     JS_FN("log2",           math_log2,            1, 0),
     JS_FN("log1p",          math_log1p,           1, 0),
     JS_FN("expm1",          math_expm1,           1, 0),
     JS_FN("cosh",           math_cosh,            1, 0),
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -63,42 +63,27 @@ math_random_no_outparam(JSContext *cx);
 
 extern bool
 js_math_random(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 js_math_abs(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
-js_math_ceil(JSContext *cx, unsigned argc, js::Value *vp);
-
-extern bool
-js_math_floor(JSContext *cx, unsigned argc, js::Value *vp);
-
-extern bool
 js_math_max(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 js_math_min(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
-js_math_round(JSContext *cx, unsigned argc, js::Value *vp);
-
-extern bool
 js_math_sqrt(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 js_math_pow(JSContext *cx, unsigned argc, js::Value *vp);
 
-extern double
-js_math_ceil_impl(double x);
-
-extern double
-js_math_floor_impl(double x);
-
 namespace js {
 
 extern bool
 math_imul(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 math_fround(JSContext *cx, unsigned argc, js::Value *vp);
 
@@ -229,16 +214,34 @@ extern double
 math_acos_impl(MathCache *cache, double x);
 
 extern double
 math_acos_uncached(double x);
 
 extern bool
 math_acos(JSContext *cx, unsigned argc, js::Value *vp);
 
+extern bool
+math_ceil(JSContext *cx, unsigned argc, Value *vp);
+
+extern double
+math_ceil_impl(double x);
+
+extern bool
+math_floor(JSContext *cx, unsigned argc, Value *vp);
+
+extern double
+math_floor_impl(double x);
+
+extern bool
+math_round(JSContext *cx, unsigned argc, Value *vp);
+
+extern double
+math_round_impl(double x);
+
 extern double
 powi(double x, int y);
 
 extern double
 ecmaPow(double x, double y);
 
 extern bool
 math_imul(JSContext *cx, unsigned argc, Value *vp);