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