[pypy-svn] pypy default: intbound support for shift operations
hakanardo
commits-noreply at bitbucket.org
Thu Jan 6 17:54:05 CET 2011
Author: Hakan Ardo <hakan at debian.org>
Branch:
Changeset: r40418:1806b0bb68fe
Date: 2011-01-06 17:51 +0100
http://bitbucket.org/pypy/pypy/changeset/1806b0bb68fe/
Log: intbound support for shift operations
diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py
--- a/pypy/module/pypyjit/test/test_pypy_c.py
+++ b/pypy/module/pypyjit/test/test_pypy_c.py
@@ -82,6 +82,8 @@
def run_source(self, source, expected_max_ops, *testcases, **kwds):
assert isinstance(expected_max_ops, int)
threshold = kwds.pop('threshold', 3)
+ self.count_debug_merge_point = \
+ kwds.pop('count_debug_merge_point', True)
if kwds:
raise TypeError, 'Unsupported keyword arguments: %s' % kwds.keys()
source = py.code.Source(source)
@@ -154,14 +156,16 @@
sliced_loops = [] # contains all bytecodes of all loops
total_ops = 0
for loop in loops:
- total_ops += len(loop.operations)
for op in loop.operations:
if op.getopname() == "debug_merge_point":
sliced_loop = BytecodeTrace()
sliced_loop.bytecode = op.getarg(0)._get_str().rsplit(" ", 1)[1]
sliced_loops.append(sliced_loop)
+ if self.count_debug_merge_point:
+ total_ops += 1
else:
sliced_loop.append(op)
+ total_ops += 1
return loops, sliced_loops, total_ops
def check_0_op_bytecodes(self):
@@ -1328,10 +1332,7 @@
r = 2000
else:
r = 0
- if a > 0 and b > 1:
- ops = 0
- else:
- ops = 0
+ ops = 46
self.run_source('''
def main(a, b):
@@ -1347,6 +1348,37 @@
return sa
''', ops, ([a, b], r))
+ def test_shift(self):
+ from sys import maxint
+ maxvals = (-maxint-1, -maxint, maxint-1, maxint)
+ for a in (-4, -3, -2, -1, 0, 1, 2, 3, 4) + maxvals:
+ for b in (0, 1, 2, 31, 32, 33, 61, 62, 63):
+ r = 0
+ if (a >> b) >= 0:
+ r += 2000
+ if (a << b) > 2:
+ r += 20000000
+ if abs(a) < 10 and b < 5:
+ ops = 13
+ else:
+ ops = 29
+
+ self.run_source('''
+ def main(a, b):
+ i = sa = 0
+ while i < 2000:
+ if a > 0: # Specialises the loop
+ pass
+ if b < 2 and b > 0:
+ pass
+ if (a >> b) >= 0:
+ sa += 1
+ if (a << b) > 2:
+ sa += 10000
+ i += 1
+ return sa
+ ''', ops, ([a, b], r), count_debug_merge_point=False)
+
class AppTestJIT(PyPyCJITTests):
def setup_class(cls):
diff --git a/pypy/jit/metainterp/test/test_intbound.py b/pypy/jit/metainterp/test/test_intbound.py
--- a/pypy/jit/metainterp/test/test_intbound.py
+++ b/pypy/jit/metainterp/test/test_intbound.py
@@ -210,6 +210,17 @@
assert not a.contains(4)
assert not a.contains(-3)
+def test_shift_bound():
+ for _, _, b1 in some_bounds():
+ for _, _, b2 in some_bounds():
+ bleft = b1.lshift_bound(b2)
+ bright = b1.rshift_bound(b2)
+ for n1 in nbr:
+ for n2 in range(10):
+ if b1.contains(n1) and b2.contains(n2):
+ assert bleft.contains(n1 << n2)
+ assert bright.contains(n1 >> n2)
+
def test_div_bound():
for _, _, b1 in some_bounds():
for _, _, b2 in some_bounds():
diff --git a/pypy/module/pypyjit/test/randomized.py b/pypy/module/pypyjit/test/randomized.py
--- a/pypy/module/pypyjit/test/randomized.py
+++ b/pypy/module/pypyjit/test/randomized.py
@@ -32,8 +32,12 @@
' ' + self.expression()
def test(self):
- return self.expression() + ' ' + self.sample(self.tests) + \
- ' ' + self.expression()
+ tst = self.sample(self.tests)
+ if tst:
+ return self.expression() + ' ' + tst + \
+ ' ' + self.expression()
+ else:
+ return self.expression()
def constant(self):
return str(self.sample(self.constants))
@@ -81,9 +85,9 @@
class IntBounds(RandomCode):
- opperators = ('+', '-', '*')
- tests = ('<', '>', '<=', '>=', '==', '!=')
- constants = range(-3,4)
+ opperators = ('+', '-', '*', '/', '>>', '<<')
+ tests = ('<', '>', '<=', '>=', '==', '!=', None)
+ constants = range(-3,4)
varnames = 'abcd'
def function(self, name='f'):
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -4188,6 +4188,148 @@
"""
py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+ def test_bound_lshift(self):
+ ops = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_lshift(i1, i3)
+ i8 = int_le(i7, 14)
+ guard_true(i8) []
+ i8b = int_lshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_lshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i12 = int_lt(i0, 15)
+ guard_true(i12) []
+ i13 = int_lshift(i1b, i3)
+ i14 = int_le(i13, 14)
+ guard_true(i14) []
+ i15 = int_lshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ preamble = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_lshift(i1, i3)
+ i8 = int_le(i7, 14)
+ guard_true(i8) []
+ i8b = int_lshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_lshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i13 = int_lshift(i1b, i3)
+ i15 = int_lshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ expected = """
+ [i0, i1, i1b, i2, i3]
+ jump(i0, i1, i1b, i2, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_bound_rshift(self):
+ ops = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_rshift(i1, i3)
+ i8 = int_le(i7, 14)
+ guard_true(i8) []
+ i8b = int_rshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_rshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i12 = int_lt(i0, 25)
+ guard_true(i12) []
+ i13 = int_rshift(i1b, i3)
+ i14 = int_le(i13, 14)
+ guard_true(i14) []
+ i15 = int_rshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ preamble = """
+ [i0, i1, i1b, i2, i3]
+ i4 = int_lt(i1, 7)
+ guard_true(i4) []
+ i4b = int_lt(i1b, 7)
+ guard_true(i4b) []
+ i4c = int_ge(i1b, 0)
+ guard_true(i4c) []
+ i5 = int_lt(i3, 2)
+ guard_true(i5) []
+ i6 = int_ge(i3, 0)
+ guard_true(i6) []
+ i7 = int_rshift(i1, i3)
+ i8b = int_rshift(i1, i2)
+ i9 = int_le(i8b, 14)
+ guard_true(i9) []
+ i10 = int_rshift(i0, i3)
+ i11 = int_le(i10, 14)
+ guard_true(i11) []
+ i12 = int_lt(i0, 25)
+ guard_true(i12) []
+ i13 = int_rshift(i1b, i3)
+ i15 = int_rshift(i1b, i2)
+ i16 = int_le(i15, 14)
+ guard_true(i16) []
+ jump(i0, i1, i1b, i2, i3)
+ """
+ expected = """
+ [i0, i1, i1b, i2, i3]
+ jump(i0, i1, i1b, i2, i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_bound_dont_backpropagate_rshift(self):
+ ops = """
+ [i0]
+ i3 = int_rshift(i0, 1)
+ i5 = int_eq(i3, 1)
+ guard_true(i5) []
+ i11 = int_add(i0, 1)
+ jump(i11)
+ """
+ self.optimize_loop(ops, ops, ops)
+
+
def test_mul_ovf(self):
ops = """
[i0, i1]
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -117,6 +117,20 @@
r = self.getvalue(op.result)
r.intbound.intersect(v1.intbound.div_bound(v2.intbound))
+ def optimize_INT_LSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+ self.emit_operation(op)
+ r = self.getvalue(op.result)
+ r.intbound.intersect(v1.intbound.lshift_bound(v2.intbound))
+
+ def optimize_INT_RSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+ self.emit_operation(op)
+ r = self.getvalue(op.result)
+ r.intbound.intersect(v1.intbound.rshift_bound(v2.intbound))
+
def optimize_INT_ADD_OVF(self, op):
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
@@ -339,6 +353,14 @@
if v2.intbound.intersect(b):
self.propagate_bounds_backward(op.getarg(1))
+ def propagate_bounds_INT_LSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+ r = self.getvalue(op.result)
+ b = r.intbound.rshift_bound(v2.intbound)
+ if v1.intbound.intersect(b):
+ self.propagate_bounds_backward(op.getarg(0))
+
propagate_bounds_INT_ADD_OVF = propagate_bounds_INT_ADD
propagate_bounds_INT_SUB_OVF = propagate_bounds_INT_SUB
propagate_bounds_INT_MUL_OVF = propagate_bounds_INT_MUL
diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py
--- a/pypy/jit/metainterp/optimizeopt/intutils.py
+++ b/pypy/jit/metainterp/optimizeopt/intutils.py
@@ -155,6 +155,37 @@
else:
return IntUnbounded()
+ def lshift_bound(self, other):
+ if self.has_upper and self.has_lower and \
+ other.has_upper and other.has_lower and \
+ other.known_ge(IntBound(0, 0)):
+ try:
+ vals = (ovfcheck(self.upper * pow2(other.upper)),
+ ovfcheck(self.upper * pow2(other.lower)),
+ ovfcheck(self.lower * pow2(other.upper)),
+ ovfcheck(self.lower * pow2(other.lower)))
+ return IntBound(min4(vals), max4(vals))
+ except OverflowError:
+ return IntUnbounded()
+ else:
+ return IntUnbounded()
+
+ def rshift_bound(self, other):
+ if self.has_upper and self.has_lower and \
+ other.has_upper and other.has_lower and \
+ other.known_ge(IntBound(0, 0)):
+ try:
+ vals = (ovfcheck(self.upper / pow2(other.upper)),
+ ovfcheck(self.upper / pow2(other.lower)),
+ ovfcheck(self.lower / pow2(other.upper)),
+ ovfcheck(self.lower / pow2(other.lower)))
+ return IntBound(min4(vals), max4(vals))
+ except OverflowError:
+ return IntUnbounded()
+ else:
+ return IntUnbounded()
+
+
def contains(self, val):
if self.has_lower and val < self.lower:
return False
@@ -205,3 +236,11 @@
def max4(t):
return max(max(t[0], t[1]), max(t[2], t[3]))
+
+def pow2(x):
+ y = 1 << x
+ if y < 1:
+ raise OverflowError, "pow2 did overflow"
+ return y
+
+
More information about the Pypy-commit
mailing list