Bug 894786 - Part 2: Work around the lack of unsigned representation. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Wed, 24 Jul 2013 10:46:39 -0700
changeset 152157 68e224769eb123528f2a2ca7bc086143bc09d54d
parent 152156 6aa9971523fc21ad1267a9e3bfc7c911c3de8f97
child 152158 3b36617ed67cdc31401819f4c97f56683a7e1ab5
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs894786
milestone25.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 894786 - Part 2: Work around the lack of unsigned representation. r=jandem
js/src/ion/RangeAnalysis.cpp
js/src/ion/RangeAnalysis.h
js/src/jit-test/tests/ion/bug894786-2.js
js/src/jit-test/tests/ion/bug894786.js
--- a/js/src/ion/RangeAnalysis.cpp
+++ b/js/src/ion/RangeAnalysis.cpp
@@ -971,21 +971,24 @@ MUrsh::computeRange()
 {
     Range left(getOperand(0));
     Range right(getOperand(1));
 
     MDefinition *rhs = getOperand(1);
     if (!rhs->isConstant()) {
         right.wrapAroundToShiftCount();
         setRange(Range::ursh(&left, &right));
-        return;
+    } else {
+        int32_t c = rhs->toConstant()->value().toInt32();
+        setRange(Range::ursh(&left, c));
     }
 
-    int32_t c = rhs->toConstant()->value().toInt32();
-    setRange(Range::ursh(&left, c));
+    JS_ASSERT(range()->lower() >= 0);
+    if (type() == MIRType_Int32 && range()->isUpperInfinite())
+        range()->extendUInt32ToInt32Min();
 }
 
 void
 MAbs::computeRange()
 {
     if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double)
         return;
 
@@ -1111,18 +1114,21 @@ static Range *GetTypedArrayRange(int typ
     }
 
   return NULL;
 }
 
 void
 MLoadTypedArrayElement::computeRange()
 {
-    if (Range *range = GetTypedArrayRange(arrayType()))
+    if (Range *range = GetTypedArrayRange(arrayType())) {
+        if (type() == MIRType_Int32 && range->isUpperInfinite())
+            range->extendUInt32ToInt32Min();
         setRange(range);
+    }
 }
 
 void
 MLoadTypedArrayElementStatic::computeRange()
 {
     if (Range *range = GetTypedArrayRange(typedArray_->type()))
         setRange(range);
 }
