[pypy-commit] cffi default: MSVC-style bitfields, first attempt
arigo
noreply at buildbot.pypy.org
Sat Jun 1 13:07:50 CEST 2013
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1264:4e06afeabe1c
Date: 2013-06-01 13:04 +0200
http://bitbucket.org/cffi/cffi/changeset/4e06afeabe1c/
Log: MSVC-style bitfields, first attempt
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3424,6 +3424,8 @@
return cf; /* borrowed reference */
}
+#define SF_MSVC_BITFIELDS 1
+
static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct;
@@ -3433,11 +3435,17 @@
Py_ssize_t totalsize = -1;
int totalalignment = -1;
CFieldObject **previous;
-
- if (!PyArg_ParseTuple(args, "O!O!|Oni:complete_struct_or_union",
+ int prev_bitfield_size, prev_bitfield_free;
+#ifdef MS_WIN32
+ int sflags = SF_MSVC_BITFIELDS;
+#else
+ int sflags = 0;
+#endif
+
+ if (!PyArg_ParseTuple(args, "O!O!|Onii:complete_struct_or_union",
&CTypeDescr_Type, &ct,
&PyList_Type, &fields,
- &ignored, &totalsize, &totalalignment))
+ &ignored, &totalsize, &totalalignment, &sflags))
return NULL;
if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) ==
@@ -3457,6 +3465,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;
nb_fields = PyList_GET_SIZE(fields);
interned_fields = PyDict_New();
if (interned_fields == NULL)
@@ -3543,6 +3553,7 @@
previous = &(*previous)->cf_next;
}
boffset += ftype->ct_size * 8;
+ prev_bitfield_size = 0;
}
else {
/* this is the case of a bitfield */
@@ -3592,29 +3603,59 @@
assert(boffset < field_offset_bytes * 8);
}
boffset = field_offset_bytes * 8; /* the only effect */
+ 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 (bits_already_occupied + fbitsize > 8 * ftype->ct_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;
+ if (!(sflags & SF_MSVC_BITFIELDS)) {
+ /* GCC's algorithm */
+
+ /* 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->ct_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;
+ else {
+ /* 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->ct_size &&
+ 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); /*align*/
+ boffset += ftype->ct_size * 8;
+ bitshift = 0;
+ prev_bitfield_size = ftype->ct_size;
+ prev_bitfield_free = 8 * prev_bitfield_size;
+ }
+ prev_bitfield_free -= fbitsize;
+ field_offset_bytes = boffset / 8 - ftype->ct_size;
+ }
*previous = _add_field(interned_fields, fname, ftype,
field_offset_bytes, bitshift, fbitsize);
if (*previous == NULL)
goto error;
previous = &(*previous)->cf_next;
- boffset += fbitsize;
}
}
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2768,22 +2768,28 @@
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
@@ -2792,12 +2798,19 @@
complete_struct_or_union(BStruct, [('a', BChar, -1),
('', BInt, 0),
('', BInt, 0),
- ('c', BChar, -1)])
+ ('c', BChar, -1)], -1, -1, -1, flag)
assert typeoffsetof(BStruct, 'c') == (BChar, 4)
assert sizeof(BStruct) == 5
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"
More information about the pypy-commit
mailing list