[pypy-svn] r29307 - in pypy/dist/pypy/rpython: . lltypesystem lltypesystem/test

arigo at codespeak.net arigo at codespeak.net
Sun Jun 25 12:35:13 CEST 2006


Author: arigo
Date: Sun Jun 25 12:35:09 2006
New Revision: 29307

Added:
   pypy/dist/pypy/rpython/lltypesystem/opimpl.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_lloperation.py
   pypy/dist/pypy/rpython/rarithmetic.py
Log:
Refactor and clean up the execution of ll operations.  All 'canfold'
operations are implemented in a new opimpl.py, which is used both by
llinterp and by direct calls to the LLOps like:

    assert llop.int_add(Signed, 5, 6) == 11

The idea is that llop calls are used when constant-folding only, and can
raise TypeError if the operation is not foldable.  For general
execution, the llinterpreter is still needed.



Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Sun Jun 25 12:35:09 2006
@@ -147,25 +147,19 @@
         raise ValueError, "couldn't match exception"
 
 
-# implementations of ops from flow.operation
-from pypy.objspace.flow.operation import FunctionByName
-opimpls = FunctionByName.copy()
-opimpls['is_true'] = bool
-
-ops_returning_a_bool = {'gt': True, 'ge': True,
-                        'lt': True, 'le': True,
-                        'eq': True, 'ne': True,
-                        'is_true': True}
-
 def checkptr(ptr):
-    return isinstance(lltype.typeOf(ptr), lltype.Ptr)
+    assert isinstance(lltype.typeOf(ptr), lltype.Ptr)
 
 def checkadr(addr):
-    return lltype.typeOf(addr) == llmemory.Address
+    assert lltype.typeOf(addr) is llmemory.Address
     
-def checkinst(inst):
+def is_inst(inst):
     return isinstance(lltype.typeOf(inst), (ootype.Instance, ootype.BuiltinType))
 
+def checkinst(inst):
+    assert is_inst(inst)
+
+
 class LLFrame(object):
     def __init__(self, graph, args, llinterpreter, f_back=None):
         assert not graph or isinstance(graph, FunctionGraph)
@@ -225,7 +219,10 @@
     def getoperationhandler(self, opname):
         ophandler = getattr(self, 'op_' + opname, None)
         if ophandler is None:
-            raise AssertionError, "cannot handle operation %r yet" %(opname,)
+            # try to import the operation from opimpl.py
+            from pypy.rpython.lltypesystem.opimpl import get_op_impl
+            ophandler = get_op_impl(opname)
+            LLFrame.ophandler = staticmethod(ophandler)
         return ophandler
     # _______________________________________________________
     # evaling functions
@@ -332,12 +329,7 @@
         elif operation.opname == 'indirect_call':
             assert isinstance(operation.args[0], Variable)
         vals = [self.getval(x) for x in operation.args]
-        # XXX these special cases DO pile up, do something better here
-        if operation.opname in ['cast_pointer', 'ooupcast', 'oodowncast',
-                                'cast_adr_to_ptr', 'cast_weakadr_to_ptr',
-                                'cast_int_to_ptr',
-                                'cast_opaque_ptr', 'unsafe_call',
-                                'cast_primitive']:
+        if getattr(ophandler, 'need_result_type', False):
             vals.insert(0, operation.result.concretetype)
         try:
             retval = ophandler(*vals)
@@ -428,9 +420,6 @@
     def op_keepalive(self, value):
         pass
 
-    def op_same_as(self, x):
-        return x
-
     def op_hint(self, x, hints):
         return x
 
@@ -527,6 +516,7 @@
         from pypy.translator.stackless.frame import storage_type
         assert storage_type(lltype.typeOf(result)) == TGT
         return lltype._cast_whatever(TGT, result)
+    op_unsafe_call.need_result_type = True
 
     def op_malloc(self, obj):
         if self.llinterpreter.gc is not None:
@@ -565,179 +555,22 @@
         self.heap.free(obj, flavor=flavor)
 
     def op_getfield(self, obj, field):
-        assert checkptr(obj)
+        checkptr(obj)
         # check the difference between op_getfield and op_getsubstruct:
         assert not isinstance(getattr(lltype.typeOf(obj).TO, field),
                               lltype.ContainerType)
         return getattr(obj, field)
 