--- a/js/src/ion/RangeAnalysis.h
+++ b/js/src/ion/RangeAnalysis.h
@@ -349,16 +349,24 @@ class Range : public TempObject {
     // If this range exceeds [0, 32) range, at either or both ends, change
     // it to the [0, 32) range.  Otherwise do nothing.
     void wrapAroundToShiftCount();
 
     // If this range exceeds [0, 1] range, at either or both ends, change
     // it to the [0, 1] range.  Otherwise do nothing.
     void wrapAroundToBoolean();
 
+    // As we lack support of MIRType_UInt32, we need to work around the int32
+    // representation by doing an overflow while keeping the upper infinity to
+    // repesent the fact that the value might reach bigger numbers.
+    void extendUInt32ToInt32Min() {
+        JS_ASSERT(isUpperInfinite());
+        lower_ = JSVAL_INT_MIN;
+    }
+
     // Set the exponent by using the precise range analysis on the full
     // range of Int32 values. This might shrink the exponent after some
     // operations.
     //
     // Note:
     //     exponent of JSVAL_INT_MIN == 32
     //     exponent of JSVAL_INT_MAX == 31
     inline void rectifyExponent() {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug894786-2.js
@@ -0,0 +1,91 @@
+
+function f56(x) {
+  var a = x >>> 0; // Range = [0 .. UINT32_MAX] (bits = 32)
+  var b = 0x800000; // == 2^23 (bits = 24)
+  if (a > 0) {
+    // Beta node: Range [1 .. UINT32_MAX] (bits = 32)
+    var c = a * b; // Range = [0 .. +inf] (bits = a.bits + b.bits - 1 = 55)
+    var d = c + 1; // Range = [0 .. +inf] (bits = c.bits + 1 = 56)
+    return (d | 0) & 1;
+  } else {
+    return 1;
+  }
+}
+
+function f55(x) {
+  var a = x >>> 0; // Range = [0 .. UINT32_MAX] (bits = 32)
+  var b = 0x400000; // == 2^22 (bits = 23)
+  if (a > 0) {
+    // Beta node: Range [1 .. UINT32_MAX] (bits = 32)
+    var c = a * b; // Range = [0 .. +inf] (bits = a.bits + b.bits - 1 = 54)
+    var d = c + 1; // Range = [0 .. +inf] (bits = c.bits + 1 = 55)
+    return (d | 0) & 1;
+  } else {
+    return 1;
+  }
+}
+
+// Still returns 1, because the top-level bit is not represented.
+function f54(x) {
+  var a = x >>> 0; // Range = [0 .. UINT32_MAX] (bits = 32)
+  var b = 0x200000; // == 2^21 (bits = 22)
+  if (a > 0) {
+    // Beta node: Range [1 .. UINT32_MAX] (bits = 32)
+    var c = a * b; // Range = [0 .. +inf] (bits = a.bits + b.bits - 1 = 53)
+    var d = c + 1; // Range = [1 .. +inf] (bits = c.bits + 1 = 54)
+    return (d | 0) & 1;
+  } else {
+    return 1;
+  }
+}
+
+// Can safely truncate after these operations. (the mantissa has 53 bits)
+function f53(x) {
+  var a = x >>> 0; // Range = [0 .. UINT32_MAX] (bits = 32)
+  var b = 0x100000; // == 2^20 (bits = 21)
+  if (a > 0) {
+    // Beta node: Range [1 .. UINT32_MAX] (bits = 32)
+    var c = a * b; // Range = [0 .. +inf] (bits = a.bits + b.bits - 1 = 52)
+    var d = c + 1; // Range = [1 .. +inf] (bits = c.bits + 1 = 53)
+    return (d | 0) & 1;
+  } else {
+    return 1;
+  }
+}
+
+function f52(x) {
+  var a = x >>> 0; // Range = [0 .. UINT32_MAX] (bits = 32)
+  var b = 0x80000; // == 2^19 (bits = 20)
+  if (a > 0) {
+    // Beta node: Range [1 .. UINT32_MAX] (bits = 32)
+    var c = a * b; // Range = [0 .. +inf] (bits = a.bits + b.bits - 1 = 51)
+    var d = c + 1; // Range = [1 .. +inf] (bits = c.bits + 1 = 52)
+    return (d | 0) & 1;
+  } else {
+    return 1;
+  }
+}
+
+function f51(x) {
+  var a = x >>> 0; // Range = [0 .. UINT32_MAX] (bits = 32)
+  var b = 0x40000; // == 2^18 (bits = 19)
+  if (a > 0) {
+    // Beta node: Range [1 .. UINT32_MAX] (bits = 32)
+    var c = a * b; // Range = [0 .. +inf] (bits = a.bits + b.bits - 1 = 50)
+    var d = c + 1; // Range = [1 .. +inf] (bits = c.bits + 1 = 51)
+    return (d | 0) & 1;
+  } else {
+    return 1;
+  }
+}
+
+var e = Math.pow(2, 32);
+for (var i = 1; i < e; i = i * 1.5) {
+    var x = i >>> 0;
+    assertEq(f56(x) , (x >= Math.pow(2, 30)) ? 0 : 1);
+    assertEq(f55(x), (x >= Math.pow(2, 31)) ? 0 : 1);
+    assertEq(f54(x), 1);
+    assertEq(f53(x), 1);
+    assertEq(f52(x), 1);
+    assertEq(f51(x), 1);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug894786.js
@@ -0,0 +1,9 @@
+(function() {
+  "use asm";
+  function f(z)
+  {
+    z = z|0;
+    return (((0xc0000000 >>> z) >> 0) % -1)|0;
+  }
+  return f;
+})()(0);