added bitfields support
This commit is contained in:
parent
cb693e5318
commit
3d1bdcf70e
1 changed files with 181 additions and 54 deletions
235
tcc.c
235
tcc.c
|
@ -164,7 +164,7 @@ int gnu_ext = 1;
|
||||||
#define VT_TYPEDEF 0x00000100 /* typedef definition */
|
#define VT_TYPEDEF 0x00000100 /* typedef definition */
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
#define VT_STRUCT_SHIFT 15 /* structure/enum name shift (14 bits left) */
|
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
|
||||||
|
|
||||||
#define VT_BTYPE_SHIFT 9
|
#define VT_BTYPE_SHIFT 9
|
||||||
#define VT_INT (0 << VT_BTYPE_SHIFT) /* integer type */
|
#define VT_INT (0 << VT_BTYPE_SHIFT) /* integer type */
|
||||||
|
@ -178,6 +178,7 @@ int gnu_ext = 1;
|
||||||
#define VT_BTYPE (0xf << VT_BTYPE_SHIFT) /* mask for basic type */
|
#define VT_BTYPE (0xf << VT_BTYPE_SHIFT) /* mask for basic type */
|
||||||
#define VT_UNSIGNED (0x10 << VT_BTYPE_SHIFT) /* unsigned type */
|
#define VT_UNSIGNED (0x10 << VT_BTYPE_SHIFT) /* unsigned type */
|
||||||
#define VT_ARRAY (0x20 << VT_BTYPE_SHIFT) /* array type (also has VT_PTR) */
|
#define VT_ARRAY (0x20 << VT_BTYPE_SHIFT) /* array type (also has VT_PTR) */
|
||||||
|
#define VT_BITFIELD (0x40 << VT_BTYPE_SHIFT) /* bitfield modifier */
|
||||||
|
|
||||||
#define VT_TYPE 0xfffffe00 /* type mask */
|
#define VT_TYPE 0xfffffe00 /* type mask */
|
||||||
|
|
||||||
|
@ -313,6 +314,7 @@ int get_reg(void);
|
||||||
void macro_subst(int **tok_str, int *tok_len,
|
void macro_subst(int **tok_str, int *tok_len,
|
||||||
Sym **nested_list, int *macro_str);
|
Sym **nested_list, int *macro_str);
|
||||||
int save_reg_forced(int r);
|
int save_reg_forced(int r);
|
||||||
|
void gen_op(int op);
|
||||||
void vstore(void);
|
void vstore(void);
|
||||||
int type_size(int t, int *a);
|
int type_size(int t, int *a);
|
||||||
int pointed_type(int t);
|
int pointed_type(int t);
|
||||||
|
@ -1635,7 +1637,7 @@ void gen_addr32(int c, int t)
|
||||||
|
|
||||||
/* XXX: generate correct pointer for forward references to functions */
|
/* XXX: generate correct pointer for forward references to functions */
|
||||||
/* r = (ft, fc) */
|
/* r = (ft, fc) */
|
||||||
void load(r, ft, fc)
|
void load(int r, int ft, int fc)
|
||||||
{
|
{
|
||||||
int v, t;
|
int v, t;
|
||||||
|
|
||||||
|
@ -1975,18 +1977,35 @@ void move_reg(r, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert a stack entry in register. lvalues are converted as
|
/* convert a (vt, vc) in register. lvalues are converted as
|
||||||
values. Cannot be used if cannot be converted to register value
|
values. Cannot be used if cannot be converted to register value
|
||||||
(such as structures). */
|
(such as structures). */
|
||||||
int gvp(int *p)
|
int gvp(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r, bit_pos, bit_size;
|
||||||
r = p[0] & VT_VALMASK;
|
|
||||||
if (r >= VT_CONST || (p[0] & VT_LVAL))
|
/* NOTE: get_reg can modify vstack[] */
|
||||||
r = get_reg();
|
if (vt & VT_BITFIELD) {
|
||||||
/* NOTE: get_reg can modify p[] */
|
bit_pos = (vt >> VT_STRUCT_SHIFT) & 0x3f;
|
||||||
load(r, p[0], p[1]);
|
bit_size = (vt >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
||||||
p[0] = (p[0] & VT_TYPE) | r;
|
/* remove bit field info to avoid loops */
|
||||||
|
vt &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
||||||
|
/* generate shifts */
|
||||||
|
vpush();
|
||||||
|
vset(VT_CONST, 32 - (bit_pos + bit_size));
|
||||||
|
gen_op(TOK_SHL);
|
||||||
|
vpush();
|
||||||
|
vset(VT_CONST, 32 - bit_size);
|
||||||
|
/* NOTE: transformed to SHR if unsigned */
|
||||||
|
gen_op(TOK_SAR);
|
||||||
|
r = gv();
|
||||||
|
} else {
|
||||||
|
r = vt & VT_VALMASK;
|
||||||
|
if (r >= VT_CONST || (vt & VT_LVAL))
|
||||||
|
r = get_reg();
|
||||||
|
load(r, vt, vc);
|
||||||
|
vt = (vt & VT_TYPE) | r;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1994,12 +2013,12 @@ void vpush(void)
|
||||||
{
|
{
|
||||||
if (vstack_ptr >= vstack + VSTACK_SIZE)
|
if (vstack_ptr >= vstack + VSTACK_SIZE)
|
||||||
error("memory full");
|
error("memory full");
|
||||||
*vstack_ptr++ = vt;
|
|
||||||
*vstack_ptr++ = vc;
|
|
||||||
/* cannot let cpu flags if other instruction are generated */
|
/* cannot let cpu flags if other instruction are generated */
|
||||||
/* XXX: VT_JMP test too ? */
|
/* XXX: VT_JMP test too ? */
|
||||||
if ((vt & VT_VALMASK) == VT_CMP)
|
if ((vt & VT_VALMASK) == VT_CMP)
|
||||||
gvp(vstack_ptr - 2);
|
gvp();
|
||||||
|
*vstack_ptr++ = vt;
|
||||||
|
*vstack_ptr++ = vc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vpop(int *ft, int *fc)
|
void vpop(int *ft, int *fc)
|
||||||
|
@ -2008,18 +2027,25 @@ void vpop(int *ft, int *fc)
|
||||||
*ft = *--vstack_ptr;
|
*ft = *--vstack_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vswap(void)
|
||||||
|
{
|
||||||
|
swap(vstack_ptr - 4, vstack_ptr - 2);
|
||||||
|
swap(vstack_ptr - 3, vstack_ptr - 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* generate a value in a register from vt and vc */
|
/* generate a value in a register from vt and vc */
|
||||||
int gv(void)
|
int gv(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
vpush();
|
vpush(); /* need so that gvp does not allocate the register we
|
||||||
r = gvp(vstack_ptr - 2);
|
currently use */
|
||||||
vpop(&vt, &vc);
|
r = gvp();
|
||||||
|
vstack_ptr -= 2;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle constant optimizations and various machine independant opt */
|
/* handle constant optimizations and various machine independant opt */
|
||||||
void gen_opc(op)
|
void gen_opc(int op)
|
||||||
{
|
{
|
||||||
int fr, ft, fc, r, c1, c2, n;
|
int fr, ft, fc, r, c1, c2, n;
|
||||||
|
|
||||||
|
@ -2098,11 +2124,15 @@ void gen_opc(op)
|
||||||
vpush();
|
vpush();
|
||||||
vt = ft;
|
vt = ft;
|
||||||
vc = fc;
|
vc = fc;
|
||||||
vpush();
|
|
||||||
r = gvp(vstack_ptr - 4);
|
fr = gv(); /* second operand */
|
||||||
fr = gvp(vstack_ptr - 2);
|
|
||||||
vpop(&ft, &fc);
|
vpop(&ft, &fc);
|
||||||
vpop(&vt, &vc);
|
vpush();
|
||||||
|
vt = ft;
|
||||||
|
vc = fc;
|
||||||
|
r = gv(); /* first operand */
|
||||||
|
vpop(&ft, &fc);
|
||||||
|
|
||||||
/* call low level op generator */
|
/* call low level op generator */
|
||||||
gen_op1(op, r, fr);
|
gen_op1(op, r, fr);
|
||||||
}
|
}
|
||||||
|
@ -2217,12 +2247,15 @@ int type_size(int t, int *a)
|
||||||
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
|
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
|
||||||
*a = 4; /* XXX: cannot store it yet. Doing that is safe */
|
*a = 4; /* XXX: cannot store it yet. Doing that is safe */
|
||||||
return s->c;
|
return s->c;
|
||||||
} else if (t & VT_ARRAY) {
|
} else if (bt == VT_PTR) {
|
||||||
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
|
if (t & VT_ARRAY) {
|
||||||
return type_size(s->t, a) * s->c;
|
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
|
||||||
} else if (bt == VT_PTR ||
|
return type_size(s->t, a) * s->c;
|
||||||
bt == VT_INT ||
|
} else {
|
||||||
bt == VT_ENUM) {
|
*a = 4;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
} else if (bt == VT_INT || bt == VT_ENUM) {
|
||||||
*a = 4;
|
*a = 4;
|
||||||
return 4;
|
return 4;
|
||||||
} else if (bt == VT_SHORT) {
|
} else if (bt == VT_SHORT) {
|
||||||
|
@ -2254,7 +2287,7 @@ int mk_pointer(int t)
|
||||||
/* store value in lvalue pushed on stack */
|
/* store value in lvalue pushed on stack */
|
||||||
void vstore(void)
|
void vstore(void)
|
||||||
{
|
{
|
||||||
int ft, fc, r, t, size, align;
|
int ft, fc, r, t, size, align, bit_size, bit_pos;
|
||||||
GFuncContext gf;
|
GFuncContext gf;
|
||||||
|
|
||||||
if ((vt & VT_BTYPE) == VT_STRUCT) {
|
if ((vt & VT_BTYPE) == VT_STRUCT) {
|
||||||
|
@ -2285,6 +2318,31 @@ void vstore(void)
|
||||||
/* generate again current type */
|
/* generate again current type */
|
||||||
vt = ft;
|
vt = ft;
|
||||||
vc = fc;
|
vc = fc;
|
||||||
|
} else if (vstack_ptr[-2] & VT_BITFIELD) {
|
||||||
|
/* bitfield store handling */
|
||||||
|
ft = vstack_ptr[-2];
|
||||||
|
bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f;
|
||||||
|
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
||||||
|
/* remove bit field info to avoid loops */
|
||||||
|
vstack_ptr[-2] = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
|
||||||
|
|
||||||
|
/* mask and shift source */
|
||||||
|
vpush();
|
||||||
|
vset(VT_CONST, (1 << bit_size) - 1);
|
||||||
|
gen_op('&');
|
||||||
|
vpush();
|
||||||
|
vset(VT_CONST, bit_pos);
|
||||||
|
gen_op(TOK_SHL);
|
||||||
|
vpush();
|
||||||
|
/* load destination, mask and or with source */
|
||||||
|
vt = vstack_ptr[-4];
|
||||||
|
vc = vstack_ptr[-3];
|
||||||
|
vpush();
|
||||||
|
vset(VT_CONST, ~(((1 << bit_size) - 1) << bit_pos));
|
||||||
|
gen_op('&');
|
||||||
|
gen_op('|');
|
||||||
|
/* store result */
|
||||||
|
vstore();
|
||||||
} else {
|
} else {
|
||||||
r = gv(); /* generate value */
|
r = gv(); /* generate value */
|
||||||
vpush();
|
vpush();
|
||||||
|
@ -2302,7 +2360,7 @@ void vstore(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* post defines POST/PRE add. c is the token ++ or -- */
|
/* post defines POST/PRE add. c is the token ++ or -- */
|
||||||
void inc(post, c)
|
void inc(int post, int c)
|
||||||
{
|
{
|
||||||
int r, r1;
|
int r, r1;
|
||||||
test_lvalue();
|
test_lvalue();
|
||||||
|
@ -2329,7 +2387,8 @@ void inc(post, c)
|
||||||
/* enum/struct/union declaration */
|
/* enum/struct/union declaration */
|
||||||
int struct_decl(int u)
|
int struct_decl(int u)
|
||||||
{
|
{
|
||||||
int a, t, b, v, size, align, maxalign, c;
|
int a, t, b, v, size, align, maxalign, c, offset;
|
||||||
|
int bit_size, bit_pos, bsize, bt, lbit_pos;
|
||||||
Sym *s, *ss, **ps;
|
Sym *s, *ss, **ps;
|
||||||
|
|
||||||
a = tok; /* save decl type */
|
a = tok; /* save decl type */
|
||||||
|
@ -2360,6 +2419,8 @@ int struct_decl(int u)
|
||||||
c = 0;
|
c = 0;
|
||||||
maxalign = 0;
|
maxalign = 0;
|
||||||
ps = &s->next;
|
ps = &s->next;
|
||||||
|
bit_pos = 0;
|
||||||
|
offset = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (a == TOK_ENUM) {
|
if (a == TOK_ENUM) {
|
||||||
v = tok;
|
v = tok;
|
||||||
|
@ -2376,26 +2437,92 @@ int struct_decl(int u)
|
||||||
} else {
|
} else {
|
||||||
b = ist();
|
b = ist();
|
||||||
while (1) {
|
while (1) {
|
||||||
t = type_decl(&v, b, TYPE_DIRECT);
|
bit_size = -1;
|
||||||
if ((t & VT_BTYPE) == VT_FUNC ||
|
v = 0;
|
||||||
(t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN)))
|
if (tok != ':') {
|
||||||
error("invalid type");
|
t = type_decl(&v, b, TYPE_DIRECT);
|
||||||
/* XXX: align & correct type size */
|
if ((t & VT_BTYPE) == VT_FUNC ||
|
||||||
v |= SYM_FIELD;
|
(t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN)))
|
||||||
size = type_size(t, &align);
|
error("invalid type for '%s'", get_tok_str(v, 0));
|
||||||
if (a == TOK_STRUCT) {
|
|
||||||
c = (c + align - 1) & -align;
|
|
||||||
ss = sym_push(v, t, c);
|
|
||||||
c += size;
|
|
||||||
} else {
|
} else {
|
||||||
ss = sym_push(v, t, 0);
|
t = b;
|
||||||
if (size > c)
|
}
|
||||||
c = size;
|
if (tok == ':') {
|
||||||
|
next();
|
||||||
|
bit_size = expr_const();
|
||||||
|
/* XXX: handle v = 0 case for messages */
|
||||||
|
if (bit_size < 0)
|
||||||
|
error("negative width in bit-field '%s'",
|
||||||
|
get_tok_str(v, 0));
|
||||||
|
if (v && bit_size == 0)
|
||||||
|
error("zero width for bit-field '%s'",
|
||||||
|
get_tok_str(v, 0));
|
||||||
|
}
|
||||||
|
size = type_size(t, &align);
|
||||||
|
lbit_pos = 0;
|
||||||
|
if (bit_size >= 0) {
|
||||||
|
bt = t & VT_BTYPE;
|
||||||
|
if (bt != VT_INT &&
|
||||||
|
bt != VT_BYTE &&
|
||||||
|
bt != VT_SHORT)
|
||||||
|
error("bitfields must have scalar type");
|
||||||
|
bsize = size * 8;
|
||||||
|
if (bit_size > bsize) {
|
||||||
|
error("width of '%s' exceeds its type",
|
||||||
|
get_tok_str(v, 0));
|
||||||
|
} else if (bit_size == bsize) {
|
||||||
|
/* no need for bit fields */
|
||||||
|
bit_pos = 0;
|
||||||
|
} else if (bit_size == 0) {
|
||||||
|
/* XXX: what to do if only padding in a
|
||||||
|
structure ? */
|
||||||
|
/* zero size: means to pad */
|
||||||
|
if (bit_pos > 0)
|
||||||
|
bit_pos = bsize;
|
||||||
|
} else {
|
||||||
|
/* we do not have enough room ? */
|
||||||
|
if ((bit_pos + bit_size) > bsize)
|
||||||
|
bit_pos = 0;
|
||||||
|
lbit_pos = bit_pos;
|
||||||
|
/* XXX: handle LSB first */
|
||||||
|
t |= VT_BITFIELD |
|
||||||
|
(bit_pos << VT_STRUCT_SHIFT) |
|
||||||
|
(bit_size << (VT_STRUCT_SHIFT + 6));
|
||||||
|
bit_pos += bit_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bit_pos = 0;
|
||||||
|
}
|
||||||
|
if (v) {
|
||||||
|
/* add new memory data only if starting
|
||||||
|
bit field */
|
||||||
|
if (lbit_pos == 0) {
|
||||||
|
if (a == TOK_STRUCT) {
|
||||||
|
c = (c + align - 1) & -align;
|
||||||
|
offset = c;
|
||||||
|
c += size;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
if (size > c)
|
||||||
|
c = size;
|
||||||
|
}
|
||||||
|
if (align > maxalign)
|
||||||
|
maxalign = align;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
printf("add field %s offset=%d",
|
||||||
|
get_tok_str(v, 0), offset);
|
||||||
|
if (t & VT_BITFIELD) {
|
||||||
|
printf(" pos=%d size=%d",
|
||||||
|
(t >> VT_STRUCT_SHIFT) & 0x3f,
|
||||||
|
(t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
ss = sym_push(v | SYM_FIELD, t, offset);
|
||||||
|
*ps = ss;
|
||||||
|
ps = &ss->next;
|
||||||
}
|
}
|
||||||
if (align > maxalign)
|
|
||||||
maxalign = align;
|
|
||||||
*ps = ss;
|
|
||||||
ps = &ss->next;
|
|
||||||
if (tok == ';' || tok == -1)
|
if (tok == ';' || tok == -1)
|
||||||
break;
|
break;
|
||||||
skip(',');
|
skip(',');
|
||||||
|
@ -3003,15 +3130,15 @@ int check_assign_types(int t1, int t2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uneq()
|
void uneq(void)
|
||||||
{
|
{
|
||||||
int t;
|
int t;
|
||||||
|
|
||||||
unary();
|
unary();
|
||||||
if (tok == '=' |
|
if (tok == '=' ||
|
||||||
(tok >= TOK_A_MOD & tok <= TOK_A_DIV) |
|
(tok >= TOK_A_MOD && tok <= TOK_A_DIV) ||
|
||||||
tok == TOK_A_XOR | tok == TOK_A_OR |
|
tok == TOK_A_XOR || tok == TOK_A_OR ||
|
||||||
tok == TOK_A_SHL | tok == TOK_A_SAR) {
|
tok == TOK_A_SHL || tok == TOK_A_SAR) {
|
||||||
test_lvalue();
|
test_lvalue();
|
||||||
vpush();
|
vpush();
|
||||||
t = tok;
|
t = tok;
|
||||||
|
|
Loading…
Reference in a new issue