Author: Carl Friedrich Bolz-Tereick <cfb...@gmx.de> Branch: intbound-improvements Changeset: r93252:3485b3be23ea Date: 2017-12-03 11:17 +0100 http://bitbucket.org/pypy/pypy/changeset/3485b3be23ea/
Log: separate implementations of or and xor, improve upper bounds on both diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py --- a/rpython/jit/metainterp/optimizeopt/intbounds.py +++ b/rpython/jit/metainterp/optimizeopt/intbounds.py @@ -62,18 +62,22 @@ postprocess_GUARD_FALSE = _postprocess_guard_true_false_value postprocess_GUARD_VALUE = _postprocess_guard_true_false_value - def optimize_INT_OR_or_XOR(self, op): + def optimize_INT_OR(self, op): v1 = self.get_box_replacement(op.getarg(0)) v2 = self.get_box_replacement(op.getarg(1)) if v1 is v2: - if op.getopnum() == rop.INT_OR: - self.make_equal_to(op, v1) - else: - self.make_constant_int(op, 0) + self.make_equal_to(op, v1) return None return self.emit(op) - def postprocess_INT_OR_or_XOR(self, op): + def optimize_INT_XOR(self, op): + v1 = self.get_box_replacement(op.getarg(0)) + v2 = self.get_box_replacement(op.getarg(1)) + if v1 is v2: + self.make_constant_int(op, 0) + return self.emit(op) + + def postprocess_INT_OR(self, op): v1 = self.get_box_replacement(op.getarg(0)) b1 = self.getintbound(v1) v2 = self.get_box_replacement(op.getarg(1)) @@ -81,11 +85,13 @@ b = b1.or_bound(b2) self.getintbound(op).intersect(b) - optimize_INT_OR = optimize_INT_OR_or_XOR - optimize_INT_XOR = optimize_INT_OR_or_XOR - - postprocess_INT_OR = postprocess_INT_OR_or_XOR - postprocess_INT_XOR = postprocess_INT_OR_or_XOR + def postprocess_INT_XOR(self, op): + v1 = self.get_box_replacement(op.getarg(0)) + b1 = self.getintbound(v1) + v2 = self.get_box_replacement(op.getarg(1)) + b2 = self.getintbound(v2) + b = b1.xor_bound(b2) + self.getintbound(op).intersect(b) def optimize_INT_AND(self, op): return self.emit(op) 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 @@ -1,8 +1,6 @@ import sys from rpython.rlib.rarithmetic import ovfcheck, LONG_BIT, maxint, is_valid_int from rpython.rlib.objectmodel import we_are_translated -from rpython.rtyper.lltypesystem import lltype -from rpython.rtyper.lltypesystem.lloperation import llop from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.metainterp.optimizeopt.info import AbstractInfo, INFO_NONNULL,\ INFO_UNKNOWN, INFO_NULL @@ -25,6 +23,15 @@ n |= n >> 32 return n +def upper_bound_or_xor(upper1, upper2): + pow2 = next_pow2_m1(upper1 | upper2) + try: + # addition gives an ok (but not tight) upper bound of | and ^ + add = ovfcheck(upper1 + upper2) + except OverflowError: + return pow2 + else: + return min(pow2, add) class IntBound(AbstractInfo): _attrs_ = ('has_upper', 'has_lower', 'upper', 'lower') @@ -277,13 +284,27 @@ r = IntUnbounded() if self.known_nonnegative() and \ other.known_nonnegative(): + r.make_ge(IntBound(0, 0)) if self.has_upper and other.has_upper: - mostsignificant = self.upper | other.upper - r.intersect(IntBound(0, next_pow2_m1(mostsignificant))) + r.intersect(IntBound(0, upper_bound_or_xor(self.upper, other.upper))) + if self.has_lower and other.has_lower: + # max of the two lower bounds gives an ok (but not tight) lower + # bound of or + lower = max(self.lower, other.lower) + r.make_ge(IntBound(lower, lower)) + return r + + def xor_bound(self, other): + r = IntUnbounded() + if self.known_nonnegative() and \ + other.known_nonnegative(): + if self.has_upper and other.has_upper: + r.intersect(IntBound(0, upper_bound_or_xor(self.upper, other.upper))) else: r.make_ge(IntBound(0, 0)) return r + def contains(self, val): if not we_are_translated(): assert not isinstance(val, long) 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 @@ -418,6 +418,15 @@ if b1.contains(n1) and b2.contains(n2): assert b3.contains(n1 & n2) +def test_or_bound_explicit(): + a = bound(0b10, 0b100) + b = bound(0, 0b10) + c = a.or_bound(b) + assert c.contains(0b10) + assert c.contains(0b100 | 0b10) + assert not c.contains(1) + assert not c.contains(0b111) + def test_or_bound(): for _, _, b1 in some_bounds(): for _, _, b2 in some_bounds(): @@ -426,7 +435,24 @@ for n2 in nbr: if b1.contains(n1) and b2.contains(n2): assert b3.contains(n1 | n2) - assert b3.contains(n1 ^ n2) # we use it for xor too + +def test_xor_bound_explicit(): + a = bound(0b10, 0b100) + b = bound(0, 0b10) + c = a.or_bound(b) + assert c.contains(0b10) + assert c.contains(0b100 | 0b10) + assert not c.contains(-1) + assert not c.contains(0b111) + +def test_xor_bound(): + for _, _, b1 in some_bounds(): + for _, _, b2 in some_bounds(): + b3 = b1.xor_bound(b2) + for n1 in nbr: + for n2 in nbr: + if b1.contains(n1) and b2.contains(n2): + assert b3.contains(n1 ^ n2) def test_next_pow2_m1(): @@ -515,5 +541,11 @@ b3 = b1.or_bound(b2) r = n1 | n2 assert b3.contains(r) + +@given(bound_with_contained_number, bound_with_contained_number) +def test_xor_bound_random(t1, t2): + b1, n1 = t1 + b2, n2 = t2 + b3 = b1.xor_bound(b2) r = n1 ^ n2 assert b3.contains(r) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit