According to Christian, we have at least one major compiler (VC++) whose behavior matches tcc's current behavior and another (GCC) whose behavior differs. While it would be nice to just pick one implementation and go with it, I am personally much more concerned with binary compatibility with one's major compiler of choice. In that case, the logic for how to handle this would depend upon a bit being set in the TCCState struct.
Here is a patch that makes the bit field size logic match gcc. I can confirm that the original alignment bug is gone (though other alignment bugs may yet be around). I am not 100% sure if this is correct, but I throw it out there for folks to mull over. Note that indentation may not be consistent; the indentation pattern in the existing code was weird. Finally, it might be more efficient to use (bit_size & 7) rather than (bit_size % 8), or optimizing compilers might do that for us anyway; I leave that to the gurus.
If this looks good, I propose adding a bit to TCCState to pick this vs the old behavior, then throwing in a couple of if statements to the below patch to switch based on said bit.
David
diff --git a/tccgen.c b/tccgen.c
index ad70de6..97b37a4 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3109,13 +3109,27 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
/* zero size: means to pad */
bit_pos = 0;
} else {
+ size = bit_size / 8;
+ if (bit_size % 8) size++; /* round up */
+ lbit_pos = bit_pos;
/* we do not have enough room ?
did the type change?
is it a union? */
if ((bit_pos + bit_size) > bsize ||
- bt != prevbt || a == TOK_UNION)
- bit_pos = 0;
- lbit_pos = bit_pos;
+ bt != prevbt || a == TOK_UNION) {
+ lbit_pos = bit_pos = 0;
+ }
+ /* only allocate large-type int bitfields
+ * one byte at a time */
+ else {
+ int overage;
+ overage = bit_pos % 8 + bit_size;
+ if (overage > 8) {
+ lbit_pos = 0;
+ size = overage / 8;
+ if (overage % 8 == 0) size--;
+ }
+ }
/* XXX: handle LSB first */
type1.t |= VT_BITFIELD |
(bit_pos << VT_STRUCT_SHIFT) |