-    def op_getsubstruct(self, obj, field):
-        assert checkptr(obj)
-        # check the difference between op_getfield and op_getsubstruct:
-        assert isinstance(getattr(lltype.typeOf(obj).TO, field),
-                          lltype.ContainerType)
-        return getattr(obj, field)
-
-    def op_getarraysubstruct(self, array, index):
-        assert checkptr(array)
-        result = array[index]
-        return result
-        # the diff between op_getarrayitem and op_getarraysubstruct
-        # is the same as between op_getfield and op_getsubstruct
-
-    def op_getarraysize(self, array):
-        #print array,type(array),dir(array)
-        assert isinstance(lltype.typeOf(array).TO, lltype.Array)
-        return len(array)
-
-    def op_cast_pointer(self, tp, obj):
-        return lltype.cast_pointer(tp, obj)
-
-    def op_cast_opaque_ptr(self, tp, obj):
-        return lltype.cast_opaque_ptr(tp, obj)
-
-    def op_ptr_eq(self, ptr1, ptr2):
-        assert checkptr(ptr1)
-        assert checkptr(ptr2)
-        return ptr1 == ptr2
-
-    def op_ptr_ne(self, ptr1, ptr2):
-        assert checkptr(ptr1)
-        assert checkptr(ptr2)
-        return ptr1 != ptr2
-
-    def op_ptr_nonzero(self, ptr1):
-        assert checkptr(ptr1)
-        return bool(ptr1)
-
-    def op_ptr_iszero(self, ptr1):
-        assert checkptr(ptr1)
-        return not bool(ptr1)
-
-    def op_direct_fieldptr(self, obj, field):
-        assert checkptr(obj)
-        assert isinstance(field, str)
-        return lltype.direct_fieldptr(obj, field)
-
-    def op_direct_arrayitems(self, obj):
-        assert checkptr(obj)
-        return lltype.direct_arrayitems(obj)
-
-    def op_direct_ptradd(self, obj, index):
-        assert checkptr(obj)
-        assert isinstance(index, int)
-        return lltype.direct_ptradd(obj, index)
-
-    def op_cast_primitive(self, TYPE, value):
-        assert isinstance(lltype.typeOf(value), lltype.Primitive)
-        return lltype.cast_primitive(TYPE, value)
+    def op_cast_int_to_ptr(self, RESTYPE, int1):
+        return lltype.cast_int_to_ptr(RESTYPE, int1)
+    op_cast_int_to_ptr.need_result_type = True
 
     def op_cast_ptr_to_int(self, ptr1):
-        assert checkptr(ptr1)
-        assert isinstance(lltype.typeOf(ptr1).TO, (lltype.Array, lltype.Struct))
+        checkptr(ptr1)
+        assert isinstance(lltype.typeOf(ptr1).TO, (lltype.Array, lltype.Struct)
+)
         return lltype.cast_ptr_to_int(ptr1)
 
-    def op_cast_int_to_ptr(self, tp, int1):
-        return lltype.cast_int_to_ptr(tp, int1)
-
-    def op_cast_ptr_to_adr(self, ptr):
-        assert checkptr(ptr)
-        return llmemory.cast_ptr_to_adr(ptr)
-
-    def op_cast_adr_to_ptr(self, TYPE, adr):
-        assert checkadr(adr)
-        return llmemory.cast_adr_to_ptr(adr, TYPE)
-
-    def op_cast_adr_to_int(self, adr):
-        assert checkadr(adr)
-        return llmemory.cast_adr_to_int(adr)
-
-    def op_cast_ptr_to_weakadr(self, ptr):
-        assert checkptr(ptr)
-        return llmemory.cast_ptr_to_weakadr(ptr)
-
-    def op_cast_weakadr_to_ptr(self, TYPE, wadr):
-        assert lltype.typeOf(wadr) == llmemory.WeakGcAddress
-        return llmemory.cast_weakadr_to_ptr(wadr, TYPE)
-
-    def op_cast_weakadr_to_int(self, wadr):
-        assert lltype.typeOf(wadr) == llmemory.WeakGcAddress
-        return wadr.cast_to_int()
-    
-    def op_cast_int_to_float(self, i):
-        assert type(i) is int
-        return float(i)
-
-    def op_cast_int_to_char(self, b):
-        assert type(b) is int
-        return chr(b)
-
-    def op_cast_bool_to_int(self, b):
-        assert type(b) is bool
-        return int(b)
-
-    def op_cast_bool_to_uint(self, b):
-        assert type(b) is bool
-        return r_uint(int(b))
-
-    def op_cast_bool_to_float(self, b):
-        assert type(b) is bool
-        return float(b)
-
-    def op_bool_not(self, b):
-        assert type(b) is bool
-        return not b
-
-    def op_cast_float_to_int(self, f):
-        assert type(f) is float
-        return ovfcheck(int(f))
-
-    def op_cast_float_to_uint(self, f):
-        assert type(f) is float
-        return r_uint(int(f))
-
-    def op_cast_char_to_int(self, b):
-        assert type(b) is str and len(b) == 1
-        return ord(b)
-
-    def op_cast_unichar_to_int(self, b):
-        assert type(b) is unicode and len(b) == 1
-        return ord(b)
-
-    def op_cast_int_to_unichar(self, b):
-        assert type(b) is int 
-        return unichr(b)
-
-    def op_cast_int_to_uint(self, b):
-        assert type(b) is int
-        return r_uint(b)
-
-    def op_cast_uint_to_int(self, b):
-        assert type(b) is r_uint
-        return intmask(b)
-
-    def op_cast_int_to_longlong(self, b):
-        assert type(b) is int
-        return r_longlong(b)
-
-    def op_truncate_longlong_to_int(self, b):
-        assert type(b) is r_longlong
-        assert -sys.maxint-1 <= b <= sys.maxint
-        return int(b)
-
-    def op_float_floor(self, b):
-        assert type(b) is float
-        return math.floor(b)
-
-    def op_float_fmod(self, b,c):
-        assert type(b) is float
-        assert type(c) is float
-        return math.fmod(b,c)
-
-    def op_float_pow(self, b,c):
-        assert type(b) is float
-        assert type(c) is float
-        return math.pow(b,c)
 
     def op_gc__collect(self):
         import gc
