Author: Carl Friedrich Bolz-Tereick <cfb...@gmx.de>
Branch: intbound-improvements
Changeset: r93251:2ecf080bbdb4
Date: 2017-12-02 22:32 +0100
http://bitbucket.org/pypy/pypy/changeset/2ecf080bbdb4/

Log:    improve the bounds computation of modulo

diff --git a/rpython/jit/metainterp/optimizeopt/intutils.py 
b/rpython/jit/metainterp/optimizeopt/intutils.py
--- a/rpython/jit/metainterp/optimizeopt/intutils.py
+++ b/rpython/jit/metainterp/optimizeopt/intutils.py
@@ -210,14 +210,26 @@
 
     def mod_bound(self, other):
         r = IntUnbounded()
-        if other.is_constant():
-            val = other.getint()
-            if val >= 0:        # with Python's modulo:  0 <= (x % pos) < pos
-                r.make_ge(IntBound(0, 0))
-                r.make_lt(IntBound(val, val))
-            else:               # with Python's modulo:  neg < (x % neg) <= 0
-                r.make_gt(IntBound(val, val))
-                r.make_le(IntBound(0, 0))
+        if not other.has_upper and not other.has_lower:
+            return r # nothing known about other
+        if other.known_nonnegative():
+            # with Python's modulo:  0 <= (x % pos) < pos
+            r.make_ge(IntBound(0, 0))
+            if other.has_upper:
+                r.make_lt(IntBound(other.upper, other.upper))
+        elif other.has_upper and other.upper <= 0:
+            # with Python's modulo:  neg < (x % neg) <= 0
+            r.make_le(IntBound(0, 0))
+            if other.has_lower:
+                r.make_gt(IntBound(other.lower, other.lower))
+        else:
+            # the interval straddles 0, so we know this:
+            # other.lower < x % other < other.upper
+            if other.has_upper:
+                r.make_lt(IntBound(other.upper, other.upper))
+            if other.has_lower:
+                r.make_gt(IntBound(other.lower, other.lower))
+            pass
         return r
 
     def lshift_bound(self, other):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_intbound.py 
b/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
@@ -5,7 +5,7 @@
 import sys
 from rpython.rlib.rarithmetic import LONG_BIT, ovfcheck
 
-from hypothesis import given, strategies
+from hypothesis import given, strategies, settings
 
 special_values = (
     range(-100, 100) +
@@ -23,7 +23,7 @@
 ints = strategies.builds(
     int, # strategies.integers sometimes returns a long?
     special_values | strategies.integers(
-    min_value=int(-sys.maxint-1), max_value=sys.maxint))
+        min_value=int(-sys.maxint-1), max_value=sys.maxint))
 
 ints_or_none = strategies.none() | ints
 
@@ -39,7 +39,7 @@
         return IntBound(a, b)
 
 def const(a):
-    return bound(a,a)
+    return bound(a, a)
 
 
 def build_bound_with_contained_number(a, b, c):
@@ -335,6 +335,67 @@
                         if n2 != 0:
                             assert b3.contains(n1 % n2)   # Python-style div
 
+def test_mod_bound_explicit():
+    # % positive
+    a = bound(1, 5).mod_bound(bound(1, 5))
+    assert a.contains(0)
+    assert a.contains(4)
+    assert not a.contains(-1)
+    assert not a.contains(5)
+
+    a = bound(1, 5).mod_bound(bound(1, None))
+    assert a.contains(0)
+    assert a.contains(4)
+    assert not a.contains(-1)
+    assert a.contains(100000)
+
+    # % negative
+    a = bound(1, 5).mod_bound(bound(-6, -1))
+    assert a.contains(0)
+    assert a.contains(-5)
+    assert not a.contains(-6)
+    assert not a.contains(1)
+
+    a = bound(1, 5).mod_bound(bound(None, -1))
+    assert a.contains(0)
+    assert a.contains(-5)
+    assert a.contains(-60000)
+    assert not a.contains(1)
+
+    # % neither
+    a = bound(1, 5).mod_bound(bound(-6, 10))
+    assert a.contains(0)
+    assert a.contains(-5)
+    assert a.contains(9)
+    assert not a.contains(-6)
+    assert not a.contains(10)
+
+    a = bound(1, 5).mod_bound(bound(None, 5))
+    assert a.contains(0)
+    assert a.contains(4)
+    assert a.contains(-5)
+    assert a.contains(-60000)
+    assert not a.contains(5)
+
+    a = bound(1, 5).mod_bound(bound(None, 0))
+    assert a.contains(0)
+    assert a.contains(-5)
+    assert a.contains(-60000)
+    assert not a.contains(1)
+
+    a = bound(1, 5).mod_bound(bound(-4, None))
+    assert a.contains(0)
+    assert a.contains(-3)
+    assert a.contains(60000)
+    assert not a.contains(-4)
+
+    a = bound(1, 5).mod_bound(bound(0, None))
+    assert a.contains(0)
+    assert a.contains(5)
+    assert a.contains(60000)
+    assert not a.contains(-1)
+
+
 def test_sub_bound():
     for _, _, b1 in some_bounds():
         for _, _, b2 in some_bounds():
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to