[pypy-commit] pypy ffistruct: add a JIT optimization which turns calls to libffi.struct_{get, set}field_* into {SET, GET}FIELD_RAW. optimizeopt unit test are coming in the next checkin

antocuni noreply at buildbot.pypy.org
Fri Sep 9 15:36:14 CEST 2011


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: ffistruct
Changeset: r47183:a86930b6e9ff
Date: 2011-09-08 16:57 +0200
http://bitbucket.org/pypy/pypy/changeset/a86930b6e9ff/

Log:	add a JIT optimization which turns calls to
	libffi.struct_{get,set}field_* into {SET,GET}FIELD_RAW. optimizeopt
	unit test are coming in the next checkin

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_STRUCT_GETFIELD   = 63
+    OS_LIBFFI_STRUCT_SETFIELD   = 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
@@ -1483,6 +1483,12 @@
         elif oopspec_name.startswith('libffi_call_'):
             oopspecindex = EffectInfo.OS_LIBFFI_CALL
             extraeffect = EffectInfo.EF_RANDOM_EFFECTS
+        elif oopspec_name == 'libffi_struct_getfield':
+            oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_GETFIELD
+            extraeffect = EffectInfo.EF_CANNOT_RAISE
+        elif oopspec_name == 'libffi_struct_setfield':
+            oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_SETFIELD
+            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/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -392,7 +392,6 @@
 def _ll_3_libffi_call_void(llfunc, funcsym, ll_args):
     return func(llfunc)._do_call(funcsym, ll_args, lltype.Void)
 
-
 # in the following calls to builtins, the JIT is allowed to look inside:
 inline_calls_to = [
     ('int_floordiv_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
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,7 +1,9 @@
 from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
+from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.libffi import Func
 from pypy.rlib.debug import debug_print
+from pypy.rlib import libffi, clibffi
 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
@@ -116,6 +118,9 @@
             ops = self.do_push_arg(op)
         elif oopspec == EffectInfo.OS_LIBFFI_CALL:
             ops = self.do_call(op)
+        elif (oopspec == EffectInfo.OS_LIBFFI_STRUCT_GETFIELD or
+              oopspec == EffectInfo.OS_LIBFFI_STRUCT_SETFIELD):
+            ops = self.do_struct_getsetfield(op, oopspec)
         #
         for op in ops:
             self.emit_operation(op)
@@ -190,6 +195,46 @@
         ops.append(newop)
         return ops
 
+    def do_struct_getsetfield(self, op, oopspec):
+        ffitypeval = self.getvalue(op.getarg(1))
+        addrval = self.getvalue(op.getarg(2))
+        offsetval = self.getvalue(op.getarg(3))
+        if not ffitypeval.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()
+        descr = self._get_field_descr(ffitype, offset)
+        #
+        arglist = [addrval.force_box()]
+        if oopspec == EffectInfo.OS_LIBFFI_STRUCT_GETFIELD:
+            opnum = rop.GETFIELD_RAW
+        else:
+            opnum = rop.SETFIELD_RAW
+            newval = self.getvalue(op.getarg(4))
+            arglist.append(newval.force_box())
+        #
+        newop = ResOperation(opnum, arglist, op.result, descr=descr)
+        return [newop]
+
+    def _get_field_descr(self, ffitype, 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.fielddescrof_dynamic(offset, 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/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
@@ -3,8 +3,8 @@
 from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
 from pypy.rlib.jit import JitDriver, promote, dont_look_inside
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.libffi import ArgChain
-from pypy.rlib.libffi import IS_32_BIT
+from pypy.rlib.libffi import ArgChain, types
+from pypy.rlib.libffi import IS_32_BIT, struct_setfield_int, struct_getfield_int
 from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.objectmodel import specialize
@@ -93,5 +93,26 @@
     test_byval_result.dont_track_allocations = True
 
 
+
 class TestFfiCallSupportAll(TestFfiCall):
     supports_all = True     # supports_{floats,longlong,singlefloats}
+
+
+    def test_struct_getfield(self):
+        myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'addr'])
+
+        def f(n):
+            i = 0
+            addr = lltype.malloc(rffi.VOIDP.TO, 10, flavor='raw')
+            while i < n:
+                myjitdriver.jit_merge_point(n=n, i=i, addr=addr)
+                struct_setfield_int(types.slong, addr, 0, 1)
+                i += struct_getfield_int(types.slong, addr, 0)
+            lltype.free(addr, flavor='raw')
+            return i
+        assert self.meta_interp(f, [20]) == f(20)
+        self.check_loops(
+            setfield_raw=1,
+            getfield_raw=1,
+            call=0)
+        
diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -414,6 +414,7 @@
 
 # ======================================================================
 
+ at jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')
 def struct_getfield_int(ffitype, addr, offset):
     """
     Return the field of type ``ffitype`` at ``addr+offset``, widened to
@@ -425,6 +426,8 @@
             return rffi.cast(lltype.Signed, value)
     assert False, "cannot find the given ffitype"
 
+
+ at jit.oopspec('libffi_struct_setfield(ffitype, addr, offset, value)')
 def struct_setfield_int(ffitype, addr, offset, value):
     """
     Set the field of type ``ffitype`` at ``addr+offset``.  ``value`` is of
@@ -438,7 +441,6 @@
     assert False, "cannot find the given ffitype"
 
 
- at jit.dont_look_inside
 @specialize.arg(0)
 def _struct_getfield(TYPE, addr, offset):
     """
@@ -450,7 +452,6 @@
     return rffi.cast(PTR_FIELD, addr)[0]
 
 
- at jit.dont_look_inside
 @specialize.arg(0)
 def _struct_setfield(TYPE, addr, offset, value):
     """


More information about the pypy-commit mailing list