[pypy-svn] pypy fast-forward: Implement bitfield members access in _rawffi.Structure.

amauryfa commits-noreply at bitbucket.org
Thu Dec 30 01:30:22 CET 2010


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: fast-forward
Changeset: r40272:f6efeec20670
Date: 2010-12-30 00:14 +0100
http://bitbucket.org/pypy/pypy/changeset/f6efeec20670/

Log:	Implement bitfield members access in _rawffi.Structure. Let's see
	how ctypes can use it.

diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py
--- a/pypy/module/_rawffi/test/test__rawffi.py
+++ b/pypy/module/_rawffi/test/test__rawffi.py
@@ -461,6 +461,20 @@
         free_double_struct = lib.ptr("free_double_struct", ['P'], None)
         free_double_struct(res)
 
+    def test_structure_bitfields(self):
+        import _rawffi
+        X = _rawffi.Structure([('A', 'I', 1),
+                               ('B', 'I', 2),
+                               ('C', 'i', 2)])
+        x = X()
+        x.A = 0xf
+        x.B = 0xf
+        x.C = 0xf
+        assert x.A == 1
+        assert x.B == 3
+        assert x.C == -2
+        x.free()
+
     def test_array(self):
         import _rawffi
         lib = _rawffi.CDLL(self.lib_name)

diff --git a/pypy/module/_rawffi/test/test_struct.py b/pypy/module/_rawffi/test/test_struct.py
--- a/pypy/module/_rawffi/test/test_struct.py
+++ b/pypy/module/_rawffi/test/test_struct.py
@@ -53,6 +53,3 @@
 
     assert pos      == [getattr(X, name).offset for (name, _, _) in fields]
     assert bitsizes == [getattr(X, name).size   for (name, _, _) in fields]
-
-    # TODO: test a normal struct containing a big array > 0x10000.
-    # Make sure we don't take this for a bitsize...

diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py
--- a/pypy/module/_rawffi/structure.py
+++ b/pypy/module/_rawffi/structure.py
@@ -14,7 +14,8 @@
 from pypy.module._rawffi.interp_rawffi import W_DataShape, W_DataInstance
 from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value
 from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
-from pypy.module._rawffi.interp_rawffi import size_alignment
+from pypy.module._rawffi.interp_rawffi import size_alignment, LL_TYPEMAP
+from pypy.module._rawffi.interp_rawffi import unroll_letters_for_numbers
 from pypy.rlib import clibffi
 from pypy.rlib.rarithmetic import intmask, r_uint
 
@@ -48,7 +49,9 @@
     pos = []
     bitsizes = []
     bitoffset = 0
+    has_bitfield = False
     last_size = 0
+
     for fieldname, fieldtype, bitsize in fields:
         # fieldtype is a W_Array
         fieldsize = fieldtype.size
@@ -77,11 +80,13 @@
         else:
               # start new bitfield
               field_type = NEW_BITFIELD
+              has_bitfield = True
               bitoffset = 0
               last_size = fieldsize * 8
 
         if is_union:
             pos.append(0)
+            bitsizes.append(fieldsize)
             size = max(size, fieldsize)
         else:
             if field_type == NO_BITFIELD:
@@ -108,6 +113,9 @@
                 bitoffset += bitsize
                 # offset is already updated for the NEXT field
                 pos.append(size - fieldsize)
+
+    if not has_bitfield:
+        bitsizes = None
     size = round_up(size, alignment)
     return size, alignment, pos, bitsizes
 
@@ -122,16 +130,17 @@
                     raise operationerrfmt(space.w_ValueError,
                         "duplicate field name %s", name)
                 name_to_index[name] = i
-            size, alignment, pos, bitfields = size_alignment_pos(fields, is_union)
+            size, alignment, pos, bitsizes = size_alignment_pos(
+                fields, is_union)
         else: # opaque case
             fields = []
             pos = []
-            bitfields = []
+            bitsizes = None
         self.fields = fields
         self.size = size
         self.alignment = alignment                
         self.ll_positions = pos
-        self.ll_bitfields = bitfields
+        self.ll_bitsizes = bitsizes
         self.name_to_index = name_to_index
 
     def allocate(self, space, length, autofree=False):
@@ -222,17 +231,61 @@
 )
 W_Structure.typedef.acceptable_as_base_class = False
 
+def LOW_BIT(x):
+    return x & 0xFFFF
+def NUM_BITS(x):
+    return x >> 16
+def BIT_MASK(x):
+    return (1 << x) - 1
+
 def push_field(self, num, value):
     ptr = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[num])
     TP = lltype.typeOf(value)
     T = lltype.Ptr(rffi.CArray(TP))
+
+    # Handle bitfields
+    for c in unroll_letters_for_numbers:
+        if LL_TYPEMAP[c] is TP and self.shape.ll_bitsizes:
+            # Modify the current value with the bitfield changed
+            bitsize = self.shape.ll_bitsizes[num]
+            numbits = NUM_BITS(bitsize)
+            lowbit = LOW_BIT(bitsize)
+            if numbits:
+                current = rffi.cast(T, ptr)[0]
+                bitmask = BIT_MASK(numbits)
+                current &= ~ (bitmask << lowbit)
+                current |= (value & bitmask) << lowbit
+                value = current
+            break
+
     rffi.cast(T, ptr)[0] = value
 push_field._annspecialcase_ = 'specialize:argtype(2)'
-    
+
 def cast_pos(self, i, ll_t):
     pos = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i])
     TP = lltype.Ptr(rffi.CArray(ll_t))
-    return rffi.cast(TP, pos)[0]
+    value = rffi.cast(TP, pos)[0]
+
+    # Handle bitfields
+    for c in unroll_letters_for_numbers:
+        if LL_TYPEMAP[c] is ll_t and self.shape.ll_bitsizes:
+            bitsize = self.shape.ll_bitsizes[i]
+            numbits = NUM_BITS(bitsize)
+            lowbit = LOW_BIT(bitsize)
+            if numbits:
+                if ll_t._type.SIGN:
+                    value >>= lowbit
+                    sign = (value >> (numbits - 1)) & 1
+                    value &= BIT_MASK(numbits - 1)
+                    if sign:
+                        value = ~value
+                else:
+                    # unsigned is easier
+                    value >>= lowbit
+                    value &= BIT_MASK(numbits)
+            break
+
+    return value
 cast_pos._annspecialcase_ = 'specialize:arg(2)'
 
 class W_StructureInstance(W_DataInstance):


More information about the Pypy-commit mailing list