aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c150
1 files changed, 56 insertions, 94 deletions
diff --git a/tccgen.c b/tccgen.c
index 38d2d44..6ea62e2 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3279,26 +3279,11 @@ static void struct_layout(CType *type, AttributeDef *ad)
prevbt = VT_STRUCT; /* make it never match */
prev_bit_size = 0;
for (f = type->ref->next; f; f = f->next) {
- int extra_bytes = 0;
int typealign, bit_size;
int size = type_size(&f->type, &typealign);
- if (f->type.t & VT_BITFIELD) {
- bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
- /* without ms-bitfields, allocate the
- * minimum number of bytes necessary,
- * adding single bytes as needed */
- if (0 && !tcc_state->ms_bitfields) {
- if (bit_pos == 0)
- /* minimum bytes for new bitfield */
- size = (bit_size + 7) / 8;
- else {
- /* enough spare bits already allocated? */
- int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
- if (add_size > 8) /* doesn't fit */
- extra_bytes = (add_size - 1) / 8;
- }
- }
- } else
+ if (f->type.t & VT_BITFIELD)
+ bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+ else
bit_size = -1;
if (bit_size == 0 && pcc) {
/* Zero-width bit-fields in PCC mode aren't affected
@@ -3312,35 +3297,39 @@ static void struct_layout(CType *type, AttributeDef *ad)
} else {
align = typealign;
}
- if (extra_bytes) c += extra_bytes;
- else if (bit_size < 0) {
+ if (type->ref->type.t != TOK_STRUCT) {
+ if (pcc && bit_size >= 0)
+ size = (bit_size + 7) >> 3;
+ /* Bit position is already zero from our caller. */
+ offset = 0;
+ if (size > c)
+ c = size;
+ } else if (bit_size < 0) {
+ int addbytes = pcc ? (bit_pos + 7) >> 3 : 0;
prevbt = VT_STRUCT;
prev_bit_size = 0;
- if (type->ref->type.t == TOK_STRUCT) {
- int addbytes = pcc ? (bit_pos + 7) >> 3 : 0;
- c = (c + addbytes + align - 1) & -align;
- offset = c;
- if (size > 0)
- c += size;
- } else {
- union_tail:
- offset = 0;
- if (size > c)
- c = size;
- }
- if (align > maxalign)
- maxalign = align;
+ c = (c + addbytes + align - 1) & -align;
+ offset = c;
+ if (size > 0)
+ c += size;
bit_pos = 0;
- } else if (type->ref->type.t != TOK_STRUCT) {
- if (pcc)
- size = (bit_size + 7) >> 3;
- f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
- | (0 << VT_STRUCT_SHIFT);
- goto union_tail;
} else {
/* A bit-field. Layout is more complicated. There are two
options TCC implements: PCC compatible and MS compatible
- (PCC compatible is what GCC uses for almost all targets). */
+ (PCC compatible is what GCC uses for almost all targets).
+ In PCC layout the overall size of the struct (in c) is
+ _excluding_ the current run of bit-fields (that is,
+ there's at least additional bit_pos bits after c). In
+ MS layout c does include the current run of bit-fields.
+
+ This matters for calculating the natural alignment buckets
+ in PCC mode. */
+
+ /* 'align' will be used to influence records alignment,
+ so it's the max of specified and type alignment, except
+ in certain cases that depend on the mode. */
+ if (align < typealign)
+ align = typealign;
if (pcc) {
/* In PCC layout a non-packed bit-field is placed adjacent
to the preceding bit-fields, except if it would overflow
@@ -3349,15 +3338,9 @@ static void struct_layout(CType *type, AttributeDef *ad)
placed adjacent. */
int ofs = (c * 8 + bit_pos) % (typealign * 8);
int ofs2 = ofs + bit_size + (typealign * 8) - 1;
- /*if ((typealign != 1 &&
- //bit_pos + bit_size > size * 8) ||
- (((c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign)
- != ((c + ((bit_pos + bit_size + 7) >> 3) + typealign - 1) & -typealign))) ||
- bit_size == 0 ||
- (bit_pos + bit_size > size * 8)
- ) {*/
if (bit_size == 0 ||
- (typealign != 1 && (ofs2 / (typealign * 8)) > (size/typealign))) {
+ (typealign != 1 &&
+ (ofs2 / (typealign * 8)) > (size/typealign))) {
c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign;
bit_pos = 0;
}
@@ -3366,33 +3349,28 @@ static void struct_layout(CType *type, AttributeDef *ad)
of the containing struct using the base types alignment,
except for packed fields (which here have correct
align/typealign). */
- if (!(f->v & SYM_FIRST_ANOM)) {
- if (align > maxalign)
- maxalign = align;
- if (typealign > maxalign)
- maxalign = typealign;
- }
+ if ((f->v & SYM_FIRST_ANOM))
+ align = 1;
} else {
bt = f->type.t & VT_BTYPE;
- if (
- ((
- bit_pos + bit_size > size * 8) ||
- (bit_size == 0 && prevbt == bt) ||
- (bit_size > 0 && bt != prevbt))) {
+ if ((bit_pos + bit_size > size * 8) ||
+ (bit_size > 0) == (bt != prevbt)) {
c = (c + typealign - 1) & -typealign;
offset = c;
bit_pos = 0;
/* In MS bitfield mode a bit-field run always uses
- at least as many bits as the underlying type. */
+ at least as many bits as the underlying type.
+ To start a new run it's also required that this
+ or the last bit-field had non-zero width. */
if (bit_size || prev_bit_size)
c += size;
}
- if (bit_size > 0 || prevbt == bt) {
- if (align > maxalign)
- maxalign = align;
- if (typealign > maxalign)
- maxalign = typealign;
- }
+ /* In MS layout the records alignment is normally
+ influenced by the field, except for a zero-width
+ field at the start of a run (but by further zero-width
+ fields it is again). */
+ if (bit_size == 0 && prevbt != bt)
+ align = 1;
prevbt = bt;
prev_bit_size = bit_size;
}
@@ -3404,6 +3382,8 @@ static void struct_layout(CType *type, AttributeDef *ad)
bit_pos -= size * 8;
}
}
+ if (align > maxalign)
+ maxalign = align;
#if 0
printf("set field %s offset=%d c=%d",
get_tok_str(f->v & ~SYM_FIELD, NULL), offset, c);
@@ -3461,10 +3441,9 @@ static void struct_layout(CType *type, AttributeDef *ad)
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
static void struct_decl(CType *type, AttributeDef *ad, int u)
{
- int extra_bytes;
int a, v, size, align, flexible, alignoverride;
long c;
- int bit_size, bit_pos, bsize, bt, prevbt;
+ int bit_size, bsize, bt;
Sym *s, *ss, **ps;
AttributeDef ad1;
CType type1, btype;
@@ -3553,8 +3532,6 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
skip('}');
} else {
ps = &s->next;
- prevbt = VT_INT;
- bit_pos = 0;
flexible = 0;
while (tok != '}') {
if (!parse_btype(&btype, &ad1)) {
@@ -3562,7 +3539,6 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
continue;
}
while (1) {
- extra_bytes = 0;
if (flexible)
tcc_error("flexible array member '%s' not at the end of struct",
get_tok_str(v, NULL));
@@ -3634,41 +3610,27 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
get_tok_str(v, NULL));
} else if (bit_size == bsize) {
/* no need for bit fields */
- bit_pos = 0;
+ ;
} else {
- /* if type change, union, or will overrun
- * allignment slot, start at a newly
- * alligned slot */
- if ((bit_pos + bit_size) > bsize ||
- bt != prevbt || a == TOK_UNION)
- bit_pos = 0;
- /* XXX: handle LSB first */
type1.t |= VT_BITFIELD |
- (bit_pos << VT_STRUCT_SHIFT) |
+ (0 << VT_STRUCT_SHIFT) |
(bit_size << (VT_STRUCT_SHIFT + 6));
- bit_pos += bit_size;
}
- prevbt = bt;
- } else {
- bit_pos = 0;
}
if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
/* Remember we've seen a real field to check
for placement of flexible array member. */
c = 1;
}
- if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
- /* See struct_layout for special casing
- anonymous member of struct type. */
+ /* If member is a struct or bit-field, enforce
+ placing into the struct (as anonymous). */
+ if (v == 0 &&
+ ((type1.t & VT_BTYPE) == VT_STRUCT ||
+ bit_size >= 0)) {
v = anon_sym++;
}
- if (v == 0 && bit_size >= 0) {
- /* Need to remember anon bit-fields as well.
- They influence layout. */
- v = anon_sym++;
- }
if (v) {
- ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
+ ss = sym_push(v | SYM_FIELD, &type1, alignoverride, 0);
*ps = ss;
ps = &ss->next;
}