Author: Armin Rigo <[email protected]>
Branch:
Changeset: r64701:7b2e8cc68c61
Date: 2013-06-01 13:58 +0200
http://bitbucket.org/pypy/pypy/changeset/7b2e8cc68c61/
Log: Update to cffi/263caa88878e
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
@@ -1,3 +1,4 @@
+import sys
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import unwrap_spec
@@ -113,6 +114,14 @@
# ____________________________________________________________
+SF_MSVC_BITFIELDS = 1
+
+if sys.platform == 'win32':
+ DEFAULT_SFLAGS = SF_MSVC_BITFIELDS
+else:
+ DEFAULT_SFLAGS = 0
+
+
@unwrap_spec(name=str)
def new_struct_type(space, name):
return ctypestruct.W_CTypeStruct(space, name)
@@ -121,9 +130,11 @@
def new_union_type(space, name):
return ctypestruct.W_CTypeUnion(space, name)
-@unwrap_spec(w_ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int)
+@unwrap_spec(w_ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int,
+ sflags=int)
def complete_struct_or_union(space, w_ctype, w_fields, w_ignored=None,
- totalsize=-1, totalalignment=-1):
+ totalsize=-1, totalalignment=-1,
+ sflags=DEFAULT_SFLAGS):
if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion)
or w_ctype.size >= 0):
raise OperationError(space.w_TypeError,
@@ -134,6 +145,8 @@
alignment = 1
boffset = 0 # this number is in *bits*, not bytes!
boffsetmax = 0 # the maximum value of boffset, in bits too
+ prev_bitfield_size = 0
+ prev_bitfield_free = 0
fields_w = space.listview(w_fields)
fields_list = []
fields_dict = {}
@@ -166,7 +179,15 @@
# update the total alignment requirement, but skip it if the
# field is an anonymous bitfield
falign = ftype.alignof()
- if alignment < falign and (fbitsize < 0 or fname != ''):
+ do_align = True
+ if fbitsize >= 0:
+ if (sflags & SF_MSVC_BITFIELDS) == 0:
+ # GCC: anonymous bitfields (of any size) don't cause alignment
+ do_align = (fname != '')
+ else:
+ # MSVC: zero-sized bitfields don't cause alignment
+ do_align = (fbitsize > 0)
+ if alignment < falign and do_align:
alignment = falign
#
if fbitsize < 0:
@@ -208,6 +229,7 @@
fields_dict[fname] = fld
boffset += ftype.size * 8
+ prev_bitfield_size = 0
else:
# this is the case of a bitfield
@@ -243,31 +265,67 @@
raise operationerrfmt(space.w_TypeError,
"field '%s.%s' is declared with :0",
w_ctype.name, fname)
- if boffset > field_offset_bytes * 8:
- field_offset_bytes += falign
- assert boffset < field_offset_bytes * 8
- boffset = field_offset_bytes * 8
+ if (sflags & SF_MSVC_BITFIELDS) == 0:
+ # GCC's notion of "ftype :0;"
+ # pad boffset to a value aligned for "ftype"
+ if boffset > field_offset_bytes * 8:
+ field_offset_bytes += falign
+ assert boffset < field_offset_bytes * 8
+ boffset = field_offset_bytes * 8
+ else:
+ # MSVC's notion of "ftype :0;
+ # Mostly ignored. It seems they only serve as
+ # separator between other bitfields, to force them
+ # into separate words.
+ pass
+ prev_bitfield_size = 0
+
else:
- # Can the field start at the offset given by 'boffset'? It
- # can if it would entirely fit into an aligned ftype field.
- bits_already_occupied = boffset - (field_offset_bytes * 8)
+ if (sflags & SF_MSVC_BITFIELDS) == 0:
+ # GCC's algorithm
- if bits_already_occupied + fbitsize > 8 * ftype.size:
- # it would not fit, we need to start at the next
- # allowed position
- field_offset_bytes += falign
- assert boffset < field_offset_bytes * 8
- boffset = field_offset_bytes * 8
- bitshift = 0
+ # Can the field start at the offset given by 'boffset'? It
+ # can if it would entirely fit into an aligned ftype field.
+ bits_already_occupied = boffset - (field_offset_bytes * 8)
+
+ if bits_already_occupied + fbitsize > 8 * ftype.size:
+ # it would not fit, we need to start at the next
+ # allowed position
+ field_offset_bytes += falign
+ assert boffset < field_offset_bytes * 8
+ boffset = field_offset_bytes * 8
+ bitshift = 0
+ else:
+ bitshift = bits_already_occupied
+ assert bitshift >= 0
+ boffset += fbitsize
+
else:
- bitshift = bits_already_occupied
+ # MSVC's algorithm
+
+ # A bitfield is considered as taking the full width
+ # of their declared type. It can share some bits
+ # with the previous field only if it was also a
+ # bitfield and used a type of the same size.
+ if (prev_bitfield_size == ftype.size and
+ prev_bitfield_free >= fbitsize):
+ # yes: reuse
+ bitshift = 8 * prev_bitfield_size - prev_bitfield_free
+ else:
+ # no: start a new full field
+ boffset = (boffset + falign*8-1) & ~(falign*8-1)
+ boffset += ftype.size * 8
+ bitshift = 0
+ prev_bitfield_size = ftype.size
+ prev_bitfield_free = 8 * prev_bitfield_size
+ #
+ prev_bitfield_free -= fbitsize
+ field_offset_bytes = boffset / 8 - ftype.size
fld = ctypestruct.W_CField(ftype, field_offset_bytes,
bitshift, fbitsize)
fields_list.append(fld)
fields_dict[fname] = fld
-
- boffset += fbitsize
if boffset > boffsetmax:
boffsetmax = boffset
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
@@ -2757,36 +2757,57 @@
assert wr() is None
py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
-def test_bitfield_as_gcc():
+def _test_bitfield_details(flag):
BChar = new_primitive_type("char")
BShort = new_primitive_type("short")
BInt = new_primitive_type("int")
+ BUInt = new_primitive_type("unsigned int")
BStruct = new_struct_type("foo1")
complete_struct_or_union(BStruct, [('a', BChar, -1),
- ('b', BInt, 9),
- ('c', BChar, -1)])
- assert typeoffsetof(BStruct, 'c') == (BChar, 3)
- assert sizeof(BStruct) == 4
+ ('b1', BInt, 9),
+ ('b2', BUInt, 7),
+ ('c', BChar, -1)], -1, -1, -1, flag)
+ if flag == 0: # gcc
+ assert typeoffsetof(BStruct, 'c') == (BChar, 3)
+ assert sizeof(BStruct) == 4
+ else: # msvc
+ assert typeoffsetof(BStruct, 'c') == (BChar, 8)
+ assert sizeof(BStruct) == 12
assert alignof(BStruct) == 4
#
BStruct = new_struct_type("foo2")
complete_struct_or_union(BStruct, [('a', BChar, -1),
('', BShort, 9),
- ('c', BChar, -1)])
+ ('c', BChar, -1)], -1, -1, -1, flag)
assert typeoffsetof(BStruct, 'c') == (BChar, 4)
- assert sizeof(BStruct) == 5
- assert alignof(BStruct) == 1
+ if flag == 0: # gcc
+ assert sizeof(BStruct) == 5
+ assert alignof(BStruct) == 1
+ else: # msvc
+ assert sizeof(BStruct) == 6
+ assert alignof(BStruct) == 2
#
BStruct = new_struct_type("foo2")
complete_struct_or_union(BStruct, [('a', BChar, -1),
('', BInt, 0),
('', BInt, 0),
- ('c', BChar, -1)])
- assert typeoffsetof(BStruct, 'c') == (BChar, 4)
- assert sizeof(BStruct) == 5
+ ('c', BChar, -1)], -1, -1, -1, flag)
+ if flag == 0: # gcc
+ assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+ assert sizeof(BStruct) == 5
+ else: # msvc
+ assert typeoffsetof(BStruct, 'c') == (BChar, 1)
+ assert sizeof(BStruct) == 2
assert alignof(BStruct) == 1
+def test_bitfield_as_gcc():
+ _test_bitfield_details(flag=0)
+
+def test_bitfield_as_msvc():
+ _test_bitfield_details(flag=1)
+
+
def test_version():
# this test is here mostly for PyPy
assert __version__ == "0.7"
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit