[pypy-svn] r76717 - in pypy/branch/jit-bounds/pypy: jit/metainterp jit/metainterp/test module/pypyjit/test
hakanardo at codespeak.net
hakanardo at codespeak.net
Tue Aug 24 17:52:16 CEST 2010
Author: hakanardo
Date: Tue Aug 24 17:52:13 2010
New Revision: 76717
Added:
pypy/branch/jit-bounds/pypy/module/pypyjit/test/randomized.py
Modified:
pypy/branch/jit-bounds/pypy/jit/metainterp/optimizeopt.py
pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_intbound.py
pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/branch/jit-bounds/pypy/module/pypyjit/test/test_pypy_c.py
Log:
int_mul and int_ne suppert, randomized tests, more traces
Modified: pypy/branch/jit-bounds/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/jit-bounds/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/branch/jit-bounds/pypy/jit/metainterp/optimizeopt.py Tue Aug 24 17:52:13 2010
@@ -118,6 +118,9 @@
except OverflowError:
res.has_upper = False
return res
+
+ def mul(self, value):
+ return self.mul_bound(IntBound(value, value))
def add_bound(self, other):
res = self.copy()
@@ -155,6 +158,35 @@
res.has_lower = False
return res
+ def mul_bound(self, other):
+ if self.has_upper and self.has_lower and \
+ other.has_upper and other.has_lower:
+ try:
+ vals = (ovfcheck(self.upper * other.upper),
+ ovfcheck(self.upper * other.lower),
+ ovfcheck(self.lower * other.upper),
+ ovfcheck(self.lower * other.lower))
+ return IntBound(min4(vals), max4(vals))
+ except OverflowError:
+ return IntUnbounded()
+ else:
+ return IntUnbounded()
+
+ def div_bound(self, other):
+ if self.has_upper and self.has_lower and \
+ other.has_upper and other.has_lower and \
+ not other.contains(0):
+ try:
+ vals = (ovfcheck(self.upper / other.upper),
+ ovfcheck(self.upper / other.lower),
+ ovfcheck(self.lower / other.upper),
+ ovfcheck(self.lower / 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
@@ -711,6 +743,9 @@
self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
def propagate_bounds_backward(self, box):
+ # FIXME: This takes care of the instruction where box is the reuslt
+ # but the bounds produced by all instructions where box is
+ # an argument might also be tighten
v = self.getvalue(box)
b = v.intbound
if b.has_lower and b.has_upper and b.lower == b.upper:
@@ -817,7 +852,6 @@
oldop = self.pure_operations.get(targs, None)
if oldop is not None and oldop.descr is op.descr:
value = self.getvalue(oldop.result)
- print value
if value.is_constant():
if value.box.same_constant(CONST_1):
self.make_constant(op.result, CONST_0)
@@ -1280,13 +1314,29 @@
self.pure(rop.INT_SUB, [op.result, op.args[1]], op.args[0])
self.pure(rop.INT_SUB, [op.result, op.args[0]], op.args[1])
+ def optimize_INT_MUL(self, op):
+ v1 = self.getvalue(op.args[0])
+ v2 = self.getvalue(op.args[1])
+ # If one side of the op is 0 the result is the other side.
+ if v1.is_constant() and v1.box.getint() == 1:
+ self.make_equal_to(op.result, v2)
+ elif v2.is_constant() and v2.box.getint() == 1:
+ self.make_equal_to(op.result, v1)
+ elif (v1.is_constant() and v1.box.getint() == 0) or \
+ (v2.is_constant() and v2.box.getint() == 0):
+ self.make_constant_int(op.result, 0)
+ else:
+ self.optimize_default(op)
+ r = self.getvalue(op.result)
+ r.intbound.intersect(v1.intbound.mul_bound(v2.intbound))
+
def optimize_INT_ADD_OVF(self, op):
v1 = self.getvalue(op.args[0])
v2 = self.getvalue(op.args[1])
resbound = v1.intbound.add_bound(v2.intbound)
if resbound.has_lower and resbound.has_upper and \
self.loop.operations[self.i+1].opnum == rop.GUARD_NO_OVERFLOW:
- # Transform into INT_SUB and remove guard
+ # Transform into INT_ADD and remove guard
op.opnum = rop.INT_ADD
self.i += 1
self.optimize_INT_ADD(op)
@@ -1310,6 +1360,21 @@
r = self.getvalue(op.result)
r.intbound.intersect(resbound)
+ def optimize_INT_MUL_OVF(self, op):
+ v1 = self.getvalue(op.args[0])
+ v2 = self.getvalue(op.args[1])
+ resbound = v1.intbound.mul_bound(v2.intbound)
+ if resbound.has_lower and resbound.has_upper and \
+ self.loop.operations[self.i+1].opnum == rop.GUARD_NO_OVERFLOW:
+ # Transform into INT_MUL and remove guard
+ op.opnum = rop.INT_MUL
+ self.i += 1
+ self.optimize_INT_MUL(op)
+ else:
+ self.optimize_default(op)
+ r = self.getvalue(op.result)
+ r.intbound.intersect(resbound)
+
def optimize_INT_LT(self, op):
v1 = self.getvalue(op.args[0])
v2 = self.getvalue(op.args[1])
@@ -1360,6 +1425,16 @@
else:
self.optimize_default(op)
+ def optimize_INT_NE(self, op):
+ v1 = self.getvalue(op.args[0])
+ v2 = self.getvalue(op.args[1])
+ if v1.intbound.known_gt(v2.intbound):
+ self.make_constant_int(op.result, 1)
+ elif v1.intbound.known_lt(v2.intbound):
+ self.make_constant_int(op.result, 1)
+ else:
+ self.optimize_default(op)
+
def make_int_lt(self, args):
v1 = self.getvalue(args[0])
v2 = self.getvalue(args[1])
@@ -1426,6 +1501,17 @@
if v2.intbound.intersect(v1.intbound):
self.propagate_bounds_backward(op.args[1])
+ def propagate_bounds_INT_NE(self, op):
+ r = self.getvalue(op.result)
+ if r.is_constant():
+ if r.box.same_constant(CONST_0):
+ v1 = self.getvalue(op.args[0])
+ v2 = self.getvalue(op.args[1])
+ if v1.intbound.intersect(v2.intbound):
+ self.propagate_bounds_backward(op.args[0])
+ if v2.intbound.intersect(v1.intbound):
+ self.propagate_bounds_backward(op.args[1])
+
def propagate_bounds_INT_ADD(self, op):
v1 = self.getvalue(op.args[0])
v2 = self.getvalue(op.args[1])
@@ -1444,12 +1530,24 @@
b = r.intbound.add_bound(v2.intbound)
if v1.intbound.intersect(b):
self.propagate_bounds_backward(op.args[0])
- # FIXME:
- # b = r.intbound.sub_bound(v1.intbound).mul(-1)
- # if v2.intbound.intersect(b):
+ b = r.intbound.sub_bound(v1.intbound).mul(-1)
+ if v2.intbound.intersect(b):
+ self.propagate_bounds_backward(op.args[1])
+
+ def propagate_bounds_INT_MUL(self, op):
+ v1 = self.getvalue(op.args[0])
+ v2 = self.getvalue(op.args[1])
+ r = self.getvalue(op.result)
+ b = r.intbound.div_bound(v2.intbound)
+ if v1.intbound.intersect(b):
+ self.propagate_bounds_backward(op.args[0])
+ b = r.intbound.div_bound(v1.intbound)
+ if v2.intbound.intersect(b):
+ self.propagate_bounds_backward(op.args[1])
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
optimize_ops = _findall(Optimizer, 'optimize_')
propagate_bounds_ops = _findall(Optimizer, 'propagate_bounds_')
@@ -1691,3 +1789,8 @@
write=True)
+def min4(t):
+ return min(min(t[0], t[1]), min(t[2], t[3]))
+
+def max4(t):
+ return max(max(t[0], t[1]), max(t[2], t[3]))
Modified: pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_intbound.py
==============================================================================
--- pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_intbound.py (original)
+++ pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_intbound.py Tue Aug 24 17:52:13 2010
@@ -185,6 +185,53 @@
assert not a.contains(2)
assert not a.contains(7)
+def test_mul_bound():
+ for _, _, b1 in some_bounds():
+ for _, _, b2 in some_bounds():
+ b3 = b1.mul_bound(b2)
+ for n1 in nbr:
+ for n2 in nbr:
+ if b1.contains(n1) and b2.contains(n2):
+ assert b3.contains(n1 * n2)
+
+ a=bound(2, 4).mul_bound(bound(1, 2))
+ assert not a.contains(1)
+ assert not a.contains(9)
+
+ a=bound(-3, 2).mul_bound(bound(1, 2))
+ assert not a.contains(-7)
+ assert not a.contains(5)
+ assert a.contains(-6)
+ assert a.contains(4)
+
+ a=bound(-3, 2).mul(-1)
+ for i in range(-2,4):
+ assert a.contains(i)
+ assert not a.contains(4)
+ assert not a.contains(-3)
+
+def test_div_bound():
+ for _, _, b1 in some_bounds():
+ for _, _, b2 in some_bounds():
+ b3 = b1.div_bound(b2)
+ for n1 in nbr:
+ for n2 in nbr:
+ if b1.contains(n1) and b2.contains(n2):
+ if n2 != 0:
+ assert b3.contains(n1 / n2)
+
+ a=bound(2, 4).div_bound(bound(1, 2))
+ assert not a.contains(0)
+ assert not a.contains(5)
+
+ a=bound(-3, 2).div_bound(bound(1, 2))
+ assert not a.contains(-4)
+ assert not a.contains(3)
+ assert a.contains(-3)
+ assert a.contains(0)
+
+
+
def test_sub_bound():
for _, _, b1 in some_bounds():
for _, _, b2 in some_bounds():
Modified: pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/branch/jit-bounds/pypy/jit/metainterp/test/test_optimizeopt.py Tue Aug 24 17:52:13 2010
@@ -3548,10 +3548,7 @@
guard_no_overflow() []
i2 = int_gt(i1, 1)
guard_true(i2) []
- i3 = int_sub_ovf(1, i0)
- guard_no_overflow() []
- i4 = int_gt(i3, 1)
- guard_true(i4) []
+ i3 = int_sub(1, i0)
jump(i0)
"""
self.optimize_loop(ops, 'Not', expected)
@@ -3594,6 +3591,75 @@
"""
self.optimize_loop(ops, 'Not', expected)
+ def test_bound_eq_const_not(self):
+ ops = """
+ [i0]
+ i1 = int_eq(i0, 7)
+ guard_false(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_eq(i0, 7)
+ guard_false(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
+ def test_bound_ne_const(self):
+ ops = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_false(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_false(i1) []
+ jump(10)
+
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
+ def test_bound_ne_const_not(self):
+ ops = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_true(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ i1 = int_ne(i0, 7)
+ guard_true(i1) []
+ i2 = int_add(i0, 3)
+ jump(i2)
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
+ def test_bound_ltne(self):
+ ops = """
+ [i0, i1]
+ i2 = int_lt(i0, 7)
+ guard_true(i2) []
+ i3 = int_ne(i0, 10)
+ guard_true(i2) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_lt(i0, 7)
+ guard_true(i2) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+
def test_bound_lege_const(self):
ops = """
[i0]
@@ -3615,6 +3681,96 @@
"""
self.optimize_loop(ops, 'Not', expected)
+ def test_mul_ovf(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_lt(i1, 5)
+ guard_true(i3) []
+ i4 = int_gt(i1, -10)
+ guard_true(i4) []
+ i5 = int_mul_ovf(i2, i1)
+ guard_no_overflow() []
+ i6 = int_lt(i5, -2550)
+ guard_false(i6) []
+ i7 = int_ge(i5, 1276)
+ guard_false(i7) []
+ i8 = int_gt(i5, 126)
+ guard_true(i8) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_lt(i1, 5)
+ guard_true(i3) []
+ i4 = int_gt(i1, -10)
+ guard_true(i4) []
+ i5 = int_mul(i2, i1)
+ i8 = int_gt(i5, 126)
+ guard_true(i8) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+
+ def test_mul_ovf_before(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i22 = int_add(i2, 1)
+ i3 = int_mul_ovf(i22, i1)
+ guard_no_overflow() []
+ i4 = int_lt(i3, 10)
+ guard_true(i4) []
+ i5 = int_gt(i3, 2)
+ guard_true(i5) []
+ i6 = int_lt(i1, 0)
+ guard_false(i6) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i22 = int_add(i2, 1)
+ i3 = int_mul_ovf(i22, i1)
+ guard_no_overflow() []
+ i4 = int_lt(i3, 10)
+ guard_true(i4) []
+ i5 = int_gt(i3, 2)
+ guard_true(i5) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+
+ def test_sub_ovf_before(self):
+ ops = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_sub_ovf(i2, i1)
+ guard_no_overflow() []
+ i4 = int_le(i3, 10)
+ guard_true(i4) []
+ i5 = int_ge(i3, 2)
+ guard_true(i5) []
+ i6 = int_lt(i1, -10)
+ guard_false(i6) []
+ i7 = int_gt(i1, 253)
+ guard_false(i7) []
+ jump(i0, i1)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_and(i0, 255)
+ i3 = int_sub_ovf(i2, i1)
+ guard_no_overflow() []
+ i4 = int_le(i3, 10)
+ guard_true(i4) []
+ i5 = int_ge(i3, 2)
+ guard_true(i5) []
+ jump(i0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+
Added: pypy/branch/jit-bounds/pypy/module/pypyjit/test/randomized.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-bounds/pypy/module/pypyjit/test/randomized.py Tue Aug 24 17:52:13 2010
@@ -0,0 +1,124 @@
+#!/usr/bin/python
+
+import random, inspect, os
+
+class RandomCode(object):
+
+ maxifdepth = 10
+ maxopdepth = 20
+
+ def __init__(self):
+ self.vars = set()
+
+ def sample(self, population):
+ return random.sample(population, 1)[0]
+
+ def chose(self, *args):
+ return self.sample(args)()
+
+ def expression(self):
+ if len(self.vars) == 0:
+ return self.constant()
+ elif self.depth() > self.maxopdepth:
+ return self.chose(self.variable, self.constant)
+ else:
+ return self.chose(self.variable, self.opperation, self.constant)
+
+ def variable(self):
+ return self.sample(self.vars)
+
+ def opperation(self):
+ return self.expression() + ' ' + self.sample(self.opperators) + \
+ ' ' + self.expression()
+
+ def test(self):
+ return self.expression() + ' ' + self.sample(self.tests) + \
+ ' ' + self.expression()
+
+ def constant(self):
+ return str(self.sample(self.constants))
+
+ def depth(self):
+ return len(inspect.getouterframes(inspect.currentframe()))
+
+ def statement(self):
+ if self.depth() > self.maxifdepth:
+ return self.assignment()
+ else:
+ return self.chose(self.assignment, self.ifstatement)
+
+ def assignment(self):
+ v = self.sample(self.varnames)
+ s = v + ' = ' + self.expression() + '\n'
+ self.vars.add(v)
+ return s
+
+ def indent(self, s):
+ lines = s.split('\n')
+ lines = [' ' + l for l in lines[:-1]]
+ return '\n'.join(lines) + '\n'
+
+ def ifstatement(self):
+ return 'if ' + self.test() + ':\n' + self.indent(self.block(5))
+
+ def block(self, n):
+ s = ''
+ for i in range(random.randrange(1,n)):
+ s += self.statement()
+ return s
+
+ def whileloop(self):
+ self.vars.add('i')
+ return 'i = 0\nwhile i < 10:\n' + \
+ self.indent(self.block(5) + 'i += 1\n')
+
+ def setupvars(self):
+ return ', '.join(self.vars) + ' = ' + \
+ ', '.join('0' * len(self.vars)) + '\n'
+
+ def return_statement(self):
+ return 'return (' + ', '.join(self.vars) + ')\n'
+
+
+class IntBounds(RandomCode):
+ opperators = ('+', '-', '*')
+ tests = ('<', '>', '<=', '>=', '==', '!=')
+ constants = range(-3,4)
+ varnames = 'abcd'
+
+ def function(self, name='f'):
+ body = self.block(3) + self.whileloop() + self.return_statement()
+ body = self.setupvars() + body
+ return 'def %s():\n' % name + self.indent(body)
+
+
+def run(python, code):
+ (s,r,e) = os.popen3(python)
+ s.write(code)
+ s.close()
+ res = r.read()
+ err = e.read()
+ r.close()
+ return res, err
+
+while True:
+ code = '''
+try: # make the file runnable by CPython
+ import pypyjit
+ pypyjit.set_param(threshold=3)
+except ImportError:
+ pass
+
+%s
+print f()
+''' % IntBounds().function('f')
+
+ r1,e1 = run('/usr/bin/python', code)
+ r2,e2 = run('../../../translator/goal/pypy-c', code)
+ if r1 != r2:
+ print
+ print '******************** FAILED ******************'
+ print code
+ print 'cpython: ', r1, e1
+ print 'pypy: ', r2, e2
+
Modified: pypy/branch/jit-bounds/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/branch/jit-bounds/pypy/module/pypyjit/test/test_pypy_c.py (original)
+++ pypy/branch/jit-bounds/pypy/module/pypyjit/test/test_pypy_c.py Tue Aug 24 17:52:13 2010
@@ -849,7 +849,7 @@
''', maxops, ([tc], res))
def test_intbound_simple(self):
- ops = ('<', '>', '<=', '>=')
+ ops = ('<', '>', '<=', '>=', '==', '!=')
nbr = (3, 7)
for o1 in ops:
for o2 in ops:
@@ -870,7 +870,10 @@
def main():
res = [0] * 4
- for i in range(15) * 1500:
+ idx = []
+ for i in range(15):
+ idx.extend([i] * 1500)
+ for i in idx:
res[f(i)] += 1
return res
@@ -880,12 +883,12 @@
res = [0] * 4
for i in range(15):
res[f(i)] += 1500
- self.run_source(src, 220, ([], res))
+ self.run_source(src, 268, ([], res))
def test_intbound_addsub_mix(self):
tests = ('i > 4', 'i > 2', 'i + 1 > 2', '1 + i > 4',
'i - 1 > 1', '1 - i > 1', '1 - i < -3',
- 'i == 1', 'i == 5')
+ 'i == 1', 'i == 5', 'i != 1', '-2 * i < -4')
for t1 in tests:
for t2 in tests:
print t1, t2
@@ -904,7 +907,10 @@
def main():
res = [0] * 4
- for i in range(15) * 1500:
+ idx = []
+ for i in range(15):
+ idx.extend([i] * 1500)
+ for i in idx:
res[f(i)] += 1
return res
@@ -914,7 +920,7 @@
res = [0] * 4
for i in range(15):
res[f(i)] += 1500
- self.run_source(src, 232, ([], res))
+ self.run_source(src, 280, ([], res))
def test_intbound_gt(self):
self.run_source('''
@@ -953,6 +959,19 @@
return (a, b)
''', 56, ([], (2000, 2000)))
+ def test_intbound_addmul_ge(self):
+ self.run_source('''
+ def main():
+ i, a, b = 0, 0, 0
+ while i < 2000:
+ if i + 5 >= 5:
+ a += 1
+ if 2 * i >= 0:
+ b += 1
+ i += 1
+ return (a, b)
+ ''', 53, ([], (2000, 2000)))
+
def test_intbound_eq(self):
self.run_source('''
def main(a):
@@ -968,6 +987,20 @@
return s
''', 69, ([7], 12000), ([42], 1509), ([10], 1509))
+ def test_intbound_mul(self):
+ self.run_source('''
+ def main(a):
+ i, s = 0, 0
+ while i < 1500:
+ assert i >= 0
+ if 2 * i < 30000:
+ s += 1
+ else:
+ s += a
+ i += 1
+ return s
+ ''', 43, ([7], 1500))
+
def test_assert(self):
self.run_source('''
def main(a):
@@ -1012,6 +1045,7 @@
self = array.__new__(cls, 'd', range(256))
return self
def __getitem__(self, i):
+ # assert self.__len__() == 256 (FIXME: does not improve)
return array.__getitem__(self, i & 255)
def main():
More information about the Pypy-commit
mailing list