[pypy-commit] pypy ffi-backend: "long double" support

arigo noreply at buildbot.pypy.org
Wed Aug 1 13:16:20 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r56518:a0252dc89f55
Date: 2012-08-01 13:16 +0200
http://bitbucket.org/pypy/pypy/changeset/a0252dc89f55/

Log:	"long double" support

diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -209,6 +209,10 @@
         misc.write_raw_float_data(self._cdata, source, self.ctype.size)
         keepalive_until_here(self)
 
+    def write_raw_longdouble_data(self, source):
+        misc.write_raw_longdouble_data(self._cdata, source)
+        keepalive_until_here(self)
+
     def convert_to_object(self):
         w_obj = self.ctype.convert_to_object(self._cdata)
         keepalive_until_here(self)
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -18,6 +18,7 @@
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUnsigned
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveCharOrUniChar
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveFloat
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveLongDouble
 from pypy.module._cffi_backend import ctypearray, cdataobj, cerrno
 
 
@@ -261,6 +262,9 @@
     elif size == 8: return clibffi.ffi_type_double
     return _missing_ffi_type(self, cifbuilder)
 
+def _primlongdouble_ffi_type(self, cifbuilder):
+    return clibffi.ffi_type_longdouble
+
 def _ptr_ffi_type(self, cifbuilder):
     return clibffi.ffi_type_pointer
 
@@ -273,6 +277,7 @@
 W_CTypePrimitiveCharOrUniChar._get_ffi_type = _primunsigned_ffi_type
 W_CTypePrimitiveUnsigned._get_ffi_type      = _primunsigned_ffi_type
 W_CTypePrimitiveFloat._get_ffi_type         = _primfloat_ffi_type
+W_CTypePrimitiveLongDouble._get_ffi_type    = _primlongdouble_ffi_type
 W_CTypePtrBase._get_ffi_type                = _ptr_ffi_type
 W_CTypeVoid._get_ffi_type                   = _void_ffi_type
 # ----------
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -228,7 +228,11 @@
         else:
             value = space.float_w(w_ob)
         w_cdata = cdataobj.W_CDataCasted(space, self.size, self)
-        w_cdata.write_raw_float_data(value)
+        if not isinstance(self, W_CTypePrimitiveLongDouble):
+            w_cdata.write_raw_float_data(value)
+        else:
+            lvalue = rffi.cast(rffi.LONGDOUBLE, value)
+            w_cdata.write_raw_longdouble_data(lvalue)
         return w_cdata
 
     def int(self, cdata):
@@ -246,3 +250,45 @@
         space = self.space
         value = space.float_w(space.float(w_ob))
         misc.write_raw_float_data(cdata, value, self.size)
+
+
+class W_CTypePrimitiveLongDouble(W_CTypePrimitiveFloat):
+    _attrs_ = []
+
+    def extra_repr(self, cdata):
+        lvalue = misc.read_raw_longdouble_data(cdata)
+        return misc.longdouble2str(lvalue)
+
+    def cast(self, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePrimitiveLongDouble)):
+            w_cdata = self.convert_to_object(ob._cdata)
+            keepalive_until_here(ob)
+            return w_cdata
+        else:
+            return W_CTypePrimitiveFloat.cast(self, w_ob)
+
+    def float(self, cdata):
+        lvalue = misc.read_raw_longdouble_data(cdata)
+        value = rffi.cast(lltype.Float, lvalue)
+        return self.space.wrap(value)
+
+    def convert_to_object(self, cdata):
+        lvalue = misc.read_raw_longdouble_data(cdata)
+        w_cdata = cdataobj.W_CDataCasted(self.space, self.size, self)
+        w_cdata.write_raw_longdouble_data(lvalue)
+        return w_cdata
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePrimitiveLongDouble)):
+            lvalue = misc.read_raw_longdouble_data(ob._cdata)
+            keepalive_until_here(ob)
+        else:
+            value = space.float_w(space.float(w_ob))
+            lvalue = rffi.cast(rffi.LONGDOUBLE, value)
+        misc.write_raw_longdouble_data(cdata, lvalue)
diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rlib.rarithmetic import r_ulonglong
@@ -42,6 +43,9 @@
             return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0])
     raise NotImplementedError("bad float size")
 
+def read_raw_longdouble_data(target):
+    return rffi.cast(rffi.LONGDOUBLEP, target)[0]
+
 def write_raw_integer_data(target, source, size):
     for TP, TPP in _prim_unsigned_types:
         if size == rffi.sizeof(TP):
@@ -56,6 +60,22 @@
             return
     raise NotImplementedError("bad float size")
 
+def write_raw_longdouble_data(target, source):
+    rffi.cast(rffi.LONGDOUBLEP, target)[0] = source
+
+# ____________________________________________________________
+
+sprintf_longdouble = rffi.llexternal(
+    "sprintf", [rffi.CCHARP, rffi.CCHARP, rffi.LONGDOUBLE], lltype.Void,
+    _nowrapper=True, sandboxsafe=True)
+
+FORMAT_LONGDOUBLE = rffi.str2charp("%LE")
+
+def longdouble2str(lvalue):
+    with lltype.scoped_alloc(rffi.CCHARP.TO, 128) as p:    # big enough
+        sprintf_longdouble(p, FORMAT_LONGDOUBLE, lvalue)
+        return rffi.charp2str(p)
+
 # ____________________________________________________________
 
 
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -37,6 +37,7 @@
 eptype("unsigned long long", rffi.LONGLONG, ctypeprim.W_CTypePrimitiveUnsigned)
 eptype("float",  rffi.FLOAT,  ctypeprim.W_CTypePrimitiveFloat)
 eptype("double", rffi.DOUBLE, ctypeprim.W_CTypePrimitiveFloat)
+eptype("long double", rffi.LONGDOUBLE, ctypeprim.W_CTypePrimitiveLongDouble)
 
 @unwrap_spec(name=str)
 def new_primitive_type(space, name):
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1733,3 +1733,34 @@
     assert x[0] == 12.5
     x = cast(BFloat, cast(BDouble, 12.5))
     assert float(x) == 12.5
+
+def test_longdouble():
+    BLongDouble = new_primitive_type("long double")
+    BLongDoublePtr = new_pointer_type(BLongDouble)
+    BLongDoubleArray = new_array_type(BLongDoublePtr, None)
+    a = newp(BLongDoubleArray, 1)
+    x = a[0]
+    assert repr(x).startswith("<cdata 'long double' 0.0")
+    assert float(x) == 0.0
+    assert int(x) == 0
+    #
+    b = newp(BLongDoubleArray, [1.23])
+    x = b[0]
+    assert repr(x).startswith("<cdata 'long double' 1.23")
+    assert float(x) == 1.23
+    assert int(x) == 1
+    #
+    BFunc19 = new_function_type((BLongDouble,), BLongDouble)
+    f = cast(BFunc19, _testfunc(19))
+    start = 8
+    for i in range(107):
+        start = f(start)
+    if sizeof(BLongDouble) > sizeof(new_primitive_type("double")):
+        if 'PY_DOT_PY' in globals(): py.test.skip('py.py: long double->double')
+        assert repr(start).startswith("<cdata 'long double' 6.15")
+        assert repr(start).endswith("E+902>")
+        #
+        c = newp(BLongDoubleArray, [start])
+        x = c[0]
+        assert repr(x).endswith("E+902>")
+        assert float(x) == float("inf")
diff --git a/pypy/module/_cffi_backend/test/_test_lib.c b/pypy/module/_cffi_backend/test/_test_lib.c
--- a/pypy/module/_cffi_backend/test/_test_lib.c
+++ b/pypy/module/_cffi_backend/test/_test_lib.c
@@ -127,6 +127,14 @@
     return ptr->a1 + (int)ptr->a2;
 }
 
+static long double _testfunc19(long double x)
+{
+    int i;
+    for (i=0; i<28; i++)
+        x += x;
+    return x;
+}
+
 void *gettestfunc(int num)
 {
     void *f;
@@ -150,6 +158,7 @@
     case 16: f = &_testfunc16; break;
     case 17: f = &_testfunc17; break;
     case 18: f = &_testfunc18; break;
+    case 19: f = &_testfunc19; break;
     default:
         return NULL;
     }
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -1231,6 +1231,8 @@
         cvalue = ord(cvalue)     # character -> integer
     elif hasattr(RESTYPE, "_type") and issubclass(RESTYPE._type, base_int):
         cvalue = int(cvalue)
+    elif isinstance(cvalue, r_longfloat):
+        cvalue = cvalue.value
 
     if not isinstance(cvalue, (int, long, float)):
         raise NotImplementedError("casting %r to %r" % (TYPE1, RESTYPE))
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -652,6 +652,9 @@
 # float *
 FLOATP = lltype.Ptr(lltype.Array(FLOAT, hints={'nolength': True}))
 
+# long double *
+LONGDOUBLEP = lltype.Ptr(lltype.Array(LONGDOUBLE, hints={'nolength': True}))
+
 # Signed, Signed *
 SIGNED = lltype.Signed
 SIGNEDP = lltype.Ptr(lltype.Array(SIGNED, hints={'nolength': True}))
@@ -913,6 +916,11 @@
         return 8
     if tp is lltype.SingleFloat:
         return 4
+    if tp is lltype.LongFloat:
+        if globals()['r_void*'].BITS == 32:
+            return 12
+        else:
+            return 16
     assert isinstance(tp, lltype.Number)
     if tp is lltype.Signed:
         return LONG_BIT/8


More information about the pypy-commit mailing list