[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