[pypy-commit] pypy ffistruct: merge heads
antocuni
noreply at buildbot.pypy.org
Fri Sep 9 16:51:50 CEST 2011
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: ffistruct
Changeset: r47188:5219d5921d77
Date: 2011-09-09 16:51 +0200
http://bitbucket.org/pypy/pypy/changeset/5219d5921d77/
Log: merge heads
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
@@ -764,7 +764,9 @@
op_getfield_gc_pure = op_getfield_gc
def op_getfield_raw(self, fielddescr, struct):
- if fielddescr.typeinfo == REF:
+ if fielddescr.arg_types == 'dynamic': # abuse of .arg_types
+ return do_getfield_raw_dynamic(struct, fielddescr)
+ elif fielddescr.typeinfo == REF:
return do_getfield_raw_ptr(struct, fielddescr.ofs)
elif fielddescr.typeinfo == INT:
return do_getfield_raw_int(struct, fielddescr.ofs)
@@ -817,7 +819,9 @@
raise NotImplementedError
def op_setfield_raw(self, fielddescr, struct, newvalue):
- if fielddescr.typeinfo == REF:
+ if fielddescr.arg_types == 'dynamic': # abuse of .arg_types
+ do_setfield_raw_dynamic(struct, fielddescr, newvalue)
+ elif fielddescr.typeinfo == REF:
do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue)
elif fielddescr.typeinfo == INT:
do_setfield_raw_int(struct, fielddescr.ofs, newvalue)
@@ -1370,6 +1374,17 @@
def do_getfield_raw_ptr(struct, fieldnum):
return cast_to_ptr(_getfield_raw(struct, fieldnum))
+def do_getfield_raw_dynamic(struct, fielddescr):
+ from pypy.rlib import libffi
+ addr = cast_from_int(rffi.VOIDP, struct)
+ ofs = fielddescr.ofs
+ if fielddescr.is_pointer_field():
+ assert False, 'fixme'
+ elif fielddescr.is_float_field():
+ assert False, 'fixme'
+ else:
+ return libffi._struct_getfield(lltype.Signed, addr, ofs)
+
def do_new(size):
TYPE = symbolic.Size2Type[size]
x = lltype.malloc(TYPE, zero=True)
@@ -1453,6 +1468,17 @@
newvalue = cast_from_ptr(FIELDTYPE, newvalue)
setattr(ptr, fieldname, newvalue)
+def do_setfield_raw_dynamic(struct, fielddescr, newvalue):
+ from pypy.rlib import libffi
+ addr = cast_from_int(rffi.VOIDP, struct)
+ ofs = fielddescr.ofs
+ if fielddescr.is_pointer_field():
+ assert False, 'fixme'
+ elif fielddescr.is_float_field():
+ assert False, 'fixme'
+ else:
+ libffi._struct_setfield(lltype.Signed, addr, ofs, newvalue)
+
def do_newstr(length):
x = rstr.mallocstr(length)
return cast_to_ptr(x)
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
@@ -316,6 +316,16 @@
token = history.getkind(getattr(S, fieldname))
return self.getdescr(ofs, token[0], name=fieldname)
+ def fielddescrof_dynamic(self, offset, 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 field>')
+
def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
arg_types = []
for ARG in ARGS:
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -113,6 +113,17 @@
def repr_of_descr(self):
return '<%s %s %s>' % (self._clsname, self.name, self.offset)
+class DynamicFieldDescr(BaseFieldDescr):
+
+ def __init__(self, offset, fieldsize, is_pointer, is_float, is_signed):
+ self.offset = offset
+ self._fieldsize = fieldsize
+ self._is_pointer_field = is_pointer
+ self._is_float_field = is_float
+ self._is_field_signed = is_signed
+
+ def get_field_size(self, translate_support_code):
+ return self._fieldsize
class NonGcPtrFieldDescr(BaseFieldDescr):
_clsname = 'NonGcPtrFieldDescr'
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -13,6 +13,7 @@
from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes
from pypy.jit.backend.llsupport.descr import get_size_descr, BaseSizeDescr
from pypy.jit.backend.llsupport.descr import get_field_descr, BaseFieldDescr
+from pypy.jit.backend.llsupport.descr import DynamicFieldDescr
from pypy.jit.backend.llsupport.descr import get_array_descr, BaseArrayDescr
from pypy.jit.backend.llsupport.descr import get_call_descr
from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr
@@ -225,6 +226,9 @@
def fielddescrof(self, STRUCT, fieldname):
return get_field_descr(self.gc_ll_descr, STRUCT, fieldname)
+ def fielddescrof_dynamic(self, offset, fieldsize, is_pointer, is_float, is_signed):
+ return DynamicFieldDescr(offset, fieldsize, is_pointer, is_float, is_signed)
+
def unpack_fielddescr(self, fielddescr):
assert isinstance(fielddescr, BaseFieldDescr)
return fielddescr.offset
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1509,20 +1509,37 @@
assert s.x == chr(190)
assert s.y == chr(150)
- def test_field_raw_pure(self):
- # This is really testing the same thing as test_field_basic but can't
- # hurt...
- S = lltype.Struct('S', ('x', lltype.Signed))
+ def test_fielddescrof_dynamic(self):
+ S = lltype.Struct('S',
+ ('x', lltype.Signed),
+ ('y', lltype.Signed),
+ )
+ longsize = rffi.sizeof(lltype.Signed)
+ y_ofs = longsize
s = lltype.malloc(S, flavor='raw')
sa = llmemory.cast_ptr_to_adr(s)
s_box = BoxInt(heaptracker.adr2int(sa))
+ #
+ field = self.cpu.fielddescrof(S, 'y')
+ field_dyn = self.cpu.fielddescrof_dynamic(offset=y_ofs,
+ fieldsize=longsize,
+ is_pointer=False,
+ is_float=False,
+ is_signed=True)
+ assert field.is_pointer_field() == field_dyn.is_pointer_field()
+ assert field.is_float_field() == field_dyn.is_float_field()
+ if 'llgraph' not in str(self.cpu):
+ assert field.is_field_signed() == field_dyn.is_field_signed()
+
+ #
for get_op, set_op in ((rop.GETFIELD_RAW, rop.SETFIELD_RAW),
(rop.GETFIELD_RAW_PURE, rop.SETFIELD_RAW)):
- fd = self.cpu.fielddescrof(S, 'x')
- self.execute_operation(set_op, [s_box, BoxInt(32)], 'void',
- descr=fd)
- res = self.execute_operation(get_op, [s_box], 'int', descr=fd)
- assert res.getint() == 32
+ for descr in (field, field_dyn):
+ self.execute_operation(set_op, [s_box, BoxInt(32)], 'void',
+ descr=descr)
+ res = self.execute_operation(get_op, [s_box], 'int', descr=descr)
+ assert res.getint() == 32
+
lltype.free(s, flavor='raw')
def test_new_with_vtable(self):
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/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
@@ -56,6 +56,13 @@
restype=types.sint,
flags=43)
#
+ ffi_slong = types.slong
+ dyn_123_field = cpu.fielddescrof_dynamic(offset=123,
+ fieldsize=types.slong.c_size,
+ is_pointer=False,
+ is_float=False,
+ is_signed=True)
+ #
def calldescr(cpu, FUNC, oopspecindex, extraeffect=None):
if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
f = None # means "can force all" really
@@ -69,6 +76,8 @@
libffi_push_arg = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_PUSH_ARG)
libffi_call = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_CALL,
EffectInfo.EF_RANDOM_EFFECTS)
+ libffi_struct_getfield = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_STRUCT_GETFIELD)
+ libffi_struct_setfield = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_STRUCT_SETFIELD)
namespace = namespace.__dict__
@@ -277,3 +286,30 @@
jump(i3, f1, p2)
"""
loop = self.optimize_loop(ops, expected)
+
+ def test_ffi_struct_fields(self):
+ ops = """
+ [i0]
+ i1 = call(0, ConstClass(ffi_slong), i0, 123, descr=libffi_struct_getfield)
+ i2 = int_add(i1, 1)
+ call(0, ConstClass(ffi_slong), i0, 123, i2, descr=libffi_struct_setfield)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ i1 = getfield_raw(i0, descr=dyn_123_field)
+ i2 = int_add(i1, 1)
+ setfield_raw(i0, i2, descr=dyn_123_field)
+ jump(i1)
+ """
+ loop = self.optimize_loop(ops, expected)
+
+ def test_ffi_struct_fields_nonconst(self):
+ ops = """
+ [i0, i1]
+ i2 = call(0, ConstClass(ffi_slong), i0, i1, descr=libffi_struct_getfield)
+ i3 = call(0, i1 , i0, 123, descr=libffi_struct_getfield)
+ jump(i1)
+ """
+ expected = ops
+ loop = self.optimize_loop(ops, expected)
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,25 @@
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