Author: Carl Friedrich Bolz-Tereick <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit