[pypy-svn] r75320 - in pypy/trunk/pypy: jit/codewriter/test jit/metainterp jit/metainterp/test rpython rpython/lltypesystem translator/c translator/c/src
arigo at codespeak.net
arigo at codespeak.net
Sat Jun 12 12:22:26 CEST 2010
Author: arigo
Date: Sat Jun 12 12:22:24 2010
New Revision: 75320
Modified:
pypy/trunk/pypy/jit/codewriter/test/test_flatten.py
pypy/trunk/pypy/jit/metainterp/blackhole.py
pypy/trunk/pypy/jit/metainterp/pyjitpl.py
pypy/trunk/pypy/jit/metainterp/test/test_basic.py
pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
pypy/trunk/pypy/rpython/lltypesystem/rclass.py
pypy/trunk/pypy/rpython/normalizecalls.py
pypy/trunk/pypy/translator/c/funcgen.py
pypy/trunk/pypy/translator/c/src/int.h
Log:
Merge branch/int-between.
It adds an 'int_between' operation produced by lltypesystem.rclass.
This operation has a slightly more efficient form in the C backend.
More importantly, in the JIT it becomes a single True/False test;
previously, it was done with a double test "a <= b <= c", which
can fail for two distinct reasons: b < a or b > c. If we ever see
that case, it would create two equal traces from that point.
Modified: pypy/trunk/pypy/jit/codewriter/test/test_flatten.py
==============================================================================
--- pypy/trunk/pypy/jit/codewriter/test/test_flatten.py (original)
+++ pypy/trunk/pypy/jit/codewriter/test/test_flatten.py Sat Jun 12 12:22:24 2010
@@ -715,3 +715,12 @@
uint_le %i2, $456L -> %i3
int_return %i3
""", transform=True)
+
+ def test_int_between(self):
+ from pypy.rpython.lltypesystem.lloperation import llop
+ def f(n, m, p):
+ return llop.int_between(lltype.Bool, n, m, p)
+ self.encoding_test(f, [5, 6, 7], """
+ int_between %i0, %i1, %i2 -> %i3
+ int_return %i3
+ """, transform=True)
Modified: pypy/trunk/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/blackhole.py (original)
+++ pypy/trunk/pypy/jit/metainterp/blackhole.py Sat Jun 12 12:22:24 2010
@@ -475,6 +475,9 @@
@arguments("i", returns="i")
def bhimpl_int_is_true(a):
return bool(a)
+ @arguments("i", "i", "i", returns="i")
+ def bhimpl_int_between(a, b, c):
+ return a <= b < c
@arguments("i", "i", returns="i")
def bhimpl_uint_lt(a, b):
Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Sat Jun 12 12:22:24 2010
@@ -315,6 +315,16 @@
if value:
self.pc = target
+ @arguments("box", "box", "box")
+ def opimpl_int_between(self, b1, b2, b3):
+ b5 = self.execute(rop.INT_SUB, b3, b1)
+ if isinstance(b5, ConstInt) and b5.getint() == 1:
+ # the common case of int_between(a, b, a+1) turns into just INT_EQ
+ return self.execute(rop.INT_EQ, b2, b1)
+ else:
+ b4 = self.execute(rop.INT_SUB, b2, b1)
+ return self.execute(rop.UINT_LT, b4, b5)
+
@arguments("box", "descr", "orgpc")
def opimpl_switch(self, valuebox, switchdict, orgpc):
box = self.implement_guard_value(orgpc, valuebox)
Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Sat Jun 12 12:22:24 2010
@@ -145,6 +145,9 @@
def check_operations_history(self, expected=None, **isns):
# this can be used after interp_operations
+ if expected is not None:
+ expected = dict(expected)
+ expected['jump'] = 1
self.metainterp.staticdata.stats.check_history(expected, **isns)
@@ -561,6 +564,53 @@
int_le=0, uint_le=1,
int_sub=1)
+ def test_int_between(self):
+ #
+ def check(arg1, arg2, arg3, expect_result, **expect_operations):
+ from pypy.rpython.lltypesystem import lltype
+ from pypy.rpython.lltypesystem.lloperation import llop
+ loc = locals().copy()
+ exec py.code.Source("""
+ def f(n, m, p):
+ arg1 = %(arg1)s
+ arg2 = %(arg2)s
+ arg3 = %(arg3)s
+ return llop.int_between(lltype.Bool, arg1, arg2, arg3)
+ """ % locals()).compile() in loc
+ res = self.interp_operations(loc['f'], [5, 6, 7])
+ assert res == expect_result
+ self.check_operations_history(expect_operations)
+ #
+ check('n', 'm', 'p', True, int_sub=2, uint_lt=1)
+ check('n', 'p', 'm', False, int_sub=2, uint_lt=1)
+ #
+ check('n', 'm', 6, False, int_sub=2, uint_lt=1)
+ #
+ check('n', 4, 'p', False, int_sub=2, uint_lt=1)
+ check('n', 5, 'p', True, int_sub=2, uint_lt=1)
+ check('n', 8, 'p', False, int_sub=2, uint_lt=1)
+ #
+ check('n', 6, 7, True, int_sub=2, uint_lt=1)
+ #
+ check(-2, 'n', 'p', True, int_sub=2, uint_lt=1)
+ check(-2, 'm', 'p', True, int_sub=2, uint_lt=1)
+ check(-2, 'p', 'm', False, int_sub=2, uint_lt=1)
+ #check(0, 'n', 'p', True, uint_lt=1) xxx implement me
+ #check(0, 'm', 'p', True, uint_lt=1)
+ #check(0, 'p', 'm', False, uint_lt=1)
+ #
+ check(2, 'n', 6, True, int_sub=1, uint_lt=1)
+ check(2, 'm', 6, False, int_sub=1, uint_lt=1)
+ check(2, 'p', 6, False, int_sub=1, uint_lt=1)
+ check(5, 'n', 6, True, int_eq=1) # 6 == 5+1
+ check(5, 'm', 6, False, int_eq=1) # 6 == 5+1
+ #
+ check(2, 6, 'm', False, int_sub=1, uint_lt=1)
+ check(2, 6, 'p', True, int_sub=1, uint_lt=1)
+ #
+ check(2, 40, 6, False)
+ check(2, 40, 60, True)
+
def test_getfield(self):
class A:
pass
Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py Sat Jun 12 12:22:24 2010
@@ -227,6 +227,8 @@
'int_rshift': LLOp(canfold=True),
'int_xor': LLOp(canfold=True),
+ 'int_between': LLOp(canfold=True), # a <= b < c
+
'int_add_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
'int_add_nonneg_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
# ^^^ more efficient version when 2nd arg is nonneg
Modified: pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/opimpl.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/opimpl.py Sat Jun 12 12:22:24 2010
@@ -197,6 +197,12 @@
assert isinstance(y, int)
return intmask(x - y)
+def op_int_between(a, b, c):
+ assert lltype.typeOf(a) is lltype.Signed
+ assert lltype.typeOf(b) is lltype.Signed
+ assert lltype.typeOf(c) is lltype.Signed
+ return a <= b < c
+
def op_int_and(x, y):
if not isinstance(x, int):
from pypy.rpython.lltypesystem import llgroup
Modified: pypy/trunk/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/rclass.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/rclass.py Sat Jun 12 12:22:24 2010
@@ -22,6 +22,7 @@
from pypy.rlib.rarithmetic import intmask
from pypy.rlib import objectmodel
from pypy.lib.identity_dict import identity_dict
+from pypy.rpython.lltypesystem.lloperation import llop
#
# There is one "vtable" per user class, with the following structure:
@@ -645,10 +646,12 @@
return cast_pointer(OBJECTPTR, obj).typeptr
def ll_issubclass(subcls, cls):
- return cls.subclassrange_min <= subcls.subclassrange_min <= cls.subclassrange_max
+ return llop.int_between(Bool, cls.subclassrange_min,
+ subcls.subclassrange_min,
+ cls.subclassrange_max)
def ll_issubclass_const(subcls, minid, maxid):
- return minid <= subcls.subclassrange_min <= maxid
+ return llop.int_between(Bool, minid, subcls.subclassrange_min, maxid)
def ll_isinstance(obj, cls): # obj should be cast to OBJECT or NONGCOBJECT
Modified: pypy/trunk/pypy/rpython/normalizecalls.py
==============================================================================
--- pypy/trunk/pypy/rpython/normalizecalls.py (original)
+++ pypy/trunk/pypy/rpython/normalizecalls.py Sat Jun 12 12:22:24 2010
@@ -292,6 +292,13 @@
else:
return cmp(self.orderwitness, other.orderwitness)
+ # support for implementing int_between: (a<=b<c) with (b-a<c-a)
+ # see pypy.jit.metainterp.pyjitpl.opimpl_int_between
+ def __sub__(self, other):
+ return self.compute_fn() - other
+ def __rsub__(self, other):
+ return other - self.compute_fn()
+
def compute_fn(self):
if self.value is None:
self.peers.sort()
Modified: pypy/trunk/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/trunk/pypy/translator/c/funcgen.py (original)
+++ pypy/trunk/pypy/translator/c/funcgen.py Sat Jun 12 12:22:24 2010
@@ -318,6 +318,7 @@
def gen_op(self, op):
macro = 'OP_%s' % op.opname.upper()
+ line = None
if op.opname.startswith('gc_'):
meth = getattr(self.gcpolicy, macro, None)
if meth:
@@ -326,7 +327,7 @@
meth = getattr(self, macro, None)
if meth:
line = meth(op)
- if meth is None:
+ if line is None:
lst = [self.expr(v) for v in op.args]
lst.append(self.expr(op.result))
line = '%s(%s);' % (macro, ', '.join(lst))
@@ -849,5 +850,16 @@
return 'PYPY_DEBUG_CATCH_EXCEPTION("%s", %s, %s);' % (
self.getdebugfunctionname(), gottype, ' || '.join(exprs))
+ def OP_INT_BETWEEN(self, op):
+ if (isinstance(op.args[0], Constant) and
+ isinstance(op.args[2], Constant) and
+ op.args[2].value - op.args[0].value == 1):
+ # (a <= b < a+1) ----> (b == a)
+ return '%s = (%s == %s); /* was INT_BETWEEN */' % (
+ self.expr(op.result),
+ self.expr(op.args[1]),
+ self.expr(op.args[0]))
+ else:
+ return None # use the default
assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
Modified: pypy/trunk/pypy/translator/c/src/int.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/int.h (original)
+++ pypy/trunk/pypy/translator/c/src/int.h Sat Jun 12 12:22:24 2010
@@ -47,6 +47,14 @@
#define OP_INT_LT(x,y,r) r = ((x) < (y))
#define OP_INT_GE(x,y,r) r = ((x) >= (y))
+/* Implement INT_BETWEEN by optimizing for the common case where a and c
+ are constants (the 2nd subtraction below is then constant-folded), or
+ for the case of a == 0 (both subtractions are then constant-folded).
+ Note that the following line only works if a <= c in the first place,
+ which we assume is true. */
+#define OP_INT_BETWEEN(a,b,c,r) r = (((unsigned long)b - (unsigned long)a) \
+ < ((unsigned long)c - (unsigned long)a))
+
/* addition, subtraction */
#define OP_INT_ADD(x,y,r) r = (x) + (y)
More information about the Pypy-commit
mailing list