@@ -781,12 +614,12 @@
 
 
     # operations on pyobjects!
-    for opname in opimpls.keys():
+    for opname in lloperation.opimpls.keys():
         exec py.code.Source("""
         def op_%(opname)s(self, *pyobjs):
             for pyo in pyobjs:
                 assert lltype.typeOf(pyo) == lltype.Ptr(lltype.PyObject)
-            func = opimpls[%(opname)r]
+            func = lloperation.opimpls[%(opname)r]
             try:
                 pyo = func(*[pyo._obj.value for pyo in pyobjs])
             except Exception:
@@ -814,198 +647,98 @@
         return self.heap.raw_malloc_usage(size)
 
     def op_raw_free(self, addr):
-        assert checkadr(addr) 
+        checkadr(addr) 
         self.heap.raw_free(addr)
 
     def op_raw_memcopy(self, fromaddr, toaddr, size):
-        assert checkadr(fromaddr)
-        assert checkadr(toaddr)
+        checkadr(fromaddr)
+        checkadr(toaddr)
         self.heap.raw_memcopy(fromaddr, toaddr, size)
 
     def op_raw_load(self, addr, typ, offset):
-        assert checkadr(addr)
+        checkadr(addr)
         value = getattr(addr, str(typ).lower())[offset]
         assert lltype.typeOf(value) == typ
         return value
 
     def op_raw_store(self, addr, typ, offset, value):
-        assert checkadr(addr)
+        checkadr(addr)
         assert lltype.typeOf(value) == typ
         getattr(addr, str(typ).lower())[offset] = value
 
-    def op_adr_add(self, addr, offset):
-        assert checkadr(addr)
-        assert lltype.typeOf(offset) is lltype.Signed
-        return addr + offset
-
-    def op_adr_sub(self, addr, offset):
-        assert checkadr(addr)
-        assert lltype.typeOf(offset) is lltype.Signed
-        return addr - offset
-
-    def op_adr_delta(self, addr1, addr2):
-        assert checkadr(addr1)
-        assert checkadr(addr2)
-        return addr1 - addr2
-
-    for opname, op in (("eq", "=="), ("ne", "!="), ("le", "<="), ("lt", "<"),
-                       ("gt", ">"), ("ge", ">=")):
-        exec py.code.Source("""
-            def op_adr_%s(self, addr1, addr2):
-                checkadr(addr1)
-                checkadr(addr2)
-                return addr1 %s addr2""" % (opname, op)).compile()
-
-    # __________________________________________________________
-    # primitive operations
-
-    def setup_primitive_operations():
-        for typ in (float, int, r_uint, r_longlong, r_ulonglong):
-            typname = typ.__name__
-            optup = ('add', 'sub', 'mul', 'truediv', 'floordiv',
-                     'mod', 'gt', 'lt', 'ge', 'ne', 'le', 'eq',)
-            overflowing_operations = ('add', 'sub', 'mul', 'floordiv',
-                                      'mod', 'lshift')
-            if typ is r_uint:
-                opnameprefix = 'uint'
-            elif typ is r_longlong:
-                opnameprefix = 'llong'
-            elif typ is r_ulonglong:
-                opnameprefix = 'ullong'
-            else:
-                opnameprefix = typname
-            if typ is not float:
-                optup += 'and_', 'or_', 'lshift', 'rshift', 'xor'
-            for opname in optup:
-                assert opname in opimpls
-                if typ is float and opname == 'floordiv':
-                    continue    # 'floordiv' is for integer types
-                if typ is not float and opname == 'truediv':
-                    continue    # 'truediv' is for floats only
-                if typ is int and opname not in ops_returning_a_bool:
-                    adjust_result = 'intmask'
-                else:
-                    adjust_result = ''
-                pureopname = opname.rstrip('_')
-                yield """
-                    def op_%(opnameprefix)s_%(pureopname)s(self, x, y):
-                        assert isinstance(x, %(typname)s)
-                        assert isinstance(y, %(typname)s)
-                        func = opimpls[%(opname)r]
-                        return %(adjust_result)s(func(x, y))
-                """ % locals()
-
-                suffixes = []
-                if typ is not float:
-                    if opname in ('lshift', 'rshift'):
-                        suffixes.append(('_val', 'ValueError'))
-                    if opname in ('floordiv', 'mod'):
-                        suffixes.append(('_zer', 'ZeroDivisionError'))
-                    if typ is int and opname in overflowing_operations:
-                        for suffix1, exccls1 in suffixes[:]:
-                            suffixes.append(('_ovf'+suffix1,
-                                             '(OverflowError, %s)' % exccls1))
-                        suffixes.append(('_ovf', 'OverflowError'))
-
-                for suffix, exceptionclasses in suffixes:
-                    if '_ovf' in suffix:
-                        opname_ex = opname + '_ovf'
-                    else:
-                        opname_ex = opname
-                    yield """
-                        def op_%(opnameprefix)s_%(pureopname)s%(suffix)s(self, x, y):
-                            assert isinstance(x, %(typname)s)
-                            assert isinstance(y, %(typname)s)
-                            func = opimpls[%(opname_ex)r]
-                            try:
-                                return %(adjust_result)s(func(x, y))
-                            except %(exceptionclasses)s:
-                                self.make_llexception()
-                    """ % locals()
-            for opname in 'is_true', 'neg', 'abs', 'invert':
-                assert opname in opimpls
-                if typ is float and opname == 'invert':
-                    continue
-                if typ is int and opname not in ops_returning_a_bool:
-                    adjust_result = 'intmask'
-                else:
-                    adjust_result = ''
-                yield """
-                    def op_%(opnameprefix)s_%(opname)s(self, x):
-                        assert isinstance(x, %(typname)s)
-                        func = opimpls[%(opname)r]
-                        return %(adjust_result)s(func(x))
-                """ % locals()
-                if typ is int and opname in ('neg', 'abs'):
-                    opname += '_ovf'
-                    yield """
-                        def op_%(opnameprefix)s_%(opname)s(self, x):
-                            assert isinstance(x, %(typname)s)
-                            func = opimpls[%(opname)r]
-                            try:
-                                return %(adjust_result)s(func(x))
-                            except OverflowError:
-                                self.make_llexception()
-                    """ % locals()
-
-        for opname in ('gt', 'lt', 'ge', 'ne', 'le', 'eq'):
-            assert opname in opimpls
-            yield """
-                def op_char_%(opname)s(self, x, y):
-                    assert isinstance(x, str) and len(x) == 1
-                    assert isinstance(y, str) and len(y) == 1
-                    func = opimpls[%(opname)r]
-                    return func(x, y)
-            """ % locals()
-
-    for _src in setup_primitive_operations():
-        exec py.code.Source(_src).compile()
-        del _src
-    del setup_primitive_operations
-
     # ____________________________________________________________
+    # Overflow-detecting variants
 
-    original_int_add = op_int_add
-
-    def op_int_add(self, x, y):
-        if isinstance(x, llmemory.AddressOffset) or isinstance(y, llmemory.AddressOffset) :
-            return x + y
-        else:
-            return self.original_int_add(x, y)
-
-    original_int_add_ovf = op_int_add_ovf
-
-    def op_int_add_ovf(self, x, y):
-        if isinstance(x, llmemory.AddressOffset) or isinstance(y, llmemory.AddressOffset) :
-            return x + y
-        else:
-            return self.original_int_add_ovf(x, y)
+    def op_int_neg_ovf(self, x):
+        assert type(x) is int
+        try:
+            return ovfcheck(-x)
+        except OverflowError:
+            self.make_llexception()
 
-    original_int_mul = op_int_mul
+    def op_int_abs_ovf(self, x):
+        assert type(x) is int
+        try:
+            return ovfcheck(abs(x))
+        except OverflowError:
+            self.make_llexception()
 
-    def op_int_mul(self, x, y):
-        if isinstance(x, llmemory.AddressOffset):
-            return x * y
+    def _makefunc2(fn, operator, xtype, ytype=None):
+        import sys
+        d = sys._getframe(1).f_locals
+        if ytype is None:
+            ytype = xtype
+        if '_ovf' in fn:
+            checkfn = 'ovfcheck'
+        elif fn.startswith('op_int_'):
+            checkfn = 'intmask'
         else:
-            return self.original_int_mul(x, y)
+            checkfn = ''
+        exec py.code.Source("""
+        def %(fn)s(self, x, y):
+            assert isinstance(x, %(xtype)s)
+            assert isinstance(y, %(ytype)s)
+            try:
+                return %(checkfn)s(x %(operator)s y)
+            except (OverflowError, ValueError, ZeroDivisionError):
+                self.make_llexception()
+        """ % locals()).compile() in globals(), d
 
-    original_int_mul_ovf = op_int_mul_ovf
+    _makefunc2('op_int_add_ovf', '+', '(int, llmemory.AddressOffset)')
+    _makefunc2('op_int_mul_ovf', '*', '(int, llmemory.AddressOffset)', 'int')
+    _makefunc2('op_int_sub_ovf',          '-',  'int')
+    _makefunc2('op_int_floordiv_ovf',     '//', 'int')
+    _makefunc2('op_int_floordiv_zer',     '//', 'int')
+    _makefunc2('op_int_floordiv_ovf_zer', '//', 'int')
+    _makefunc2('op_int_mod_ovf',          '%',  'int')
+    _makefunc2('op_int_mod_zer',          '%',  'int')
+    _makefunc2('op_int_mod_ovf_zer',      '%',  'int')
+    _makefunc2('op_int_lshift_ovf',       '<<', 'int')
+    _makefunc2('op_int_lshift_val',       '<<', 'int')
+    _makefunc2('op_int_lshift_ovf_val',   '<<', 'int')
+    _makefunc2('op_int_rshift_val',       '>>', 'int')
+
+    _makefunc2('op_uint_floordiv_zer',    '//', 'r_uint')
+    _makefunc2('op_uint_mod_zer',         '%',  'r_uint')
+    _makefunc2('op_uint_lshift_val',      '<<', 'r_uint')
+    _makefunc2('op_uint_rshift_val',      '>>', 'r_uint')
+
+    _makefunc2('op_llong_floordiv_zer',   '//', 'r_longlong')
+    _makefunc2('op_llong_mod_zer',        '%',  'r_longlong')
+    _makefunc2('op_llong_lshift_val',     '<<', 'r_longlong')
+    _makefunc2('op_llong_rshift_val',     '>>', 'r_longlong')
+
+    _makefunc2('op_ullong_floordiv_zer',  '//', 'r_ulonglong')
+    _makefunc2('op_ullong_mod_zer',       '%',  'r_ulonglong')
+    _makefunc2('op_ullong_lshift_val',    '<<', 'r_ulonglong')
+    _makefunc2('op_ullong_rshift_val',    '>>', 'r_ulonglong')
 
-    def op_int_mul_ovf(self, x, y):
-        if isinstance(x, llmemory.AddressOffset):
-            return x * y
-        else:
-            return self.original_int_mul_ovf(x, y)
-
-    def op_unichar_eq(self, x, y):
-        assert isinstance(x, unicode) and len(x) == 1
-        assert isinstance(y, unicode) and len(y) == 1
-        return x == y
-
-    def op_unichar_ne(self, x, y):
-        assert isinstance(x, unicode) and len(x) == 1
-        assert isinstance(y, unicode) and len(y) == 1
-        return x != y
+    def op_cast_float_to_int(self, f):
+        assert type(f) is float
+        try:
+            return ovfcheck(int(f))
+        except OverflowError:
+            self.make_llexception()
 
     #Operation of ootype
 
@@ -1031,19 +764,19 @@
         return ootype.oonewcustomdict(DICT, sm_eq, sm_hash)
 
     def op_oosetfield(self, inst, name, value):
-        assert checkinst(inst)
+        checkinst(inst)
         assert isinstance(name, str)
         FIELDTYPE = lltype.typeOf(inst)._field_type(name)
         if FIELDTYPE != lltype.Void:
             setattr(inst, name, value)
 
     def op_oogetfield(self, inst, name):
-        assert checkinst(inst)
+        checkinst(inst)
         assert isinstance(name, str)
         return getattr(inst, name)
 
     def op_oosend(self, message, inst, *args):
-        assert checkinst(inst)
+        checkinst(inst)
         assert isinstance(message, str)
         bm = getattr(inst, message)
         inst = bm.inst
@@ -1055,17 +788,19 @@
 
     def op_ooupcast(self, INST, inst):
         return ootype.ooupcast(INST, inst)
+    op_ooupcast.need_result_type = True
     
     def op_oodowncast(self, INST, inst):
         return ootype.oodowncast(INST, inst)
+    op_oodowncast.need_result_type = True
 
     def op_oononnull(self, inst):
-        assert checkinst(inst)
+        checkinst(inst)
         return bool(inst)
 
     def op_oois(self, obj1, obj2):
-        if checkinst(obj1):
-            assert checkinst(obj2)
+        if is_inst(obj1):
+            checkinst(obj2)
             return obj1 == obj2   # NB. differently-typed NULLs must be equal
         elif isinstance(obj1, ootype._class):
             assert isinstance(obj2, ootype._class)

Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Sun Jun 25 12:35:09 2006
@@ -43,7 +43,23 @@
     __name__ = property(lambda self: 'llop_'+self.opname)
 
     def __call__(self, RESULTTYPE, *args):
-        raise TypeError, "llop is meant to be rtyped and not called direclty"
+        # llop is meant to be rtyped and not called directly, unless it is
+        # a canfold=True operation
+        fold = self.fold
+        if getattr(fold, 'need_result_type', False):
+            return fold(RESULTTYPE, *args)
+        else:
+            return fold(*args)
+
+    def fold(self, RESULTTYPE, *args):
+        if not self.canfold:
+            raise TypeError, "cannot constant-fold operation %r" % (
+                self.opname,)
+        from pypy.rpython.lltypesystem.opimpl import get_op_impl
+        # cache the implementation function into 'self'
+        self.fold = get_op_impl(self.opname)
+        return self(RESULTTYPE, *args)
+    fold.need_result_type = True
 
 
 def enum_ops_without_sideeffects(raising_is_ok=False):
@@ -258,7 +274,7 @@
     'cast_int_to_float':    LLOp(canfold=True),
     'cast_int_to_longlong': LLOp(canfold=True),
     'cast_uint_to_int':     LLOp(canfold=True),
-    'cast_float_to_int':    LLOp(canfold=True),
+    'cast_float_to_int':    LLOp(canraise=(OverflowError,)),
     'cast_float_to_uint':   LLOp(canfold=True),
     'truncate_longlong_to_int':LLOp(canfold=True),
 
@@ -374,11 +390,11 @@
 
 from pypy.objspace.flow.operation import FunctionByName
 opimpls = FunctionByName.copy()
-opimpls['is_true'] = True
-opimpls['simple_call'] = True
+opimpls['is_true'] = bool
 for opname in opimpls:
     LL_OPERATIONS[opname] = LLOp(canraise=(Exception,), pyobj=True)
-del opname, opimpls, FunctionByName
+LL_OPERATIONS['simple_call'] = LLOp(canraise=(Exception,), pyobj=True)
+del opname, FunctionByName
 
 # ____________________________________________________________
 # Post-processing

Added: pypy/dist/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/lltypesystem/opimpl.py	Sun Jun 25 12:35:09 2006
@@ -0,0 +1,332 @@
+import sys
+from pypy.tool.sourcetools import func_with_new_name
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem.lloperation import opimpls
+
+# ____________________________________________________________
+# Implementation of the 'canfold' operations
+
+
+# implementations of ops from flow.operation
+ops_returning_a_bool = {'gt': True, 'ge': True,
+                        'lt': True, 'le': True,
+                        'eq': True, 'ne': True,
+                        'is_true': True}
+ops_unary = {'is_true': True, 'neg': True, 'abs': True, 'invert': True}
+
+# global synonyms for some types
+from pypy.rpython.rarithmetic import intmask
+from pypy.rpython.rarithmetic import r_uint, r_longlong, r_ulonglong
+
+type_by_name = {
+    'int': int,
+    'float': float,
+    'uint': r_uint,
+    'llong': r_longlong,
+    'ullong': r_ulonglong,
+    }
+
+def no_op(x):
+    return x
+
+def get_primitive_op_src(fullopname):
+    assert '_' in fullopname, "%s: not a primitive op" % (fullopname,)
+    typname, opname = fullopname.split('_', 1)
+    if opname not in opimpls and (opname + '_') in opimpls:
+        func = opimpls[opname + '_']   # or_, and_
+    else:
+        assert opname in opimpls, "%s: not a primitive op" % (fullopname,)
+        func = opimpls[opname]
+
+    if typname == 'char':
+        # char_lt, char_eq, ...
+        def op_function(x, y):
+            if not isinstance(x, str) or len(x) != 1:
+                raise TypeError("%r arg must be a char, got %r instead" % (
+                    fullopname, typname, type(x).__name__))
+            if not isinstance(y, str) or len(y) != 1:
+                raise TypeError("%r arg must be a char, got %r instead" % (
+                    fullopname, typname, type(y).__name__))
+            return func(x, y)
+
+    else:
+        if typname == 'int' and opname not in ops_returning_a_bool:
+            adjust_result = intmask
+        else:
+            adjust_result = no_op
+        assert typname in type_by_name, "%s: not a primitive op" % (
+            fullopname,)
+        argtype = type_by_name[typname]
+
+        if opname in ops_unary:
+            def op_function(x):
+                if not isinstance(x, argtype):
+                    raise TypeError("%r arg must be %s, got %r instead" % (
+                        fullopname, typname, type(x).__name__))
+                return adjust_result(func(x))
+        else:
+            def op_function(x, y):
+                if not isinstance(x, argtype):
+                    raise TypeError("%r arg 1 must be %s, got %r instead" % (
+                        fullopname, typname, type(x).__name__))
+                if not isinstance(y, argtype):
+                    raise TypeError("%r arg 2 must be %s, got %r instead" % (
+                        fullopname, typname, type(y).__name__))
+                return adjust_result(func(x, y))
+
+    return func_with_new_name(op_function, 'op_' + fullopname)
+
+def checkptr(ptr):
+    if not isinstance(lltype.typeOf(ptr), lltype.Ptr):
+        raise TypeError("arg must be a pointer, got %r instead" % (
+            typeOf(ptr),))
+
+def checkadr(adr):
+    if lltype.typeOf(adr) is not llmemory.Address:
+        raise TypeError("arg must be an address, got %r instead" % (
+            typeOf(adr),))
+
+
+def op_ptr_eq(ptr1, ptr2):
+    checkptr(ptr1)
+    checkptr(ptr2)
+    return ptr1 == ptr2
+
+def op_ptr_ne(ptr1, ptr2):
+    checkptr(ptr1)
+    checkptr(ptr2)
+    return ptr1 != ptr2
+
+def op_ptr_nonzero(ptr1):
+    checkptr(ptr1)
+    return bool(ptr1)
+
+def op_ptr_iszero(ptr1):
+    checkptr(ptr1)
+    return not bool(ptr1)
+
+def op_getsubstruct(obj, field):
+    checkptr(obj)
+    # check the difference between op_getfield and op_getsubstruct:
+    assert isinstance(getattr(lltype.typeOf(obj).TO, field),
+                      lltype.ContainerType)
+    return getattr(obj, field)
+
+def op_getarraysubstruct(array, index):
+    checkptr(array)
+    result = array[index]
+    return result
+    # the diff between op_getarrayitem and op_getarraysubstruct
+    # is the same as between op_getfield and op_getsubstruct
+
+def op_getarraysize(array):
+    checkptr(array)
+    return len(array)
+
+def op_direct_fieldptr(obj, field):
+    checkptr(obj)
+    assert isinstance(field, str)
+    return lltype.direct_fieldptr(obj, field)
+
+def op_direct_arrayitems(obj):
+    checkptr(obj)
+    return lltype.direct_arrayitems(obj)
+
+def op_direct_ptradd(obj, index):
+    checkptr(obj)
+    assert isinstance(index, int)
+    return lltype.direct_ptradd(obj, index)
+
+
+def op_bool_not(b):
+    assert type(b) is bool
+    return not b
+
+def op_int_add(x, y):
+    assert isinstance(x, (int, llmemory.AddressOffset))
+    assert isinstance(y, (int, llmemory.AddressOffset))
+    return intmask(x + y)
+
+def op_int_mul(x, y):
+    assert isinstance(x, (int, llmemory.AddressOffset))
+    assert isinstance(y, int)
+    return intmask(x * y)
+
+
+def op_same_as(x):
+    return x
+
+def op_cast_primitive(TYPE, value):
+    assert isinstance(lltype.typeOf(value), lltype.Primitive)
+    return lltype.cast_primitive(TYPE, value)
+op_cast_primitive.need_result_type = True
+
+def op_cast_int_to_float(i):
+    assert type(i) is int
+    return float(i)
+
+def op_cast_int_to_char(b):
+    assert type(b) is int
+    return chr(b)
+
+def op_cast_bool_to_int(b):
+    assert type(b) is bool
+    return int(b)
+
+def op_cast_bool_to_uint(b):
+    assert type(b) is bool
+    return r_uint(int(b))
+
+def op_cast_bool_to_float(b):
+    assert type(b) is bool
+    return float(b)
+
+def op_cast_float_to_uint(f):
+    assert type(f) is float
+    return r_uint(int(f))
+
+def op_cast_char_to_int(b):
+    assert type(b) is str and len(b) == 1
+    return ord(b)
+
+def op_cast_unichar_to_int(b):
+    assert type(b) is unicode and len(b) == 1
+    return ord(b)
+
+def op_cast_int_to_unichar(b):
+    assert type(b) is int 
+    return unichr(b)
+
+def op_cast_int_to_uint(b):
+    assert type(b) is int
+    return r_uint(b)
+
+def op_cast_uint_to_int(b):
+    assert type(b) is r_uint
+    return intmask(b)
+
+def op_cast_int_to_longlong(b):
+    assert type(b) is int
+    return r_longlong(b)
+
+def op_truncate_longlong_to_int(b):
+    assert type(b) is r_longlong
+    assert -sys.maxint-1 <= b <= sys.maxint
+    return int(b)
+
+def op_float_floor(b):
+    assert type(b) is float
+    return math.floor(b)
+
+def op_float_fmod(b,c):
+    assert type(b) is float
+    assert type(c) is float
+    return math.fmod(b,c)
+
+def op_float_pow(b,c):
+    assert type(b) is float
+    assert type(c) is float
+    return math.pow(b,c)
+
+
+def op_cast_pointer(RESTYPE, obj):
+    checkptr(obj)
+    return lltype.cast_pointer(RESTYPE, obj)
+op_cast_pointer.need_result_type = True
+
+def op_cast_opaque_ptr(RESTYPE, obj):
+    checkptr(obj)
+    return lltype.cast_opaque_ptr(RESTYPE, obj)
+op_cast_opaque_ptr.need_result_type = True
+
+def op_cast_ptr_to_weakadr(ptr):
+    checkptr(ptr)
+    return llmemory.cast_ptr_to_weakadr(ptr)
+
+def op_cast_weakadr_to_ptr(TYPE, wadr):
+    assert lltype.typeOf(wadr) == llmemory.WeakGcAddress
+    return llmemory.cast_weakadr_to_ptr(wadr, TYPE)
+op_cast_weakadr_to_ptr.need_result_type = True
+
+def op_cast_weakadr_to_int(wadr):
+    assert lltype.typeOf(wadr) == llmemory.WeakGcAddress
+    return wadr.cast_to_int()
+
+def op_cast_ptr_to_adr(ptr):
+    checkptr(ptr)
+    return llmemory.cast_ptr_to_adr(ptr)
+
+def op_cast_adr_to_ptr(TYPE, adr):
+    checkadr(adr)
+    return llmemory.cast_adr_to_ptr(adr, TYPE)
+op_cast_adr_to_ptr.need_result_type = True
+
+def op_cast_adr_to_int(adr):
+    checkadr(adr)
+    return llmemory.cast_adr_to_int(adr)
+
+
+def op_unichar_eq(x, y):
+    assert isinstance(x, unicode) and len(x) == 1
+    assert isinstance(y, unicode) and len(y) == 1
+    return x == y
+
+def op_unichar_ne(x, y):
+    assert isinstance(x, unicode) and len(x) == 1
+    assert isinstance(y, unicode) and len(y) == 1
+    return x != y
+
+
+def op_adr_lt(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 < addr2
+
+def op_adr_le(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 <= addr2
+
+def op_adr_eq(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 == addr2
+
+def op_adr_ne(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 != addr2
+
+def op_adr_gt(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 > addr2
+
+def op_adr_ge(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 >= addr2
+
+def op_adr_add(addr, offset):
+    checkadr(addr)
+    assert lltype.typeOf(offset) is lltype.Signed
+    return addr + offset
+
+def op_adr_sub(addr, offset):
+    checkadr(addr)
+    assert lltype.typeOf(offset) is lltype.Signed
+    return addr - offset
+
+def op_adr_delta(addr1, addr2):
+    checkadr(addr1)
+    checkadr(addr2)
+    return addr1 - addr2
+
+# ____________________________________________________________
+
+def get_op_impl(opname):
+    # get the op_xxx() function from the globals above
+    try:
+        return globals()['op_' + opname]
+    except KeyError:
+        return get_primitive_op_src(opname)

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_lloperation.py	Sun Jun 25 12:35:09 2006
@@ -1,9 +1,8 @@
 from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop
+from pypy.rpython.lltypesystem import lltype, opimpl
 from pypy.rpython.llinterp import LLFrame
 from pypy.rpython.test.test_llinterp import interpret
 
-# This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync.
-
 LL_INTERP_OPERATIONS = [name[3:] for name in LLFrame.__dict__.keys()
                                  if name.startswith('op_')
 # Ignore OO operations for now
@@ -14,21 +13,37 @@
                                              name == 'op_runtimenew' or
                                              name.startswith('op_oo'))]
 
+# ____________________________________________________________
+
+def test_canfold_opimpl_complete():
+    for opname, llop in LL_OPERATIONS.items():
+        assert opname == llop.opname
+        if llop.canfold:
+            func = opimpl.get_op_impl(opname)
+            assert callable(func)
+
+def test_llop_fold():
+    assert llop.int_add(lltype.Signed, 10, 2) == 12
+    assert llop.int_add(lltype.Signed, -6, -7) == -13
+
+def test_llop_interp():
+    from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy
+    def llf(x, y):
+        return llop.int_add(lltype.Signed, x, y)
+    res = interpret(llf, [5, 7], policy=LowLevelAnnotatorPolicy())
+    assert res == 12
+
+# ___________________________________________________________________________
+# This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync.
 
 def test_table_complete():
     for opname in LL_INTERP_OPERATIONS:
         assert opname in LL_OPERATIONS
 
 def test_llinterp_complete():
-    for opname in LL_OPERATIONS:
+    for opname, llop in LL_OPERATIONS.items():
+        if llop.canfold:
+            continue
         if opname.startswith('gc_x_'):
             continue   # ignore experimental stuff
         assert opname in LL_INTERP_OPERATIONS
-
-def test_llop():
-    from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy
-    from pypy.rpython.lltypesystem import lltype
-    def llf(x, y):
-        return llop.int_add(lltype.Signed, x, y)
-    res = interpret(llf, [5, 7], policy=LowLevelAnnotatorPolicy())
-    assert res == 12

Modified: pypy/dist/pypy/rpython/rarithmetic.py
==============================================================================
--- pypy/dist/pypy/rpython/rarithmetic.py	(original)
+++ pypy/dist/pypy/rpython/rarithmetic.py	Sun Jun 25 12:35:09 2006
@@ -29,7 +29,7 @@
 
 """
 import math
-from pypy.rpython import extregistry
+from pypy.rpython import extregistry, objectmodel
 
 # set up of machine internals
 _bits = 0
@@ -49,6 +49,8 @@
         return int(n)   # possibly bool->int
     if isinstance(n, unsigned_int):
         n = long(n)
+    elif isinstance(n, objectmodel.Symbolic):
+        return n        # assume Symbolics don't overflow
     n &= LONG_MASK
     if n >= LONG_TEST:
         n -= 2*LONG_TEST



More information about the Pypy-commit mailing list