[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