[pypy-commit] pypy ffi-backend: Bitfields.

arigo noreply at buildbot.pypy.org
Fri Jul 6 15:25:44 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55936:a1c66a24e626
Date: 2012-07-06 15:25 +0200
http://bitbucket.org/pypy/pypy/changeset/a1c66a24e626/

Log:	Bitfields.

diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -7,9 +7,10 @@
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.typedef import TypeDef, interp_attrproperty
 from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import r_ulonglong, r_longlong, intmask
 
 from pypy.module._cffi_backend.ctypeobj import W_CType
-from pypy.module._cffi_backend import cdataobj
+from pypy.module._cffi_backend import cdataobj, ctypeprim, misc
 
 
 class W_CTypeStructOrUnion(W_CType):
@@ -153,17 +154,70 @@
     def read(self, cdata):
         cdata = rffi.ptradd(cdata, self.offset)
         if self.is_bitfield():
-            xxx
+            return self.convert_bitfield_to_object(cdata)
         else:
             return self.ctype.convert_to_object(cdata)
 
     def write(self, cdata, w_ob):
         cdata = rffi.ptradd(cdata, self.offset)
         if self.is_bitfield():
-            xxx
+            self.convert_bitfield_from_object(cdata, w_ob)
         else:
             self.ctype.convert_from_object(cdata, w_ob)
 
+    def convert_bitfield_to_object(self, cdata):
+        ctype = self.ctype
+        space = ctype.space
+        #
+        if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+            value = r_ulonglong(misc.read_raw_signed_data(cdata, ctype.size))
+            valuemask = (r_ulonglong(1) << self.bitsize) - 1
+            shiftforsign = r_ulonglong(1) << (self.bitsize - 1)
+            value = ((value >> self.bitshift) + shiftforsign) & valuemask
+            result = r_longlong(value) - r_longlong(shiftforsign)
+            if ctype.value_fits_long:
+                return space.wrap(intmask(result))
+            else:
+                return space.wrap(result)
+        #
+        if isinstance(ctype, ctypeprim.W_CTypePrimitiveUnsigned):
+            value_fits_long = ctype.value_fits_long
+        elif isinstance(ctype, ctypeprim.W_CTypePrimitiveChar):
+            value_fits_long = True
+        else:
+            raise NotImplementedError
+        #
+        value = misc.read_raw_unsigned_data(cdata, ctype.size)
+        valuemask = (r_ulonglong(1) << self.bitsize) - 1
+        value = (value >> self.bitshift) & valuemask
+        if value_fits_long:
+            return space.wrap(intmask(value))
+        else:
+            return space.wrap(value)
+
+    def convert_bitfield_from_object(self, cdata, w_ob):
+        ctype = self.ctype
+        space = ctype.space
+        #
+        value = misc.as_long_long(space, w_ob)
+        if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+            fmin = -(r_longlong(1) << (self.bitsize-1))
+            fmax = (r_longlong(1) << (self.bitsize-1)) - 1
+            if fmax == 0:
+                fmax = 1      # special case to let "int x:1" receive "1"
+        else:
+            fmin = r_longlong(0)
+            fmax = r_longlong((r_ulonglong(1) << self.bitsize) - 1)
+        if value < fmin or value > fmax:
+            raise operationerrfmt(space.w_OverflowError,
+                                  "value %d outside the range allowed by the "
+                                  "bit field width: %d <= x <= %d",
+                                  value, fmin, fmax)
+        rawmask = ((r_ulonglong(1) << self.bitsize) - 1) << self.bitshift
+        rawvalue = r_ulonglong(value) << self.bitshift
+        rawfielddata = misc.read_raw_unsigned_data(cdata, ctype.size)
+        rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask)
+        misc.write_raw_integer_data(cdata, rawfielddata, ctype.size)
 
 
 W_CField.typedef = TypeDef(
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
@@ -109,7 +109,6 @@
     fields_list = []
     fields_dict = {}
     prev_bit_position = 0
-    prev_field = None
     custom_field_pos = False
 
     for w_field in fields_w:
@@ -146,13 +145,34 @@
             custom_field_pos |= (offset != foffset)
             offset = foffset
         #
-        if fbitsize < 0 or (fbitsize == 8 * ftype.size and
-                            not isinstance(ftype, W_CTypePrimitiveChar)):
+        if fbitsize < 0 or (fbitsize == 8 * ftype.size and not
+                            isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)):
             fbitsize = -1
             bitshift = -1
             prev_bit_position = 0
         else:
-            xxx
+            if (not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or
+                     isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or
+                     isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)) or
+                fbitsize == 0 or
+                fbitsize > 8 * ftype.size):
+                raise operationerrfmt(space.w_TypeError,
+                                      "invalid bit field '%s'", fname)
+            if prev_bit_position > 0:
+                prev_field = fields_list[-1]
+                assert prev_field.bitshift >= 0
+                if prev_field.ctype.size != ftype.size:
+                    raise OperationError(space.w_NotImplementedError,
+                        space.wrap("consecutive bit fields should be "
+                                   "declared with a same-sized type"))
+                if prev_bit_position + fbitsize > 8 * ftype.size:
+                    prev_bit_position = 0
+                else:
+                    # we can share the same field as 'prev_field'
+                    offset = prev_field.offset
+            bitshift = prev_bit_position
+            if not is_union:
+                prev_bit_position += fbitsize
         #
         fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize)
         fields_list.append(fld)


More information about the pypy-commit mailing list