Bug 897747 - IonMonkey: Fix range analysis for MMod. r=waldo
authorDan Gohman <sunfish@google.com>
Thu, 25 Jul 2013 19:09:50 -0700
changeset 152378 5d14c20ba495ea2be332cca9bdf49d18bd0d1edd
parent 152377 0cd7bded61f6e6d588d28b34822ae4897ac9e3c0
child 152379 1c4f2677e2eb4a4a6851b3c580ec32a7ccac5624
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)
reviewerswaldo
bugs897747
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 897747 - IonMonkey: Fix range analysis for MMod. r=waldo
js/src/ion/RangeAnalysis.cpp
js/src/jit-test/tests/ion/bug897747.js
--- a/js/src/ion/RangeAnalysis.cpp
+++ b/js/src/ion/RangeAnalysis.cpp
@@ -1057,26 +1057,44 @@ MMul::computeRange()
 void
 MMod::computeRange()
 {
     if (specialization() != MIRType_Int32 && specialization() != MIRType_Double)
         return;
     Range lhs(getOperand(0));
     Range rhs(getOperand(1));
 
-    // Infinite % x is NaN
-    if (lhs.isInfinite())
+    // If either operand is a NaN, the result is NaN. This also conservatively
+    // handles Infinity cases.
+    if (lhs.isInfinite() || rhs.isInfinite())
         return;
 
+    // Math.abs(lhs % rhs) == Math.abs(lhs) % Math.abs(rhs).
+    // First, the absolute value of the result will always be less than the
+    // absolute value of rhs. (And if rhs is zero, the result is NaN).
     int64_t a = Abs<int64_t>(rhs.lower());
     int64_t b = Abs<int64_t>(rhs.upper());
     if (a == 0 && b == 0)
         return;
-    int64_t bound = Max(1-a, b-1);
-    setRange(new Range(-bound, bound, lhs.isDecimal() || rhs.isDecimal()));
+    int64_t rhsAbsBound = Max(a-1, b-1);
+
+    // Next, the absolute value of the result will never be greater than the
+    // absolute value of lhs.
+    int64_t lhsAbsBound = Max(Abs<int64_t>(lhs.lower()), Abs<int64_t>(lhs.upper()));
+
+    // This gives us two upper bounds, so we can take the best one.
+    int64_t absBound = Min(lhsAbsBound, rhsAbsBound);
+
+    // Now consider the sign of the result.
+    // If lhs is non-negative, the result will be non-negative.
+    // If lhs is non-positive, the result will be non-positive.
+    int64_t lower = lhs.lower() >= 0 ? 0 : -absBound;
+    int64_t upper = lhs.upper() <= 0 ? 0 : absBound;
+
+    setRange(new Range(lower, upper, lhs.isDecimal() || rhs.isDecimal()));
 }
 
 void
 MToDouble::computeRange()
 {
     setRange(new Range(getOperand(0)));
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug897747.js
@@ -0,0 +1,6 @@
+function f(z)
+{
+  return (((0x80000000 | 0) % (0x80000001 | z)) | 0) % 100000
+}
+assertEq(f(0), -1);
+assertEq(f(0), -1);