refactor bitfields
Use 2 level strategy to access packed bitfields cleanly:
1) Allow to override the original declaration type with
an auxilary "access type". This solves cases such as
struct {
...
unsigned f1:1;
};
by using VT_BYTE to access f1.
2) Allow byte-wise split accesses using two new functions
load/store_packed_bf. This solves any cases, also ones
such as
struct __attribute((packed)) _s {
unsigned x : 12;
unsigned char y : 7;
unsigned z : 28;
unsigned a: 3;
unsigned b: 3;
unsigned c: 3;
};
where for field 'z':
- VT_INT access from offset 2 would be unaligned
- VT_LLONG from offset 0 would go past the total
struct size (7)
and for field 'a' because it is in two bytes and
aligned access with VT_SHORT/INT is not possible.
Also, static bitfield initializers are stored byte-wise always.
Also, cleanup the struct_layout function a bit.
This commit is contained in:
parent
f87afa72e0
commit
a9e502cc3b
3 changed files with 385 additions and 194 deletions
1
tcc.h
1
tcc.h
|
|
@ -450,6 +450,7 @@ typedef struct Sym {
|
||||||
int sym_scope; /* scope level for locals */
|
int sym_scope; /* scope level for locals */
|
||||||
int jnext; /* next jump label */
|
int jnext; /* next jump label */
|
||||||
struct FuncAttr f; /* function attributes */
|
struct FuncAttr f; /* function attributes */
|
||||||
|
int auxtype; /* bitfield access type */
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
long long enum_val; /* enum constant if IS_ENUM_VAL */
|
long long enum_val; /* enum constant if IS_ENUM_VAL */
|
||||||
|
|
|
||||||
490
tccgen.c
490
tccgen.c
|
|
@ -93,6 +93,7 @@ ST_FUNC void vpush(CType *type);
|
||||||
ST_FUNC int gvtst(int inv, int t);
|
ST_FUNC int gvtst(int inv, int t);
|
||||||
static void gen_inline_functions(TCCState *s);
|
static void gen_inline_functions(TCCState *s);
|
||||||
static void skip_or_save_block(TokenString **str);
|
static void skip_or_save_block(TokenString **str);
|
||||||
|
static void gv_dup(void);
|
||||||
|
|
||||||
ST_INLN int is_float(int t)
|
ST_INLN int is_float(int t)
|
||||||
{
|
{
|
||||||
|
|
@ -1065,31 +1066,134 @@ static void gbound(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void incr_bf_adr(int o)
|
||||||
|
{
|
||||||
|
vtop->type = char_pointer_type;
|
||||||
|
gaddrof();
|
||||||
|
vpushi(o);
|
||||||
|
gen_op('+');
|
||||||
|
vtop->type.t = (vtop->type.t & ~(VT_BTYPE|VT_DEFSIGN))
|
||||||
|
| (VT_BYTE|VT_UNSIGNED);
|
||||||
|
vtop->r = (vtop->r & ~VT_LVAL_TYPE)
|
||||||
|
| (VT_LVAL_BYTE|VT_LVAL_UNSIGNED|VT_LVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* single-byte load mode for packed or otherwise unaligned bitfields */
|
||||||
|
static void load_packed_bf(CType *type, int bit_pos, int bit_size)
|
||||||
|
{
|
||||||
|
int n, o, bits;
|
||||||
|
save_reg_upstack(vtop->r, 1);
|
||||||
|
vpushi(0); // B X
|
||||||
|
vtop->type.t |= type->t;
|
||||||
|
bits = 0, o = bit_pos >> 3, bit_pos &= 7;
|
||||||
|
do {
|
||||||
|
vswap(); // X B
|
||||||
|
incr_bf_adr(o);
|
||||||
|
vdup(); // X B B
|
||||||
|
n = 8 - bit_pos;
|
||||||
|
if (n > bit_size)
|
||||||
|
n = bit_size;
|
||||||
|
if (bit_pos)
|
||||||
|
vpushi(bit_pos), gen_op(TOK_SHR), bit_pos = 0; // X B Y
|
||||||
|
if (n < 8)
|
||||||
|
vpushi((1 << n) - 1), gen_op('&');
|
||||||
|
gen_cast(type);
|
||||||
|
if (bits)
|
||||||
|
vpushi(bits), gen_op(TOK_SHL);
|
||||||
|
vrotb(3); // B Y X
|
||||||
|
gen_op('|'); // B X
|
||||||
|
bits += n, bit_size -= n, o = 1;
|
||||||
|
} while (bit_size);
|
||||||
|
vswap(), vpop();
|
||||||
|
if (!(type->t & VT_UNSIGNED)) {
|
||||||
|
n = ((type->t & VT_BTYPE) == VT_LLONG ? 64 : 32) - bits;
|
||||||
|
vpushi(n), gen_op(TOK_SHL);
|
||||||
|
vpushi(n), gen_op(TOK_SAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* single-byte store mode for packed or otherwise unaligned bitfields */
|
||||||
|
void store_packed_bf(int bit_pos, int bit_size)
|
||||||
|
{
|
||||||
|
int bits, n, o, m, c;
|
||||||
|
|
||||||
|
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
||||||
|
vswap(); // X B
|
||||||
|
save_reg_upstack(vtop->r, 1);
|
||||||
|
bits = 0, o = bit_pos >> 3, bit_pos &= 7;
|
||||||
|
do {
|
||||||
|
incr_bf_adr(o); // X B
|
||||||
|
vswap(); //B X
|
||||||
|
c ? vdup() : gv_dup(); // B V X
|
||||||
|
vrott(3); // X B V
|
||||||
|
if (bits)
|
||||||
|
vpushi(bits), gen_op(TOK_SHR);
|
||||||
|
if (bit_pos)
|
||||||
|
vpushi(bit_pos), gen_op(TOK_SHL);
|
||||||
|
n = 8 - bit_pos;
|
||||||
|
if (n > bit_size)
|
||||||
|
n = bit_size;
|
||||||
|
if (n < 8) {
|
||||||
|
m = ((1 << n) - 1) << bit_pos;
|
||||||
|
vpushi(m), gen_op('&'); // X B V1
|
||||||
|
vpushv(vtop-1); // X B V1 B
|
||||||
|
vpushi(m & 0x80 ? ~m & 0x7f : ~m);
|
||||||
|
gen_op('&'); // X B V1 B1
|
||||||
|
gen_op('|'); // X B V2
|
||||||
|
}
|
||||||
|
vdup(), vtop[-1] = vtop[-2]; // X B B V2
|
||||||
|
vstore(), vpop(); // X B
|
||||||
|
bits += n, bit_size -= n, bit_pos = 0, o = 1;
|
||||||
|
} while (bit_size);
|
||||||
|
vpop(), vpop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int adjust_bf(SValue *sv, int bit_pos, int bit_size)
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
if (0 == sv->type.ref)
|
||||||
|
return 0;
|
||||||
|
t = sv->type.ref->auxtype;
|
||||||
|
if (t != -1 && t != VT_STRUCT) {
|
||||||
|
sv->type.t = (sv->type.t & ~VT_BTYPE) | t;
|
||||||
|
sv->r = (sv->r & ~VT_LVAL_TYPE) | lvalue_type(sv->type.t);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
/* store vtop a register belonging to class 'rc'. lvalues are
|
/* store vtop a register belonging to class 'rc'. lvalues are
|
||||||
converted to values. Cannot be used if cannot be converted to
|
converted to values. Cannot be used if cannot be converted to
|
||||||
register value (such as structures). */
|
register value (such as structures). */
|
||||||
ST_FUNC int gv(int rc)
|
ST_FUNC int gv(int rc)
|
||||||
{
|
{
|
||||||
int r, bit_pos, bit_size, size, align;
|
int r, bit_pos, bit_size, size, align, rc2;
|
||||||
int rc2;
|
|
||||||
|
|
||||||
/* NOTE: get_reg can modify vstack[] */
|
/* NOTE: get_reg can modify vstack[] */
|
||||||
if (vtop->type.t & VT_BITFIELD) {
|
if (vtop->type.t & VT_BITFIELD) {
|
||||||
CType type;
|
CType type;
|
||||||
int bits = 32;
|
|
||||||
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
bit_pos = BIT_POS(vtop->type.t);
|
||||||
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
bit_size = BIT_SIZE(vtop->type.t);
|
||||||
/* remove bit field info to avoid loops */
|
/* remove bit field info to avoid loops */
|
||||||
vtop->type.t &= ~VT_BITFIELD & ((1 << VT_STRUCT_SHIFT) - 1);
|
vtop->type.t &= ~VT_STRUCT_MASK;
|
||||||
/* cast to int to propagate signedness in following ops */
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
type.ref = NULL;
|
||||||
type.t = VT_LLONG;
|
type.t = vtop->type.t & VT_UNSIGNED;
|
||||||
bits = 64;
|
if ((vtop->type.t & VT_BTYPE) == VT_BOOL)
|
||||||
} else
|
|
||||||
type.t = VT_INT;
|
|
||||||
if((vtop->type.t & VT_UNSIGNED)
|
|
||||||
|| (vtop->type.t & VT_BTYPE) == VT_BOOL)
|
|
||||||
type.t |= VT_UNSIGNED;
|
type.t |= VT_UNSIGNED;
|
||||||
|
|
||||||
|
r = adjust_bf(vtop, bit_pos, bit_size);
|
||||||
|
|
||||||
|
if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
|
||||||
|
type.t |= VT_LLONG;
|
||||||
|
else
|
||||||
|
type.t |= VT_INT;
|
||||||
|
|
||||||
|
if (r == VT_STRUCT) {
|
||||||
|
load_packed_bf(&type, bit_pos, bit_size);
|
||||||
|
} else {
|
||||||
|
int bits = (type.t & VT_BTYPE) == VT_LLONG ? 64 : 32;
|
||||||
|
/* cast to int to propagate signedness in following ops */
|
||||||
gen_cast(&type);
|
gen_cast(&type);
|
||||||
/* generate shifts */
|
/* generate shifts */
|
||||||
vpushi(bits - (bit_pos + bit_size));
|
vpushi(bits - (bit_pos + bit_size));
|
||||||
|
|
@ -1097,6 +1201,7 @@ ST_FUNC int gv(int rc)
|
||||||
vpushi(bits - bit_size);
|
vpushi(bits - bit_size);
|
||||||
/* NOTE: transformed to SHR if unsigned */
|
/* NOTE: transformed to SHR if unsigned */
|
||||||
gen_op(TOK_SAR);
|
gen_op(TOK_SAR);
|
||||||
|
}
|
||||||
r = gv(rc);
|
r = gv(rc);
|
||||||
} else {
|
} else {
|
||||||
if (is_float(vtop->type.t) &&
|
if (is_float(vtop->type.t) &&
|
||||||
|
|
@ -1362,6 +1467,10 @@ static void gv_dup(void)
|
||||||
t = vtop->type.t;
|
t = vtop->type.t;
|
||||||
#if PTR_SIZE == 4
|
#if PTR_SIZE == 4
|
||||||
if ((t & VT_BTYPE) == VT_LLONG) {
|
if ((t & VT_BTYPE) == VT_LLONG) {
|
||||||
|
if (t & VT_BITFIELD) {
|
||||||
|
gv(RC_INT);
|
||||||
|
t = vtop->type.t;
|
||||||
|
}
|
||||||
lexpand();
|
lexpand();
|
||||||
gv_dup();
|
gv_dup();
|
||||||
vswap();
|
vswap();
|
||||||
|
|
@ -2920,45 +3029,49 @@ ST_FUNC void vstore(void)
|
||||||
/* save lvalue as expression result (example: s.b = s.a = n;) */
|
/* save lvalue as expression result (example: s.b = s.a = n;) */
|
||||||
vdup(), vtop[-1] = vtop[-2];
|
vdup(), vtop[-1] = vtop[-2];
|
||||||
|
|
||||||
bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f;
|
bit_pos = BIT_POS(ft);
|
||||||
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
bit_size = BIT_SIZE(ft);
|
||||||
/* remove bit field info to avoid loops */
|
/* remove bit field info to avoid loops */
|
||||||
vtop[-1].type.t = ft & ~VT_BITFIELD & ((1 << VT_STRUCT_SHIFT) - 1);
|
vtop[-1].type.t = ft & ~VT_STRUCT_MASK;
|
||||||
|
|
||||||
if ((ft & VT_BTYPE) == VT_BOOL) {
|
if ((ft & VT_BTYPE) == VT_BOOL) {
|
||||||
gen_cast(&vtop[-1].type);
|
gen_cast(&vtop[-1].type);
|
||||||
vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
|
vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* duplicate destination */
|
r = adjust_bf(vtop - 1, bit_pos, bit_size);
|
||||||
vdup();
|
if (r == VT_STRUCT) {
|
||||||
vtop[-1] = vtop[-2];
|
gen_cast_s((ft & VT_BTYPE) == VT_LLONG ? VT_LLONG : VT_INT);
|
||||||
|
store_packed_bf(bit_pos, bit_size);
|
||||||
/* mask and shift source */
|
|
||||||
if((ft & VT_BTYPE) != VT_BOOL) {
|
|
||||||
if((ft & VT_BTYPE) == VT_LLONG) {
|
|
||||||
vpushll((1ULL << bit_size) - 1ULL);
|
|
||||||
} else {
|
} else {
|
||||||
vpushi((1 << bit_size) - 1);
|
unsigned long long mask = (1ULL << bit_size) - 1;
|
||||||
}
|
if ((ft & VT_BTYPE) != VT_BOOL) {
|
||||||
|
/* mask source */
|
||||||
|
if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG)
|
||||||
|
vpushll(mask);
|
||||||
|
else
|
||||||
|
vpushi((unsigned)mask);
|
||||||
gen_op('&');
|
gen_op('&');
|
||||||
}
|
}
|
||||||
|
/* shift source */
|
||||||
vpushi(bit_pos);
|
vpushi(bit_pos);
|
||||||
gen_op(TOK_SHL);
|
gen_op(TOK_SHL);
|
||||||
/* load destination, mask and or with source */
|
|
||||||
vswap();
|
vswap();
|
||||||
if((ft & VT_BTYPE) == VT_LLONG) {
|
/* duplicate destination */
|
||||||
vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos));
|
vdup();
|
||||||
} else {
|
vrott(3);
|
||||||
vpushi(~(((1 << bit_size) - 1) << bit_pos));
|
/* load destination, mask and or with source */
|
||||||
}
|
if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
|
||||||
|
vpushll(~(mask << bit_pos));
|
||||||
|
else
|
||||||
|
vpushi(~((unsigned)mask << bit_pos));
|
||||||
gen_op('&');
|
gen_op('&');
|
||||||
gen_op('|');
|
gen_op('|');
|
||||||
/* store result */
|
/* store result */
|
||||||
vstore();
|
vstore();
|
||||||
/* ... and discard */
|
/* ... and discard */
|
||||||
vpop();
|
vpop();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* bound check case */
|
/* bound check case */
|
||||||
|
|
@ -3276,112 +3389,114 @@ static void struct_add_offset (Sym *s, int offset)
|
||||||
|
|
||||||
static void struct_layout(CType *type, AttributeDef *ad)
|
static void struct_layout(CType *type, AttributeDef *ad)
|
||||||
{
|
{
|
||||||
int align, maxalign, offset, c, bit_pos, bt, prevbt, prev_bit_size;
|
int size, align, maxalign, offset, c, bit_pos, bit_size;
|
||||||
|
int packed, a, bt, prevbt, prev_bit_size;
|
||||||
int pcc = !tcc_state->ms_bitfields;
|
int pcc = !tcc_state->ms_bitfields;
|
||||||
int packwarn = tcc_state->warn_gcc_compat;
|
int pragma_pack = *tcc_state->pack_stack_ptr;
|
||||||
int typealign, bit_size, size;
|
|
||||||
|
|
||||||
Sym *f;
|
Sym *f;
|
||||||
if (ad->a.aligned)
|
|
||||||
maxalign = 1 << (ad->a.aligned - 1);
|
|
||||||
else
|
|
||||||
maxalign = 1;
|
maxalign = 1;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
c = 0;
|
c = 0;
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
prevbt = VT_STRUCT; /* make it never match */
|
prevbt = VT_STRUCT; /* make it never match */
|
||||||
prev_bit_size = 0;
|
prev_bit_size = 0;
|
||||||
size = 0;
|
|
||||||
|
//#define BF_DEBUG
|
||||||
|
|
||||||
for (f = type->ref->next; f; f = f->next) {
|
for (f = type->ref->next; f; f = f->next) {
|
||||||
size = type_size(&f->type, &typealign);
|
|
||||||
if (f->type.t & VT_BITFIELD)
|
if (f->type.t & VT_BITFIELD)
|
||||||
bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
bit_size = BIT_SIZE(f->type.t);
|
||||||
else
|
else
|
||||||
bit_size = -1;
|
bit_size = -1;
|
||||||
if (bit_size == 0 && pcc) {
|
size = type_size(&f->type, &align);
|
||||||
/* Zero-width bit-fields in PCC mode aren't affected
|
a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0;
|
||||||
by any packing (attribute or pragma). */
|
packed = 0;
|
||||||
align = typealign;
|
|
||||||
} else if (f->r > 1) {
|
if (pcc && bit_size == 0) {
|
||||||
align = f->r;
|
/* in pcc mode, packing does not affect zero-width bitfields */
|
||||||
} else if (ad->a.packed || f->r == 1) {
|
|
||||||
align = 1;
|
|
||||||
/* Packed fields or packed records don't let the base type
|
|
||||||
influence the records type alignment. */
|
|
||||||
typealign = 1;
|
|
||||||
} else {
|
} else {
|
||||||
align = typealign;
|
/* in pcc mode, attribute packed overrides if set. */
|
||||||
|
if (pcc && (f->a.packed || ad->a.packed))
|
||||||
|
align = packed = 1;
|
||||||
|
|
||||||
|
/* pragma pack overrides align if lesser and packs bitfields always */
|
||||||
|
if (pragma_pack) {
|
||||||
|
packed = 1;
|
||||||
|
if (pragma_pack < align)
|
||||||
|
align = pragma_pack;
|
||||||
|
/* in pcc mode pragma pack also overrides individual align */
|
||||||
|
if (pcc && pragma_pack < a)
|
||||||
|
a = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* some individual align was specified */
|
||||||
|
if (a)
|
||||||
|
align = a;
|
||||||
|
|
||||||
if (type->ref->type.t == VT_UNION) {
|
if (type->ref->type.t == VT_UNION) {
|
||||||
if (pcc && bit_size >= 0)
|
if (pcc && bit_size >= 0)
|
||||||
size = (bit_size + 7) >> 3;
|
size = (bit_size + 7) >> 3;
|
||||||
/* Bit position is already zero from our caller. */
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
if (size > c)
|
if (size > c)
|
||||||
c = size;
|
c = size;
|
||||||
|
|
||||||
} else if (bit_size < 0) {
|
} else if (bit_size < 0) {
|
||||||
int addbytes = pcc ? (bit_pos + 7) >> 3 : 0;
|
if (pcc)
|
||||||
prevbt = VT_STRUCT;
|
c += (bit_pos + 7) >> 3;
|
||||||
prev_bit_size = 0;
|
c = (c + align - 1) & -align;
|
||||||
c = (c + addbytes + align - 1) & -align;
|
|
||||||
offset = c;
|
offset = c;
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
c += size;
|
c += size;
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
|
prevbt = VT_STRUCT;
|
||||||
|
prev_bit_size = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* A bit-field. Layout is more complicated. There are two
|
/* A bit-field. Layout is more complicated. There are two
|
||||||
options TCC implements: PCC compatible and MS compatible
|
options: PCC (GCC) compatible and MS compatible */
|
||||||
(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) {
|
if (pcc) {
|
||||||
/* In PCC layout a non-packed bit-field is placed adjacent
|
/* In PCC layout a bit-field is placed adjacent to the
|
||||||
to the preceding bit-fields, except if it would overflow
|
preceding bit-fields, except if:
|
||||||
its container (depending on base type) or it's a zero-width
|
- it has zero-width
|
||||||
bit-field. Packed non-zero-width bit-fields always are
|
- an individual alignment was given
|
||||||
placed adjacent. */
|
- it would overflow its base type container and
|
||||||
int ofs = (c * 8 + bit_pos) % (typealign * 8);
|
there is no packing */
|
||||||
int ofs2 = ofs + bit_size + (typealign * 8) - 1;
|
if (bit_size == 0) {
|
||||||
if (bit_size == 0 ||
|
new_field:
|
||||||
(typealign != 1 &&
|
c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align;
|
||||||
(ofs2 / (typealign * 8)) > (size/typealign))) {
|
|
||||||
c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign;
|
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
} else if (bit_pos + bit_size > size * 8) {
|
} else if (f->a.aligned) {
|
||||||
c += bit_pos >> 3;
|
goto new_field;
|
||||||
bit_pos &= 7;
|
} else if (!packed) {
|
||||||
if (bit_pos + bit_size > size * 8) {
|
int a8 = align * 8;
|
||||||
c += 1, bit_pos = 0;
|
int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8;
|
||||||
if ((ad->a.packed || f->r) && packwarn) {
|
if (ofs > size / align)
|
||||||
tcc_warning("struct layout not compatible with GCC (internal limitation)");
|
goto new_field;
|
||||||
packwarn = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* in pcc mode, long long bitfields have type int if they fit */
|
||||||
|
if (size == 8 && bit_size <= 32) {
|
||||||
|
f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT;
|
||||||
|
size = 4;
|
||||||
}
|
}
|
||||||
|
if (bit_pos >= size * 8) {
|
||||||
|
c += size;
|
||||||
|
bit_pos -= size * 8;
|
||||||
}
|
}
|
||||||
offset = c;
|
offset = c;
|
||||||
/* In PCC layout named bit-fields influence the alignment
|
/* In PCC layout named bit-fields influence the alignment
|
||||||
of the containing struct using the base types alignment,
|
of the containing struct using the base types alignment,
|
||||||
except for packed fields (which here have correct
|
except for packed fields (which here have correct align). */
|
||||||
align/typealign). */
|
if (f->v & SYM_FIRST_ANOM)
|
||||||
if ((f->v & SYM_FIRST_ANOM))
|
|
||||||
align = 1;
|
align = 1;
|
||||||
} else {
|
} else {
|
||||||
bt = f->type.t & VT_BTYPE;
|
bt = f->type.t & VT_BTYPE;
|
||||||
if ((bit_pos + bit_size > size * 8) ||
|
if ((bit_pos + bit_size > size * 8)
|
||||||
(bit_size > 0) == (bt != prevbt)) {
|
|| (bit_size > 0) == (bt != prevbt)
|
||||||
c = (c + typealign - 1) & -typealign;
|
) {
|
||||||
|
c = (c + align - 1) & -align;
|
||||||
offset = c;
|
offset = c;
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
/* In MS bitfield mode a bit-field run always uses
|
/* In MS bitfield mode a bit-field run always uses
|
||||||
|
|
@ -3400,23 +3515,22 @@ static void struct_layout(CType *type, AttributeDef *ad)
|
||||||
prevbt = bt;
|
prevbt = bt;
|
||||||
prev_bit_size = bit_size;
|
prev_bit_size = bit_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
|
f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
|
||||||
| (bit_pos << VT_STRUCT_SHIFT);
|
| (bit_pos << VT_STRUCT_SHIFT);
|
||||||
bit_pos += bit_size;
|
bit_pos += bit_size;
|
||||||
if (pcc && bit_pos >= size * 8) {
|
|
||||||
c += size;
|
|
||||||
bit_pos -= size * 8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (align > maxalign)
|
if (align > maxalign)
|
||||||
maxalign = align;
|
maxalign = align;
|
||||||
#if 0
|
|
||||||
printf("set field %s offset=%d",
|
#ifdef BF_DEBUG
|
||||||
get_tok_str(f->v & ~SYM_FIELD, NULL), offset);
|
printf("set field %s offset %-2d size %-2d align %-2d",
|
||||||
|
get_tok_str(f->v & ~SYM_FIELD, NULL), offset, size, align);
|
||||||
if (f->type.t & VT_BITFIELD) {
|
if (f->type.t & VT_BITFIELD) {
|
||||||
printf(" pos=%d size=%d",
|
printf(" pos %-2d bits %-2d",
|
||||||
(f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
|
BIT_POS(f->type.t),
|
||||||
(f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
|
BIT_SIZE(f->type.t)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -3458,18 +3572,91 @@ static void struct_layout(CType *type, AttributeDef *ad)
|
||||||
|
|
||||||
f->r = 0;
|
f->r = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pcc)
|
||||||
|
c += (bit_pos + 7) >> 3;
|
||||||
|
|
||||||
|
a = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 0;
|
||||||
|
if (a < maxalign)
|
||||||
|
a = maxalign;
|
||||||
|
c = (c + a - 1) & -a;
|
||||||
|
|
||||||
/* store size and alignment */
|
/* store size and alignment */
|
||||||
type->ref->c = (c + (pcc ? (bit_pos + 7) >> 3 : 0)
|
type->ref->c = c;
|
||||||
+ maxalign - 1) & -maxalign;
|
type->ref->r = a;
|
||||||
type->ref->r = maxalign;
|
|
||||||
if (offset + size > type->ref->c && type->ref->c)
|
#ifdef BF_DEBUG
|
||||||
tcc_warning("will touch memory past end of the struct (internal limitation)");
|
printf("struct size %-2d align %-2d\n\n", c, a), fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check whether we can access bitfields by their type */
|
||||||
|
for (f = type->ref->next; f; f = f->next) {
|
||||||
|
int s, px, cx, c0;
|
||||||
|
CType t;
|
||||||
|
|
||||||
|
if (0 == (f->type.t & VT_BITFIELD))
|
||||||
|
continue;
|
||||||
|
f->type.ref = f;
|
||||||
|
f->auxtype = -1;
|
||||||
|
bit_size = BIT_SIZE(f->type.t);
|
||||||
|
if (bit_size == 0)
|
||||||
|
continue;
|
||||||
|
bit_pos = BIT_POS(f->type.t);
|
||||||
|
size = type_size(&f->type, &align);
|
||||||
|
|
||||||
|
if (bit_pos + bit_size <= size * 8 && f->c + size <= c)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* try to access the field using a differnt type */
|
||||||
|
c0 = -1, s = align = 1;
|
||||||
|
for (;;) {
|
||||||
|
px = f->c * 8 + bit_pos;
|
||||||
|
cx = (px >> 3) & -align;
|
||||||
|
px = px - (cx << 3);
|
||||||
|
if (c0 == cx)
|
||||||
|
break;
|
||||||
|
s = (px + bit_size + 7) >> 3;
|
||||||
|
if (s > 4) {
|
||||||
|
t.t = VT_LLONG;
|
||||||
|
} else if (s > 2) {
|
||||||
|
t.t = VT_INT;
|
||||||
|
} else if (s > 1) {
|
||||||
|
t.t = VT_SHORT;
|
||||||
|
} else {
|
||||||
|
t.t = VT_BYTE;
|
||||||
|
}
|
||||||
|
s = type_size(&t, &align);
|
||||||
|
c0 = cx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (px + bit_size <= s * 8 && cx + s <= c) {
|
||||||
|
/* update offset and bit position */
|
||||||
|
f->c = cx;
|
||||||
|
bit_pos = px;
|
||||||
|
f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
|
||||||
|
| (bit_pos << VT_STRUCT_SHIFT);
|
||||||
|
if (s != size)
|
||||||
|
f->auxtype = t.t;
|
||||||
|
} else {
|
||||||
|
/* fall back to load/store single-byte wise */
|
||||||
|
f->auxtype = VT_STRUCT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BF_DEBUG
|
||||||
|
printf("FIX field %s offset %-2d size %-2d align %-2d "
|
||||||
|
"pos %-2d bits %-2d %s\n",
|
||||||
|
get_tok_str(f->v & ~SYM_FIELD, NULL),
|
||||||
|
cx, s, align, px, bit_size,
|
||||||
|
f->auxtype == VT_PTR ? " byte-wise" : ""
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */
|
/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */
|
||||||
static void struct_decl(CType *type, int u)
|
static void struct_decl(CType *type, int u)
|
||||||
{
|
{
|
||||||
int v, c, size, align, flexible, alignoverride;
|
int v, c, size, align, flexible;
|
||||||
int bit_size, bsize, bt;
|
int bit_size, bsize, bt;
|
||||||
Sym *s, *ss, **ps;
|
Sym *s, *ss, **ps;
|
||||||
AttributeDef ad, ad1;
|
AttributeDef ad, ad1;
|
||||||
|
|
@ -3623,17 +3810,6 @@ do_decl:
|
||||||
parse_attribute(&ad1);
|
parse_attribute(&ad1);
|
||||||
}
|
}
|
||||||
size = type_size(&type1, &align);
|
size = type_size(&type1, &align);
|
||||||
/* Only remember non-default alignment. */
|
|
||||||
alignoverride = 0;
|
|
||||||
if (ad1.a.aligned) {
|
|
||||||
int speca = 1 << (ad1.a.aligned - 1);
|
|
||||||
alignoverride = speca;
|
|
||||||
} else if (ad1.a.packed || ad.a.packed) {
|
|
||||||
alignoverride = 1;
|
|
||||||
} else if (*tcc_state->pack_stack_ptr) {
|
|
||||||
if (align >= *tcc_state->pack_stack_ptr)
|
|
||||||
alignoverride = *tcc_state->pack_stack_ptr;
|
|
||||||
}
|
|
||||||
if (bit_size >= 0) {
|
if (bit_size >= 0) {
|
||||||
bt = type1.t & VT_BTYPE;
|
bt = type1.t & VT_BTYPE;
|
||||||
if (bt != VT_INT &&
|
if (bt != VT_INT &&
|
||||||
|
|
@ -3646,9 +3822,12 @@ do_decl:
|
||||||
if (bit_size > bsize) {
|
if (bit_size > bsize) {
|
||||||
tcc_error("width of '%s' exceeds its type",
|
tcc_error("width of '%s' exceeds its type",
|
||||||
get_tok_str(v, NULL));
|
get_tok_str(v, NULL));
|
||||||
} else if (bit_size == bsize) {
|
} else if (bit_size == bsize
|
||||||
|
&& !ad.a.packed && !ad1.a.packed) {
|
||||||
/* no need for bit fields */
|
/* no need for bit fields */
|
||||||
;
|
;
|
||||||
|
} else if (bit_size == 64) {
|
||||||
|
tcc_error("field width 64 not implemented");
|
||||||
} else {
|
} else {
|
||||||
type1.t = (type1.t & ~VT_STRUCT_MASK)
|
type1.t = (type1.t & ~VT_STRUCT_MASK)
|
||||||
| VT_BITFIELD
|
| VT_BITFIELD
|
||||||
|
|
@ -3668,7 +3847,8 @@ do_decl:
|
||||||
v = anon_sym++;
|
v = anon_sym++;
|
||||||
}
|
}
|
||||||
if (v) {
|
if (v) {
|
||||||
ss = sym_push(v | SYM_FIELD, &type1, alignoverride, 0);
|
ss = sym_push(v | SYM_FIELD, &type1, 0, 0);
|
||||||
|
ss->a = ad1.a;
|
||||||
*ps = ss;
|
*ps = ss;
|
||||||
ps = &ss->next;
|
ps = &ss->next;
|
||||||
}
|
}
|
||||||
|
|
@ -4495,7 +4675,10 @@ ST_FUNC void unary(void)
|
||||||
next();
|
next();
|
||||||
in_sizeof++;
|
in_sizeof++;
|
||||||
expr_type(&type, 1); // Perform a in_sizeof = 0;
|
expr_type(&type, 1); // Perform a in_sizeof = 0;
|
||||||
|
s = vtop[1].sym; /* hack: accessing previous vtop */
|
||||||
size = type_size(&type, &align);
|
size = type_size(&type, &align);
|
||||||
|
if (s && s->a.aligned)
|
||||||
|
align = 1 << (s->a.aligned - 1);
|
||||||
if (t == TOK_SIZEOF) {
|
if (t == TOK_SIZEOF) {
|
||||||
if (!(type.t & VT_VLA)) {
|
if (!(type.t & VT_VLA)) {
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
|
|
@ -6140,9 +6323,8 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
|
||||||
/* store a value or an expression directly in global data or in local array */
|
/* store a value or an expression directly in global data or in local array */
|
||||||
static void init_putv(CType *type, Section *sec, unsigned long c)
|
static void init_putv(CType *type, Section *sec, unsigned long c)
|
||||||
{
|
{
|
||||||
int bt, bit_pos, bit_size;
|
int bt;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
unsigned long long bit_mask;
|
|
||||||
CType dtype;
|
CType dtype;
|
||||||
|
|
||||||
dtype = *type;
|
dtype = *type;
|
||||||
|
|
@ -6158,15 +6340,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
||||||
section_reserve(sec, c + size);
|
section_reserve(sec, c + size);
|
||||||
ptr = sec->data + c;
|
ptr = sec->data + c;
|
||||||
/* XXX: make code faster ? */
|
/* XXX: make code faster ? */
|
||||||
if (!(type->t & VT_BITFIELD)) {
|
|
||||||
bit_pos = 0;
|
|
||||||
bit_size = PTR_SIZE * 8;
|
|
||||||
bit_mask = -1LL;
|
|
||||||
} else {
|
|
||||||
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
|
||||||
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
|
||||||
bit_mask = (1LL << bit_size) - 1;
|
|
||||||
}
|
|
||||||
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
|
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
|
||||||
vtop->sym->v >= SYM_FIRST_ANOM &&
|
vtop->sym->v >= SYM_FIRST_ANOM &&
|
||||||
/* XXX This rejects compound literals like
|
/* XXX This rejects compound literals like
|
||||||
|
|
@ -6225,25 +6398,42 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
||||||
bt == VT_DOUBLE ||
|
bt == VT_DOUBLE ||
|
||||||
bt == VT_LDOUBLE ||
|
bt == VT_LDOUBLE ||
|
||||||
#if PTR_SIZE == 8
|
#if PTR_SIZE == 8
|
||||||
(bt == VT_LLONG && bit_size != 64) ||
|
bt == VT_INT ||
|
||||||
bt == VT_INT
|
|
||||||
#else
|
#else
|
||||||
bt == VT_LLONG ||
|
bt == VT_LLONG ||
|
||||||
(bt == VT_INT && bit_size != 32)
|
|
||||||
#endif
|
#endif
|
||||||
|
(type->t & VT_BITFIELD)
|
||||||
))
|
))
|
||||||
tcc_error("initializer element is not computable at load time");
|
tcc_error("initializer element is not computable at load time");
|
||||||
|
|
||||||
|
if (type->t & VT_BITFIELD) {
|
||||||
|
int bit_pos, bit_size, bits, n;
|
||||||
|
unsigned char *p, v, m;
|
||||||
|
bit_pos = BIT_POS(vtop->type.t);
|
||||||
|
bit_size = BIT_SIZE(vtop->type.t);
|
||||||
|
p = (unsigned char*)ptr + (bit_pos >> 3);
|
||||||
|
bit_pos &= 7, bits = 0;
|
||||||
|
while (bit_size) {
|
||||||
|
n = 8 - bit_pos;
|
||||||
|
if (n > bit_size)
|
||||||
|
n = bit_size;
|
||||||
|
v = vtop->c.i >> bits << bit_pos;
|
||||||
|
m = ((1 << n) - 1) << bit_pos;
|
||||||
|
*p = (*p & ~m) | (v & m);
|
||||||
|
bits += n, bit_size -= n, bit_pos = 0, ++p;
|
||||||
|
}
|
||||||
|
} else
|
||||||
switch(bt) {
|
switch(bt) {
|
||||||
/* XXX: when cross-compiling we assume that each type has the
|
/* XXX: when cross-compiling we assume that each type has the
|
||||||
same representation on host and target, which is likely to
|
same representation on host and target, which is likely to
|
||||||
be wrong in the case of long double */
|
be wrong in the case of long double */
|
||||||
case VT_BOOL:
|
case VT_BOOL:
|
||||||
vtop->c.i = (vtop->c.i != 0);
|
vtop->c.i = vtop->c.i != 0;
|
||||||
case VT_BYTE:
|
case VT_BYTE:
|
||||||
*(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
|
*(char *)ptr |= vtop->c.i;
|
||||||
break;
|
break;
|
||||||
case VT_SHORT:
|
case VT_SHORT:
|
||||||
*(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
|
*(short *)ptr |= vtop->c.i;
|
||||||
break;
|
break;
|
||||||
case VT_FLOAT:
|
case VT_FLOAT:
|
||||||
*(float*)ptr = vtop->c.f;
|
*(float*)ptr = vtop->c.f;
|
||||||
|
|
@ -6270,14 +6460,14 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
||||||
break;
|
break;
|
||||||
#if PTR_SIZE != 8
|
#if PTR_SIZE != 8
|
||||||
case VT_LLONG:
|
case VT_LLONG:
|
||||||
*(long long *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
|
*(long long *)ptr |= vtop->c.i;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case VT_LLONG:
|
case VT_LLONG:
|
||||||
#endif
|
#endif
|
||||||
case VT_PTR:
|
case VT_PTR:
|
||||||
{
|
{
|
||||||
addr_t val = (vtop->c.i & bit_mask) << bit_pos;
|
addr_t val = vtop->c.i;
|
||||||
#if PTR_SIZE == 8
|
#if PTR_SIZE == 8
|
||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM)
|
||||||
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
||||||
|
|
@ -6292,7 +6482,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
int val = (vtop->c.i & bit_mask) << bit_pos;
|
int val = vtop->c.i;
|
||||||
#if PTR_SIZE == 8
|
#if PTR_SIZE == 8
|
||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM)
|
||||||
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
||||||
|
|
|
||||||
|
|
@ -1050,8 +1050,8 @@ int pad1;
|
||||||
but __alignof__ returns the wrong result (4) because we
|
but __alignof__ returns the wrong result (4) because we
|
||||||
can't store the alignment yet when specified on symbols
|
can't store the alignment yet when specified on symbols
|
||||||
directly (it's stored in the type so we'd need to make
|
directly (it's stored in the type so we'd need to make
|
||||||
a copy of it).
|
a copy of it). -- FIXED */
|
||||||
struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
|
struct aligntest7 altest7[2] __attribute__((aligned(16)));
|
||||||
|
|
||||||
struct aligntest8
|
struct aligntest8
|
||||||
{
|
{
|
||||||
|
|
@ -1161,8 +1161,8 @@ void struct_test()
|
||||||
sizeof(altest5), __alignof__(altest5));
|
sizeof(altest5), __alignof__(altest5));
|
||||||
printf("altest6 sizeof=%d alignof=%d\n",
|
printf("altest6 sizeof=%d alignof=%d\n",
|
||||||
sizeof(altest6), __alignof__(altest6));
|
sizeof(altest6), __alignof__(altest6));
|
||||||
/*printf("altest7 sizeof=%d alignof=%d\n",
|
printf("altest7 sizeof=%d alignof=%d\n",
|
||||||
sizeof(altest7), __alignof__(altest7));*/
|
sizeof(altest7), __alignof__(altest7));
|
||||||
|
|
||||||
/* empty structures (GCC extension) */
|
/* empty structures (GCC extension) */
|
||||||
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue