Author: Armin Rigo <ar...@tunes.org> Branch: ffi-backend Changeset: r56546:bc098624b3c9 Date: 2012-08-02 14:25 +0200 http://bitbucket.org/pypy/pypy/changeset/bc098624b3c9/
Log: In-progress: JIT support for ffi_call diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py --- a/pypy/jit/backend/llsupport/ffisupport.py +++ b/pypy/jit/backend/llsupport/ffisupport.py @@ -1,43 +1,40 @@ from pypy.rlib.rarithmetic import intmask -from pypy.jit.metainterp import history from pypy.rpython.lltypesystem import rffi from pypy.jit.backend.llsupport.descr import CallDescr class UnsupportedKind(Exception): pass -def get_call_descr_dynamic(cpu, ffi_args, ffi_result, extrainfo, ffi_flags): - """Get a call descr: the types of result and args are represented by - rlib.libffi.types.*""" +def get_call_descr_dynamic(cpu, cif_description, extrainfo): + """Get a call descr from the given CIF_DESCRIPTION""" + ffi_result = cif_description.rtype try: reskind = get_ffi_type_kind(cpu, ffi_result) - argkinds = [get_ffi_type_kind(cpu, arg) for arg in ffi_args] + argkinds = [get_ffi_type_kind(cpu, atype) + for atype in cif_description.atypes] except UnsupportedKind: return None - if reskind == history.VOID: + if reskind == 'v': result_size = 0 else: result_size = intmask(ffi_result.c_size) argkinds = ''.join(argkinds) return CallDescr(argkinds, reskind, is_ffi_type_signed(ffi_result), - result_size, extrainfo, ffi_flags=ffi_flags) + result_size, extrainfo, ffi_flags=cif_description.abi) def get_ffi_type_kind(cpu, ffi_type): - from pypy.rlib.libffi import types + from pypy.rlib.jit_libffi import types kind = types.getkind(ffi_type) - if kind == 'i' or kind == 'u': - return history.INT - elif cpu.supports_floats and kind == 'f': - return history.FLOAT - elif kind == 'v': - return history.VOID - elif cpu.supports_longlong and (kind == 'I' or kind == 'U'): # longlong - return 'L' - elif cpu.supports_singlefloats and kind == 's': # singlefloat - return 'S' - raise UnsupportedKind("Unsupported kind '%s'" % kind) + if ((not cpu.supports_floats and kind == 'f') or + (not cpu.supports_longlong and kind == 'L') or + (not cpu.supports_singlefloats and kind == 'S') or + kind == '*'): + raise UnsupportedKind("Unsupported kind '%s'" % kind) + if kind == 'u': + kind = 'i' + return kind def is_ffi_type_signed(ffi_type): - from pypy.rlib.libffi import types + from pypy.rlib.jit_libffi import types kind = types.getkind(ffi_type) return kind != 'u' 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 @@ -280,10 +280,10 @@ def calldescrof(self, FUNC, ARGS, RESULT, extrainfo): return get_call_descr(self.gc_ll_descr, ARGS, RESULT, extrainfo) - def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo, ffi_flags): + def calldescrof_dynamic(self, cif_description, extrainfo): from pypy.jit.backend.llsupport import ffisupport - return ffisupport.get_call_descr_dynamic(self, ffi_args, ffi_result, - extrainfo, ffi_flags) + return ffisupport.get_call_descr_dynamic(self, cif_description, + extrainfo) def get_overflow_error(self): ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable) diff --git a/pypy/jit/backend/llsupport/test/test_ffisupport.py b/pypy/jit/backend/llsupport/test/test_ffisupport.py --- a/pypy/jit/backend/llsupport/test/test_ffisupport.py +++ b/pypy/jit/backend/llsupport/test/test_ffisupport.py @@ -1,4 +1,5 @@ -from pypy.rlib.libffi import types +from pypy.rlib.jit_libffi import types, CIF_DESCRIPTION, FFI_TYPE_PP +from pypy.rpython.lltypesystem import lltype, rffi from pypy.jit.codewriter.longlong import is_64_bit from pypy.jit.backend.llsupport.descr import * from pypy.jit.backend.llsupport.ffisupport import * @@ -12,11 +13,21 @@ self.supports_longlong = supports_longlong self.supports_singlefloats = supports_singlefloats +def grab(cpu, atypes, rtype): + p = lltype.malloc(CIF_DESCRIPTION, len(atypes), + flavor='raw', immortal=True) + rffi.setintfield(p, 'abi', 42) + p.nargs = len(atypes) + p.rtype = rtype + p.atypes = lltype.malloc(FFI_TYPE_PP.TO, len(atypes), + flavor='raw', immortal=True) + for i in range(len(atypes)): + p.atypes[i] = atypes[i] + return get_call_descr_dynamic(cpu, p, None) def test_call_descr_dynamic(): args = [types.sint, types.pointer] - descr = get_call_descr_dynamic(FakeCPU(), args, types.sint, None, - ffi_flags=42) + descr = grab(FakeCPU(), args, types.sint) assert isinstance(descr, CallDescr) assert descr.result_type == 'i' assert descr.result_flag == FLAG_SIGNED @@ -24,43 +35,39 @@ assert descr.get_ffi_flags() == 42 args = [types.sint, types.double, types.pointer] - descr = get_call_descr_dynamic(FakeCPU(), args, types.void, None, 42) + descr = grab(FakeCPU(), args, types.void) assert descr is None # missing floats - descr = get_call_descr_dynamic(FakeCPU(supports_floats=True), - args, types.void, None, ffi_flags=43) + descr = grab(FakeCPU(supports_floats=True), args, types.void) assert descr.result_type == 'v' assert descr.result_flag == FLAG_VOID assert descr.arg_classes == 'ifi' - assert descr.get_ffi_flags() == 43 + assert descr.get_ffi_flags() == 42 - descr = get_call_descr_dynamic(FakeCPU(), [], types.sint8, None, 42) + descr = grab(FakeCPU(), [], types.sint8) assert descr.get_result_size() == 1 assert descr.result_flag == FLAG_SIGNED assert descr.is_result_signed() == True - descr = get_call_descr_dynamic(FakeCPU(), [], types.uint8, None, 42) + descr = grab(FakeCPU(), [], types.uint8) assert isinstance(descr, CallDescr) assert descr.get_result_size() == 1 assert descr.result_flag == FLAG_UNSIGNED assert descr.is_result_signed() == False if not is_64_bit or is_emulated_long: - descr = get_call_descr_dynamic(FakeCPU(), [], types.slonglong, - None, 42) + descr = grab(FakeCPU(), [], types.slonglong) assert descr is None # missing longlongs - descr = get_call_descr_dynamic(FakeCPU(supports_longlong=True), - [], types.slonglong, None, ffi_flags=43) + descr = grab(FakeCPU(supports_longlong=True), [], types.slonglong) assert isinstance(descr, CallDescr) assert descr.result_flag == FLAG_FLOAT assert descr.result_type == 'L' - assert descr.get_ffi_flags() == 43 + assert descr.get_ffi_flags() == 42 else: assert types.slonglong is types.slong - descr = get_call_descr_dynamic(FakeCPU(), [], types.float, None, 42) + descr = grab(FakeCPU(), [], types.float) assert descr is None # missing singlefloats - descr = get_call_descr_dynamic(FakeCPU(supports_singlefloats=True), - [], types.float, None, ffi_flags=44) + descr = grab(FakeCPU(supports_singlefloats=True), [], types.float) assert descr.result_flag == FLAG_UNSIGNED assert descr.result_type == 'S' - assert descr.get_ffi_flags() == 44 + assert descr.get_ffi_flags() == 42 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 @@ -45,13 +45,7 @@ OS_UNIEQ_LENGTHOK = 51 # _OS_offset_uni = OS_UNI_CONCAT - OS_STR_CONCAT # - OS_LIBFFI_PREPARE = 60 - OS_LIBFFI_PUSH_ARG = 61 OS_LIBFFI_CALL = 62 - OS_LIBFFI_STRUCT_GETFIELD = 63 - OS_LIBFFI_STRUCT_SETFIELD = 64 - OS_LIBFFI_GETARRAYITEM = 65 - OS_LIBFFI_SETARRAYITEM = 66 # 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 @@ -1728,27 +1728,9 @@ # rlib.libffi def _handle_libffi_call(self, op, oopspec_name, args): - if oopspec_name == 'libffi_prepare_call': - oopspecindex = EffectInfo.OS_LIBFFI_PREPARE - extraeffect = EffectInfo.EF_CANNOT_RAISE - elif oopspec_name.startswith('libffi_push_'): - oopspecindex = EffectInfo.OS_LIBFFI_PUSH_ARG - extraeffect = EffectInfo.EF_CANNOT_RAISE - elif oopspec_name.startswith('libffi_call_'): + if oopspec_name == '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 - 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/codewriter/support.py b/pypy/jit/codewriter/support.py --- a/pypy/jit/codewriter/support.py +++ b/pypy/jit/codewriter/support.py @@ -431,31 +431,6 @@ return llop.uint_mod(lltype.Unsigned, xll, yll) -# libffi support -# -------------- - -def func(llfunc): - from pypy.rlib.libffi import Func - return cast_base_ptr_to_instance(Func, llfunc) - -def _ll_1_libffi_prepare_call(llfunc): - return func(llfunc)._prepare() - -def _ll_4_libffi_push_int(llfunc, value, ll_args, i): - return func(llfunc)._push_int(value, ll_args, i) - -def _ll_4_libffi_push_float(llfunc, value, ll_args, i): - return func(llfunc)._push_float(value, ll_args, i) - -def _ll_3_libffi_call_int(llfunc, funcsym, ll_args): - return func(llfunc)._do_call(funcsym, ll_args, rffi.LONG) - -def _ll_3_libffi_call_float(llfunc, funcsym, ll_args): - return func(llfunc)._do_call(funcsym, ll_args, rffi.DOUBLE) - -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/rlib/clibffi.py b/pypy/rlib/clibffi.py --- a/pypy/rlib/clibffi.py +++ b/pypy/rlib/clibffi.py @@ -202,7 +202,7 @@ FFI_TYPE_P.TO.become(cConfig.ffi_type) size_t = cConfig.size_t -ffi_abi = cConfig.ffi_abi +FFI_ABI = cConfig.ffi_abi ffi_arg = cConfig.ffi_arg for name in type_names: @@ -333,7 +333,7 @@ VOIDPP = rffi.CArrayPtr(rffi.VOIDP) -c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, ffi_abi, rffi.UINT, +c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, FFI_ABI, rffi.UINT, FFI_TYPE_P, FFI_TYPE_PP], rffi.INT) if _MSVC: c_ffi_call_return_type = rffi.INT diff --git a/pypy/rlib/jit_libffi.py b/pypy/rlib/jit_libffi.py --- a/pypy/rlib/jit_libffi.py +++ b/pypy/rlib/jit_libffi.py @@ -1,12 +1,13 @@ import sys from pypy.rpython.lltypesystem import lltype, rffi -from pypy.rlib import clibffi +from pypy.rlib import clibffi, jit FFI_CIF = clibffi.FFI_CIFP.TO FFI_TYPE = clibffi.FFI_TYPE_P.TO FFI_TYPE_P = clibffi.FFI_TYPE_P FFI_TYPE_PP = clibffi.FFI_TYPE_PP +FFI_ABI = clibffi.FFI_ABI SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg) # "cif_description" is a block of raw memory describing how to do the call. @@ -29,10 +30,13 @@ CIF_DESCRIPTION = lltype.Struct( 'CIF_DESCRIPTION', ('cif', FFI_CIF), + ('abi', FFI_ABI), + ('nargs', lltype.Signed), + ('rtype', FFI_TYPE_P), + ('atypes', FFI_TYPE_PP), ('exchange_size', lltype.Signed), ('exchange_result', lltype.Signed), ('exchange_result_libffi', lltype.Signed), - ('exchange_nb_args', lltype.Signed), ('exchange_args', lltype.Array(lltype.Signed, hints={'nolength': True, 'immutable': True})), hints={'immutable': True}) @@ -40,12 +44,13 @@ CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION) +@jit.oopspec("libffi_call(cif_description, func_addr, exchange_buffer)") def jit_ffi_call(cif_description, func_addr, exchange_buffer): """Wrapper around ffi_call(). Must receive a CIF_DESCRIPTION_P that - describes the layout of the 'exchange_buffer' of size 'exchange_size'. + describes the layout of the 'exchange_buffer'. """ buffer_array = rffi.cast(rffi.VOIDPP, exchange_buffer) - for i in range(cif_description.exchange_nb_args): + for i in range(cif_description.nargs): data = rffi.ptradd(exchange_buffer, cif_description.exchange_args[i]) buffer_array[i] = data resultdata = rffi.ptradd(exchange_buffer, @@ -53,3 +58,68 @@ clibffi.c_ffi_call(cif_description.cif, func_addr, rffi.cast(rffi.VOIDP, resultdata), buffer_array) + +# ____________________________________________________________ + +class types(object): + """ + This namespace contains the mapping the JIT needs from ffi types to + a less strict "kind" character. + """ + + @classmethod + def _import(cls): + prefix = 'ffi_type_' + for key, value in clibffi.__dict__.iteritems(): + if key.startswith(prefix): + name = key[len(prefix):] + setattr(cls, name, value) + cls.slong = clibffi.cast_type_to_ffitype(rffi.LONG) + cls.ulong = clibffi.cast_type_to_ffitype(rffi.ULONG) + cls.slonglong = clibffi.cast_type_to_ffitype(rffi.LONGLONG) + cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG) + cls.signed = clibffi.cast_type_to_ffitype(rffi.SIGNED) + cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar) + del cls._import + + @staticmethod + @jit.elidable + def getkind(ffi_type): + """Returns 'v' for void, 'f' for float, 'i' for signed integer, + 'u' for unsigned integer, 'S' for singlefloat, 'L' for long long + integer (signed or unsigned), or '*' for struct. + """ + if ffi_type is types.void: return 'v' + elif ffi_type is types.double: return 'f' + elif ffi_type is types.float: return 'S' + elif ffi_type is types.pointer: return 'i' + # + elif ffi_type is types.schar: return 'i' + elif ffi_type is types.uchar: return 'u' + elif ffi_type is types.sshort: return 'i' + elif ffi_type is types.ushort: return 'u' + elif ffi_type is types.sint: return 'i' + elif ffi_type is types.uint: return 'u' + elif ffi_type is types.slong: return 'i' + elif ffi_type is types.ulong: return 'u' + # + elif ffi_type is types.sint8: return 'i' + elif ffi_type is types.uint8: return 'u' + elif ffi_type is types.sint16: return 'i' + elif ffi_type is types.uint16: return 'u' + elif ffi_type is types.sint32: return 'i' + elif ffi_type is types.uint32: return 'u' + ## (note that on 64-bit platforms, types.sint64 is types.slong and the + ## case is caught above) + elif ffi_type is types.sint64: return 'L' + elif ffi_type is types.uint64: return 'L' + # + elif types.is_struct(ffi_type): return '*' + raise KeyError + + @staticmethod + @jit.elidable + def is_struct(ffi_type): + return intmask(ffi_type.c_type) == FFI_TYPE_STRUCT + +types._import() _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit