[pypy-svn] pypy jitypes2: ugly hack to support longlongs on 32bit and not having the jit to complain: we

antocuni commits-noreply at bitbucket.org
Mon Dec 20 18:58:32 CET 2010


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: jitypes2
Changeset: r40151:4788cf042dc2
Date: 2010-12-20 18:57 +0100
http://bitbucket.org/pypy/pypy/changeset/4788cf042dc2/

Log:	ugly hack to support longlongs on 32bit and not having the jit to
	complain: we store them as DOUBLEs (really reinterpreting the bit
	pattern) and do the conversion only around the actual ffi call.

	The current version is even worse than needed because e.g. if you do
	a .call with a LONGLONG result, you can get either a lltype.Signed
	or lltype.Float as a result, depending if you are on 64 or 32 bit.
	I'll try to improve this later

diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -30,6 +30,8 @@
                 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)
         del cls._import
 
     @staticmethod
@@ -78,6 +80,7 @@
     sz = rffi.sizeof(TYPE)
     return sz <= rffi.sizeof(rffi.LONG)
 
+
 # ======================================================================
 
 @specialize.memo()
@@ -105,6 +108,8 @@
             val = rffi.cast(rffi.LONG, val)
         elif TYPE is rffi.DOUBLE:
             cls = FloatArg
+        elif TYPE in (rffi.LONGLONG, rffi.ULONGLONG):
+            raise TypeError, 'r_(u)longlong not supported by arg(), use arg_longlong()'
         elif TYPE is rffi.FLOAT:
             raise TypeError, 'r_singlefloat not supported by arg(), use arg_singlefloat()'
         else:
@@ -112,6 +117,16 @@
         self._append(cls(val))
         return self
 
+    def arg_longlong(self, val):
+        """
+        Note: this is a hack. So far, the JIT does not support long longs, so
+        you must pass it as if it were a python Float (rffi.DOUBLE).  You can
+        use the convenience functions longlong2float and float2longlong to do
+        the conversions.  Note that if you use long longs, the call won't
+        be jitted at all.
+        """
+        self._append(LongLongArg(val))
+
     def arg_singlefloat(self, val):
         """
         Note: you must pass a python Float (rffi.DOUBLE), not a r_singlefloat
@@ -154,7 +169,7 @@
 
 
 class SingleFloatArg(AbstractArg):
-    """ An argument holding a C float
+    """ An argument representing a C float (but holding a C double)
     """
 
     def __init__(self, floatval):
@@ -164,6 +179,36 @@
         func._push_single_float(self.floatval, ll_args, i)
 
 
+class LongLongArg(AbstractArg):
+    """ An argument representing a C long long (but holding a C double)
+    """
+
+    def __init__(self, floatval):
+        self.floatval = floatval
+
+    def push(self, func, ll_args, i):
+        func._push_longlong(self.floatval, ll_args, i)
+
+
+DOUBLE_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.DOUBLE))
+LONGLONG_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.LONGLONG))
+def longlong2float(llval):
+    d_array = lltype.malloc(DOUBLE_ARRAY_PTR.TO, 1, flavor='raw')
+    ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
+    ll_array[0] = llval
+    floatval = d_array[0]
+    lltype.free(d_array, flavor='raw')
+    return floatval
+
+def float2longlong(floatval):
+    d_array = lltype.malloc(DOUBLE_ARRAY_PTR.TO, 1, flavor='raw')
+    ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
+    d_array[0] = floatval
+    llval = ll_array[0]
+    lltype.free(d_array, flavor='raw')
+    return llval
+
+
 # ======================================================================
 
 
@@ -219,6 +264,10 @@
             # XXX: even if RESULT is FLOAT, we still return a DOUBLE, else the
             # jit complains. Note that the jit is disabled in this case
             return self._do_call_single_float(self.funcsym, ll_args)
+        elif RESULT is rffi.LONGLONG:
+            # XXX: even if RESULT is LONGLONG, we still return a DOUBLE, else the
+            # jit complains. Note that the jit is disabled in this case
+            return self._do_call_longlong(self.funcsym, ll_args)
         elif RESULT is lltype.Void:
             return self._do_call_void(self.funcsym, ll_args)
         else:
@@ -256,6 +305,13 @@
     def _push_single_float(self, value, ll_args, i):
         self._push_arg(r_singlefloat(value), ll_args, i)
 
+    @jit.dont_look_inside
+    def _push_longlong(self, floatval, ll_args, i):
+        """
+        Takes a longlong represented as a python Float. It's a hack for the
+        jit, else we could not see the whole libffi module at all"""  
+        self._push_arg(float2longlong(floatval), ll_args, i)
+
     @jit.oopspec('libffi_call_int(self, funcsym, ll_args)')
     def _do_call_int(self, funcsym, ll_args):
         return self._do_call(funcsym, ll_args, rffi.LONG)
@@ -269,6 +325,11 @@
         single_res = self._do_call(funcsym, ll_args, rffi.FLOAT)
         return float(single_res)
 
+    @jit.dont_look_inside
+    def _do_call_longlong(self, funcsym, ll_args):
+        llres = self._do_call(funcsym, ll_args, rffi.LONGLONG)
+        return longlong2float(llres)
+
     @jit.oopspec('libffi_call_void(self, funcsym, ll_args)')
     def _do_call_void(self, funcsym, ll_args):
         return self._do_call(funcsym, ll_args, lltype.Void)

diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py
--- a/pypy/rlib/test/test_libffi.py
+++ b/pypy/rlib/test/test_libffi.py
@@ -2,9 +2,9 @@
 import sys
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED
-from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib.rarithmetic import r_singlefloat, r_longlong
 from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name
-from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types
+from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types, longlong2float, float2longlong
 
 class TestLibffiMisc(BaseFfiTest):
 
@@ -51,6 +51,12 @@
         del lib
         assert not ALLOCATED
 
+    def test_longlong_as_float(self):
+        maxint64 = r_longlong(9223372036854775807)
+        d = longlong2float(maxint64)
+        ll = float2longlong(d)
+        assert ll == maxint64
+        
 
 class TestLibffiCall(BaseFfiTest):
     """
@@ -113,6 +119,8 @@
         for arg in args:
             if isinstance(arg, r_singlefloat):
                 chain.arg_singlefloat(float(arg))
+            elif isinstance(arg, r_longlong):
+                chain.arg_longlong(longlong2float(arg))
             else:
                 chain.arg(arg)
         return func.call(chain, RESULT)
@@ -283,6 +291,29 @@
         expected = c_float(c_float(12.34).value + c_float(56.78).value).value
         assert res == expected
 
+    def test_longlong_args(self):
+        """
+            long long sum_xy_longlong(long long x, long long y)
+            {
+                return x+y;
+            }
+        """
+        maxint32 = 2147483647 # we cannot really go above maxint on 64 bits
+                              # (and we would not test anything, as there long
+                              # is the same as long long)
+        libfoo = self.get_libfoo()
+        func = (libfoo, 'sum_xy_longlong', [types.slonglong, types.slonglong], types.slonglong)
+        x = r_longlong(maxint32+1)
+        y = r_longlong(maxint32+2)
+        res = self.call(func, [x, y], rffi.LONGLONG, init_result=0)
+        if sys.maxint == maxint32:
+            # obscure, on 32bit it's really a long long, so it returns a
+            # DOUBLE because of the JIT hack
+            res = float2longlong(res)
+        expected = maxint32*2 + 3
+        assert res == expected
+
+
     def test_wrong_number_of_arguments(self):
         from pypy.rpython.llinterp import LLException
         libfoo = self.get_libfoo() 


More information about the Pypy-commit mailing list