Optimize ECMA double to int32 conversion path (patch by mohammad.r.haghighat@intel.com, r=dvander).
authorAndreas Gal <gal@mozilla.com>
Fri, 12 Jun 2009 15:18:10 -0700
changeset 29357 319361b182898684775e8d8fe7227fde4a0af957
parent 29356 9b0e68c238ebb4805d51eda892230c86289d9ed8
child 29358 a30e21c74d2da17f609a133e18b2da208b468161
push idunknown
push userunknown
push dateunknown
reviewersdvander
milestone1.9.2a1pre
Optimize ECMA double to int32 conversion path (patch by mohammad.r.haghighat@intel.com, r=dvander).
js/src/jsnum.cpp
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -960,34 +960,118 @@ js_ValueToECMAInt32(JSContext *cx, jsval
         d = js_ValueToNumber(cx, vp);
         if (JSVAL_IS_NULL(*vp))
             return 0;
         *vp = JSVAL_TRUE;
     }
     return js_DoubleToECMAInt32(d);
 }
 
+/*
+ * From the ES3 spec, 9.5
+ *  2.  If Result(1) is NaN, +0, -0, +Inf, or -Inf, return +0.
+ *  3.  Compute sign(Result(1)) * floor(abs(Result(1))).
+ *  4.  Compute Result(3) modulo 2^32; that is, a finite integer value k of Number
+ *      type with positive sign and less than 2^32 in magnitude such the mathematical
+ *      difference of Result(3) and k is mathematically an integer multiple of 2^32.
+ *  5.  If Result(4) is greater than or equal to 2^31, return Result(4)- 2^32,
+ *  otherwise return Result(4).
+ */
 int32
 js_DoubleToECMAInt32(jsdouble d)
 {
+#ifdef __i386__
+    jsdpun du, duh, two32;
+    uint32 di_h, u_tmp, expon, shift_amount;
+    int32 mask32;
+
+    /*
+     * Algorithm Outline
+     *  Step 1. If d is NaN, +/-Inf or |d|>=2^84 or |d|<1, then return 0
+     *          All of this is implemented based on an exponent comparison.
+     *  Step 2. If |d|<2^31, then return (int)d
+     *          The cast to integer (conversion in RZ mode) returns the correct result.
+     *  Step 3. If |d|>=2^32, d:=fmod(d, 2^32) is taken  -- but without a call
+     *  Step 4. If |d|>=2^31, then the fractional bits are cleared before
+     *          applying the correction by 2^32:  d - sign(d)*2^32
+     *  Step 5. Return (int)d
+     */
+
+    du.d = d;
+    di_h = du.s.hi;
+
+    u_tmp = (di_h & 0x7ff00000) - 0x3ff00000;
+    if (u_tmp >= (0x45300000-0x3ff00000)) {
+        // d is Nan, +/-Inf or +/-0, or |d|>=2^(32+52) or |d|<1, in which case result=0
+        return 0;
+    }
+
+    if (u_tmp < 0x01f00000) {
+        // |d|<2^31
+        return int32_t(d);
+    }
+
+    if (u_tmp > 0x01f00000) {
+        // |d|>=2^32
+        expon = u_tmp >> 20;
+        shift_amount = expon - 21;
+        duh.u64 = du.u64;
+        mask32 = 0x80000000;
+        if (shift_amount < 32) {
+            mask32 >>= shift_amount;
+            duh.s.hi = du.s.hi & mask32;
+            duh.s.lo = 0;
+        } else {
+            mask32 >>= (shift_amount-32);
+            duh.s.hi = du.s.hi;
+            duh.s.lo = du.s.lo & mask32;
+        }
+        du.d -= duh.d;
+    }
+
+    di_h = du.s.hi;
+
+    // eliminate fractional bits
+    u_tmp = (di_h & 0x7ff00000);
+    if (u_tmp >= 0x41e00000) {
+        // |d|>=2^31
+        expon = u_tmp >> 20;
+        shift_amount = expon - (0x3ff - 11);
+        mask32 = 0x80000000;
+        if (shift_amount < 32) {
+            mask32 >>= shift_amount;
+            du.s.hi &= mask32;
+            du.s.lo = 0;
+        } else {
+            mask32 >>= (shift_amount-32);
+            du.s.lo &= mask32;
+        }
+        two32.s.hi = 0x41f00000 ^ (du.s.hi & 0x80000000);
+        two32.s.lo = 0;
+        du.d -= two32.d;
+    }
+
+    return int32(du.d);
+#else
     int32 i;
     jsdouble two32, two31;
 
     if (!JSDOUBLE_IS_FINITE(d))
         return 0;
 
     i = (int32) d;
     if ((jsdouble) i == d)
         return i;
 
     two32 = 4294967296.0;
     two31 = 2147483648.0;
     d = fmod(d, two32);
     d = (d >= 0) ? floor(d) : ceil(d) + two32;
     return (int32) (d >= two31 ? d - two32 : d);
+#endif
 }
 
 uint32
 js_ValueToECMAUint32(JSContext *cx, jsval *vp)
 {
     jsval v;
     jsint i;
     jsdouble d;