[pypy-commit] pypy ffi-backend: In-progress: JIT support for ffi_call
arigo
noreply at buildbot.pypy.org
Thu Aug 2 22:42:04 CEST 2012
Author: Armin Rigo <arigo at 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)
+ at 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()
More information about the pypy-commit
mailing list