[pypy-commit] pypy jit-dynamic-getarrayitem: start working on the JIT optimization

alex_gaynor noreply at buildbot.pypy.org
Sun Nov 13 18:13:14 CET 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: jit-dynamic-getarrayitem
Changeset: r49373:48644296897a
Date: 2011-11-13 02:02 -0500
http://bitbucket.org/pypy/pypy/changeset/48644296897a/

Log:	start working on the JIT optimization

diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -1403,6 +1403,7 @@
     struct = array._obj.container.getitem(index)
     return cast_to_ptr(_getinteriorfield_gc(struct, fieldnum))
 
+
 def _getfield_raw(struct, fieldnum):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
     ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
@@ -1479,7 +1480,7 @@
     return do_setinteriorfield_gc
 do_setinteriorfield_gc_int = new_setinteriorfield_gc(cast_from_int)
 do_setinteriorfield_gc_float = new_setinteriorfield_gc(cast_from_floatstorage)
-do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)        
+do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)
 
 def do_setfield_raw_int(struct, fieldnum, newvalue):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -329,6 +329,18 @@
         token = history.getkind(getattr(S, fieldname))
         return self.getdescr(ofs, token[0], name=fieldname, extrainfo=ofs2)
 
+    def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
+        is_pointer, is_float, is_signed):
+
+        if is_pointer:
+            typeinfo = REF
+        elif is_float:
+            typeinfo = FLOAT
+        else:
+            typeinfo = INT
+        # we abuse the arg_types field to distinguish dynamic and static descrs
+        return self.getdescr(offset, typeinfo, arg_types='dynamic', name='<dynamic interior field>', extrainfo=width)
+
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
         arg_types = []
         for ARG in ARGS:
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -48,6 +48,8 @@
     OS_LIBFFI_PREPARE           = 60
     OS_LIBFFI_PUSH_ARG          = 61
     OS_LIBFFI_CALL              = 62
+    OS_LIBFFI_GETARRAYITEM      = 63
+    OS_LIBFFI_SETARRAYITEM      = 64
     #
     OS_LLONG_INVERT             = 69
     OS_LLONG_ADD                = 70
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1615,6 +1615,12 @@
         elif oopspec_name.startswith('libffi_call_'):
             oopspecindex = EffectInfo.OS_LIBFFI_CALL
             extraeffect = EffectInfo.EF_RANDOM_EFFECTS
+        elif oopspec_name == 'libffi_array_getitem':
+            oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
+        elif oopspec_name == 'libffi_array_setitem':
+            oopspecindex = EffectInfo.OS_LIBFFI_SETARRAYITEM
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
         else:
             assert False, 'unsupported oopspec: %s' % oopspec_name
         return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -130,6 +130,16 @@
     else:
         return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr))
 
+def do_getinteriorfield_raw(cpu, _, arraybox, indexbox, descr):
+    array = arraybox.getref_base()
+    index = indexbox.getint()
+    if descr.is_pointer_field():
+        return BoxPtr(cpu.bh_getinteriorfield_raw_r(array, index, descr))
+    elif descr.is_float_field():
+        return BoxFloat(cpu.bh_getinteriorfield_raw_f(array, index, descr))
+    else:
+        return BoxInt(cpu.bh_getionteriorfield_raw_i(array, index, descr))
+
 def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, descr):
     array = arraybox.getref_base()
     index = indexbox.getint()
@@ -143,6 +153,7 @@
         cpu.bh_setinteriorfield_gc_i(array, index, descr,
                                      valuebox.getint())
 
+
 def do_getfield_gc(cpu, _, structbox, fielddescr):
     struct = structbox.getref_base()
     if fielddescr.is_pointer_field():
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -1,11 +1,13 @@
+from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.rlib import clibffi, libffi
+from pypy.rlib.debug import debug_print
+from pypy.rlib.libffi import Func
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.libffi import Func
-from pypy.rlib.debug import debug_print
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.rpython.lltypesystem import llmemory
 
 
 class FuncInfo(object):
@@ -78,7 +80,7 @@
 
     def new(self):
         return OptFfiCall()
-    
+
     def begin_optimization(self, funcval, op):
         self.rollback_maybe('begin_optimization', op)
         self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op)
@@ -116,6 +118,8 @@
             ops = self.do_push_arg(op)
         elif oopspec == EffectInfo.OS_LIBFFI_CALL:
             ops = self.do_call(op)
+        elif oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM:
+            ops = self.do_getarrayitem(op)
         #
         for op in ops:
             self.emit_operation(op)
@@ -190,6 +194,48 @@
         ops.append(newop)
         return ops
 
+    def do_getarrayitem(self, op):
+        ffitypeval = self.getvalue(op.getarg(1))
+        widthval = self.getvalue(op.getarg(2))
+        offsetval = self.getvalue(op.getarg(5))
+        if not ffitypeval.is_constant() or not widthval.is_constant() or not offsetval.is_constant():
+            return [op]
+
+        ffitypeaddr = ffitypeval.box.getaddr()
+        ffitype = llmemory.cast_adr_to_ptr(ffitypeaddr, clibffi.FFI_TYPE_P)
+        offset = offsetval.box.getint()
+        width = offsetval.box.getint()
+        descr = self._get_interior_descr(ffitype, width, offset)
+
+        arglist = [
+            self.getvalue(op.getarg(3)).force_box(self.optimizer),
+            self.getvalue(op.getarg(4)).force_box(self.optimizer),
+        ]
+        return [
+            ResOperation(
+                rop.GETINTERIORFIELD_RAW, arglist, op.result, descr=descr
+            )
+        ]
+
+    def _get_interior_descr(self, ffitype, width, offset):
+        kind = libffi.types.getkind(ffitype)
+        is_pointer = is_float = is_signed = False
+        if ffitype is libffi.types.pointer:
+            is_pointer = True
+        elif kind == 'i':
+            is_signed = True
+        elif kind == 'f' or kind == 'I' or kind == 'U':
+            # longlongs are treated as floats, see
+            # e.g. llsupport/descr.py:getDescrClass
+            is_float = True
+        else:
+            assert False, "unsupported ffitype or kind"
+        #
+        fieldsize = ffitype.c_size
+        return self.optimizer.cpu.interiorfielddescrof_dynamic(
+            offset, width, fieldsize, is_pointer, is_float, is_signed
+        )
+
     def propagate_forward(self, op):
         if self.logops is not None:
             debug_print(self.logops.repr_of_resop(op))
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -461,6 +461,7 @@
     'GETARRAYITEM_GC/2d',
     'GETARRAYITEM_RAW/2d',
     'GETINTERIORFIELD_GC/2d',
+    'GETINTERIORFIELD_RAW/2d',
     'GETFIELD_GC/1d',
     'GETFIELD_RAW/1d',
     '_MALLOC_FIRST',
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -100,57 +100,55 @@
     def test_array_fields(self):
         myjitdriver = JitDriver(
             greens = [],
-            reds = ["n", "i", "signed_size", "points", "result_point"],
+            reds = ["n", "i", "points", "result_point"],
         )
 
         POINT = lltype.Struct("POINT",
             ("x", lltype.Signed),
             ("y", lltype.Signed),
         )
-        def f(n):
-            points = lltype.malloc(rffi.CArray(POINT), n, flavor="raw")
-            for i in xrange(n):
-                points[i].x = i * 2
-                points[i].y = i * 2 + 1
-            points = rffi.cast(rffi.CArrayPtr(lltype.Char), points)
-            result_point = lltype.malloc(rffi.CArray(POINT), 1, flavor="raw")
-            result_point[0].x = 0
-            result_point[0].y = 0
-            result_point = rffi.cast(rffi.CArrayPtr(lltype.Char), result_point)
+        def f(points, result_point, n):
             i = 0
-            signed_size = rffi.sizeof(lltype.Signed)
             while i < n:
                 myjitdriver.jit_merge_point(i=i, points=points, n=n,
-                                            signed_size=signed_size,
                                             result_point=result_point)
                 x = array_getitem(
-                    types.slong, signed_size * 2, points, i, 0
+                    types.slong, rffi.sizeof(lltype.Signed) * 2, points, i, 0
                 )
                 y = array_getitem(
-                    types.slong, signed_size * 2, points, i, signed_size
+                    types.slong, rffi.sizeof(lltype.Signed) * 2, points, i, rffi.sizeof(lltype.Signed)
                 )
 
                 cur_x = array_getitem(
-                    types.slong, signed_size * 2, result_point, 0, 0
+                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, 0
                 )
                 cur_y = array_getitem(
-                    types.slong, signed_size * 2, result_point, 0, signed_size
+                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, rffi.sizeof(lltype.Signed)
                 )
 
                 array_setitem(
-                    types.slong, signed_size * 2, result_point, 0, 0, cur_x + x
+                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, 0, cur_x + x
                 )
                 array_setitem(
-                    types.slong, signed_size * 2, result_point, 0, signed_size, cur_y + y
+                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, rffi.sizeof(lltype.Signed), cur_y + y
                 )
                 i += 1
-            result_point = rffi.cast(rffi.CArrayPtr(POINT), result_point)
-            result = result_point[0].x * result_point[0].y
-            lltype.free(result_point, flavor="raw")
-            lltype.free(points, flavor="raw")
-            return result
 
-        assert self.meta_interp(f, [10]) == f(10) == 9000
+        def main(n):
+            with lltype.scoped_alloc(rffi.CArray(POINT), n) as points:
+                with lltype.scoped_alloc(rffi.CArray(POINT), 1) as result_point:
+                    for i in xrange(n):
+                        points[i].x = i * 2
+                        points[i].y = i * 2 + 1
+                    points = rffi.cast(rffi.CArrayPtr(lltype.Char), points)
+                    result_point[0].x = 0
+                    result_point[0].y = 0
+                    result_point = rffi.cast(rffi.CArrayPtr(lltype.Char), result_point)
+                    f(points, result_point, n)
+                    result_point = rffi.cast(rffi.CArrayPtr(POINT), result_point)
+                    return result_point[0].x * result_point[0].y
+
+        assert self.meta_interp(main, [10]) == main(10) == 9000
         self.check_loops({"int_add": 3, "jump": 1, "int_lt": 1,
                           "getinteriorfield_raw": 4, "setinteriorfield_raw": 2
         })
diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -411,7 +411,7 @@
     def getaddressindll(self, name):
         return dlsym(self.lib, name)
 
- at jit.oopspec("libffi_array_getitem")
+ at jit.oopspec("libffi_array_getitem(ffitype, width, addr, index, offset)")
 def array_getitem(ffitype, width, addr, index, offset):
     for TYPE, ffitype2 in clibffi.ffitype_map:
         if ffitype is ffitype2:
@@ -420,7 +420,7 @@
             return rffi.cast(rffi.CArrayPtr(TYPE), addr)[0]
     assert False
 
- at jit.oopspec("libffi_array_setitem")
+ at jit.oopspec("libffi_array_setitem(ffitype, width, addr, index, offset, value)")
 def array_setitem(ffitype, width, addr, index, offset, value):
     for TYPE, ffitype2 in clibffi.ffitype_map:
         if ffitype is ffitype2:


More information about the pypy-commit mailing list