better type storage

tcc-xref
bellard 2001-12-08 22:51:04 +00:00
parent 52ca29cd4f
commit 9b3c96c88e
1 changed files with 84 additions and 66 deletions

150
tcc.c
View File

@ -158,27 +158,28 @@ int gnu_ext = 1;
#define VT_LVALN -17 /* ~VT_LVAL */ #define VT_LVALN -17 /* ~VT_LVAL */
#define VT_FORWARD 0x0020 /* value is forward reference #define VT_FORWARD 0x0020 /* value is forward reference
(only used for functions) */ (only used for functions) */
/* storage */
#define VT_EXTERN 0x00000040 /* extern definition */
#define VT_STATIC 0x00000080 /* static variable */
#define VT_TYPEDEF 0x00000100 /* typedef definition */
/* types */ /* types */
#define VT_INT 0 #define VT_STRUCT_SHIFT 15 /* structure/enum name shift (14 bits left) */
#define VT_VOID 0x00040
#define VT_BYTE 0x00080 /* signed byte type */
#define VT_PTR 0x00100 /* pointer increment */
#define VT_UNSIGNED 0x00200 /* unsigned type */
#define VT_ARRAY 0x00400 /* array type (only used in parsing) */
#define VT_ENUM 0x00800 /* enum definition */
#define VT_FUNC 0x01000 /* function type */
#define VT_STRUCT 0x002000 /* struct/union definition */
#define VT_SHORT 0x004000 /* short type */
#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
#define VT_TYPE 0xfffc7fc0 /* type mask */ #define VT_BTYPE_SHIFT 9
#define VT_INT (0 << VT_BTYPE_SHIFT) /* integer type */
/* storage */ #define VT_BYTE (1 << VT_BTYPE_SHIFT) /* signed byte type */
#define VT_EXTERN 0x00008000 /* extern definition */ #define VT_SHORT (2 << VT_BTYPE_SHIFT) /* short type */
#define VT_STATIC 0x00010000 /* static variable */ #define VT_VOID (3 << VT_BTYPE_SHIFT) /* void type */
#define VT_TYPEDEF 0x00020000 /* typedef definition */ #define VT_PTR (4 << VT_BTYPE_SHIFT) /* pointer increment */
#define VT_ENUM (5 << VT_BTYPE_SHIFT) /* enum definition */
#define VT_FUNC (6 << VT_BTYPE_SHIFT) /* function type */
#define VT_STRUCT (7 << VT_BTYPE_SHIFT) /* struct/union definition */
#define VT_BTYPE (0xf << VT_BTYPE_SHIFT) /* mask for basic 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_TYPE 0xfffffe00 /* type mask */
/* token values */ /* token values */
@ -366,19 +367,19 @@ void *dlsym(void *handle, char *symbol)
#endif #endif
inline int isid(c) inline int isid(int c)
{ {
return (c >= 'a' && c <= 'z') || return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z') ||
c == '_'; c == '_';
} }
inline int isnum(c) inline int isnum(int c)
{ {
return c >= '0' & c <= '9'; return c >= '0' & c <= '9';
} }
void printline() void printline(void)
{ {
IncludeFile *f; IncludeFile *f;
for(f = include_stack; f < include_stack_ptr; f++) for(f = include_stack; f < include_stack_ptr; f++)
@ -409,14 +410,14 @@ void warning(const char *msg)
fprintf(stderr, "warning: %s\n", msg); fprintf(stderr, "warning: %s\n", msg);
} }
void skip(c) void skip(int c)
{ {
if (tok != c) if (tok != c)
error("'%c' expected", c); error("'%c' expected", c);
next(); next();
} }
void test_lvalue() void test_lvalue(void)
{ {
if (!(vt & VT_LVAL)) if (!(vt & VT_LVAL))
expect("lvalue"); expect("lvalue");
@ -1686,14 +1687,17 @@ void load(r, ft, fc)
/* WARNING: r must not be allocated on the stack */ /* WARNING: r must not be allocated on the stack */
void store(r, ft, fc) void store(r, ft, fc)
{ {
int fr, b; int fr, bt;
fr = ft & VT_VALMASK; fr = ft & VT_VALMASK;
b = (ft & VT_TYPE) == VT_BYTE; bt = ft & VT_BTYPE;
/* XXX: incorrect if reg to reg */ /* XXX: incorrect if reg to reg */
if (ft & VT_SHORT) if (bt == VT_SHORT)
o(0x66); o(0x66);
o(0x89 - b); if (bt == VT_BYTE)
o(0x88);
else
o(0x89);
if (fr == VT_CONST) { if (fr == VT_CONST) {
o(0x05 + r * 8); /* mov r,xxx */ o(0x05 + r * 8); /* mov r,xxx */
gen_addr32(fc, ft); gen_addr32(fc, ft);
@ -1717,7 +1721,7 @@ void gfunc_param(GFuncContext *c)
{ {
int size, align, ft, fc, r; int size, align, ft, fc, r;
if ((vt & (VT_STRUCT | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) { if ((vt & (VT_BTYPE | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) {
size = type_size(vt, &align); size = type_size(vt, &align);
/* align to stack align size */ /* align to stack align size */
size = (size + 3) & ~3; size = (size + 3) & ~3;
@ -2114,7 +2118,8 @@ void gen_op(int op)
t1 = vstack_ptr[-4]; t1 = vstack_ptr[-4];
t2 = vstack_ptr[-2]; t2 = vstack_ptr[-2];
if (op == '+' | op == '-') { if (op == '+' | op == '-') {
if ((t1 & VT_PTR) && (t2 & VT_PTR)) { if ((t1 & VT_BTYPE) == VT_PTR &&
(t2 & VT_BTYPE) == VT_PTR) {
if (op != '-') if (op != '-')
error("invalid type"); error("invalid type");
/* XXX: check that types are compatible */ /* XXX: check that types are compatible */
@ -2124,8 +2129,9 @@ void gen_op(int op)
vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */ vstack_ptr[-2] &= ~VT_TYPE; /* set to integer */
vset(VT_CONST, u); vset(VT_CONST, u);
gen_op(TOK_PDIV); gen_op(TOK_PDIV);
} else if ((t1 | t2) & VT_PTR) { } else if ((t1 & VT_BTYPE) == VT_PTR ||
if (t2 & VT_PTR) { (t2 & VT_BTYPE) == VT_PTR) {
if ((t2 & VT_BTYPE) == VT_PTR) {
swap(vstack_ptr - 4, vstack_ptr - 2); swap(vstack_ptr - 4, vstack_ptr - 2);
swap(vstack_ptr - 3, vstack_ptr - 1); swap(vstack_ptr - 3, vstack_ptr - 1);
swap(&t1, &t2); swap(&t1, &t2);
@ -2142,7 +2148,9 @@ void gen_op(int op)
} }
} else { } else {
/* XXX: test types and compute returned value */ /* XXX: test types and compute returned value */
if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) { if ((t1 | t2) & VT_UNSIGNED ||
(t1 & VT_BTYPE) == VT_PTR ||
(t2 & VT_BTYPE) == VT_PTR) {
if (op == TOK_SAR) if (op == TOK_SAR)
op = TOK_SHR; op = TOK_SHR;
else if (op == '/') else if (op == '/')
@ -2196,9 +2204,10 @@ void gen_cast(int t)
int type_size(int t, int *a) int type_size(int t, int *a)
{ {
Sym *s; Sym *s;
int bt;
/* int, enum or pointer */ bt = t & VT_BTYPE;
if (t & VT_STRUCT) { if (bt == VT_STRUCT) {
/* struct/union */ /* struct/union */
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 */
@ -2206,15 +2215,16 @@ int type_size(int t, int *a)
} else if (t & VT_ARRAY) { } else if (t & VT_ARRAY) {
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT)); s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
return type_size(s->t, a) * s->c; return type_size(s->t, a) * s->c;
} else if ((t & VT_PTR) || } else if (bt == VT_PTR ||
(t & VT_TYPE & ~VT_UNSIGNED) == VT_INT || bt == VT_INT ||
(t & VT_ENUM)) { bt == VT_ENUM) {
*a = 4; *a = 4;
return 4; return 4;
} else if (t & VT_SHORT) { } else if (bt == VT_SHORT) {
*a = 2; *a = 2;
return 2; return 2;
} else { } else {
/* void or function */
*a = 1; *a = 1;
return 1; return 1;
} }
@ -2242,7 +2252,7 @@ void vstore(void)
int ft, fc, r, t, size, align; int ft, fc, r, t, size, align;
GFuncContext gf; GFuncContext gf;
if (vt & VT_STRUCT) { if ((vt & VT_BTYPE) == VT_STRUCT) {
/* if structure, only generate pointer */ /* if structure, only generate pointer */
/* structure assignment : generate memcpy */ /* structure assignment : generate memcpy */
/* XXX: optimize if small size */ /* XXX: optimize if small size */
@ -2362,7 +2372,8 @@ int struct_decl(int u)
b = ist(); b = ist();
while (1) { while (1) {
t = type_decl(&v, b, TYPE_DIRECT); t = type_decl(&v, b, TYPE_DIRECT);
if (t & (VT_FUNC | VT_TYPEDEF)) if ((t & VT_BTYPE) == VT_FUNC ||
(t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN)))
error("invalid type"); error("invalid type");
/* XXX: align & correct type size */ /* XXX: align & correct type size */
v |= SYM_FIELD; v |= SYM_FIELD;
@ -2467,7 +2478,7 @@ int post_type(int t)
goto old_proto; goto old_proto;
} }
} }
if (pt & VT_VOID && tok == ')') if ((pt & VT_BTYPE) == VT_VOID && tok == ')')
break; break;
l = FUNC_NEW; l = FUNC_NEW;
pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT); pt = type_decl(&n, pt, TYPE_DIRECT | TYPE_ABSTRACT);
@ -2588,7 +2599,7 @@ void indir(void)
{ {
if (vt & VT_LVAL) if (vt & VT_LVAL)
gv(); gv();
if (!(vt & VT_PTR)) if ((vt & VT_BTYPE) != VT_PTR)
expect("pointer"); expect("pointer");
vt = pointed_type(vt); vt = pointed_type(vt);
if (!(vt & VT_ARRAY)) /* an array is never an lvalue */ if (!(vt & VT_ARRAY)) /* an array is never an lvalue */
@ -2664,7 +2675,7 @@ void unary(void)
except for unary '&' and sizeof. Since we consider that except for unary '&' and sizeof. Since we consider that
functions are not lvalues, we only have to handle it functions are not lvalues, we only have to handle it
there and in function calls. */ there and in function calls. */
if (!(vt & VT_FUNC)) if ((vt & VT_BTYPE) != VT_FUNC)
test_lvalue(); test_lvalue();
vt = mk_pointer(vt & VT_LVALN); vt = mk_pointer(vt & VT_LVALN);
} else } else
@ -2741,7 +2752,7 @@ void unary(void)
vt &= VT_LVALN; vt &= VT_LVALN;
next(); next();
/* expect pointer on structure */ /* expect pointer on structure */
if (!(vt & VT_STRUCT)) if ((vt & VT_BTYPE) != VT_STRUCT)
expect("struct or union"); expect("struct or union");
s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT); s = sym_find(((unsigned)vt >> VT_STRUCT_SHIFT) | SYM_STRUCT);
/* find field */ /* find field */
@ -2774,10 +2785,11 @@ void unary(void)
int rett, retc; int rett, retc;
/* function call */ /* function call */
if (!(vt & VT_FUNC)) { if ((vt & VT_BTYPE) != VT_FUNC) {
if ((vt & (VT_PTR | VT_ARRAY)) == VT_PTR) { /* pointer test (no array accepted) */
if ((vt & (VT_BTYPE | VT_ARRAY)) == VT_PTR) {
vt = pointed_type(vt); vt = pointed_type(vt);
if (!(vt & VT_FUNC)) if ((vt & VT_BTYPE) != VT_FUNC)
goto error_func; goto error_func;
} else { } else {
error_func: error_func:
@ -2844,7 +2856,7 @@ void unary(void)
} }
#endif #endif
/* compute first implicit argument if a structure is returned */ /* compute first implicit argument if a structure is returned */
if (s->t & VT_STRUCT) { if ((s->t & VT_BTYPE) == VT_STRUCT) {
/* get some space for the returned structure */ /* get some space for the returned structure */
size = type_size(s->t, &align); size = type_size(s->t, &align);
loc = (loc - size) & -align; loc = (loc - size) & -align;
@ -2881,14 +2893,17 @@ void unary(void)
int is_compatible_types(int t1, int t2) int is_compatible_types(int t1, int t2)
{ {
Sym *s1, *s2; Sym *s1, *s2;
int bt1, bt2;
t1 &= VT_TYPE; t1 &= VT_TYPE;
t2 &= VT_TYPE; t2 &= VT_TYPE;
if (t1 & VT_PTR) { bt1 = t1 & VT_BTYPE;
bt2 = t2 & VT_BTYPE;
if (bt1 == VT_PTR) {
t1 = pointed_type(t1); t1 = pointed_type(t1);
/* if function, then convert implictely to function pointer */ /* if function, then convert implictely to function pointer */
if (!(t2 & VT_FUNC)) { if (bt2 != VT_FUNC) {
if (!(t2 & VT_PTR)) if (bt2 != VT_PTR)
return 0; return 0;
t2 = pointed_type(t2); t2 = pointed_type(t2);
} }
@ -2898,10 +2913,10 @@ int is_compatible_types(int t1, int t2)
if (t1 == VT_VOID || t2 == VT_VOID) if (t1 == VT_VOID || t2 == VT_VOID)
return 1; return 1;
return is_compatible_types(t1, t2); return is_compatible_types(t1, t2);
} else if (t1 & VT_STRUCT) { } else if (bt1 == VT_STRUCT) {
return (t2 == t1); return (t2 == t1);
} else if (t1 & VT_FUNC) { } else if (bt1 == VT_FUNC) {
if (!(t2 & VT_FUNC)) if (bt2 != VT_FUNC)
return 0; return 0;
s1 = sym_find(((unsigned)t1 >> VT_STRUCT_SHIFT)); s1 = sym_find(((unsigned)t1 >> VT_STRUCT_SHIFT));
s2 = sym_find(((unsigned)t2 >> VT_STRUCT_SHIFT)); s2 = sym_find(((unsigned)t2 >> VT_STRUCT_SHIFT));
@ -2933,7 +2948,8 @@ int check_assign_types(int t1, int t2)
{ {
t1 &= VT_TYPE; t1 &= VT_TYPE;
t2 &= VT_TYPE; t2 &= VT_TYPE;
if ((t1 & VT_PTR) && (t2 & VT_FUNC)) { if ((t1 & VT_BTYPE) == VT_PTR &&
(t2 & VT_BTYPE) == VT_FUNC) {
return is_compatible_types(pointed_type(t1), t2); return is_compatible_types(pointed_type(t1), t2);
} else { } else {
return is_compatible_types(t1, t2); return is_compatible_types(t1, t2);
@ -3168,7 +3184,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
} else if (tok == TOK_RETURN) { } else if (tok == TOK_RETURN) {
next(); next();
if (tok != ';') { if (tok != ';') {
if (func_vt & VT_STRUCT) { if ((func_vt & VT_BTYPE) == VT_STRUCT) {
/* if returning structure, must copy it to implicit /* if returning structure, must copy it to implicit
first pointer arg location */ first pointer arg location */
vset(mk_pointer(func_vt) | VT_LOCAL | VT_LVAL, func_vc); vset(mk_pointer(func_vt) | VT_LOCAL | VT_LVAL, func_vc);
@ -3176,7 +3192,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
vpush(); vpush();
} }
expr(); expr();
if (func_vt & VT_STRUCT) { if ((func_vt & VT_BTYPE) == VT_STRUCT) {
/* copy structure value to pointer */ /* copy structure value to pointer */
vstore(); vstore();
} else { } else {
@ -3363,7 +3379,7 @@ void decl_designator(int t, int c,
l = tok; l = tok;
next(); next();
struct_field: struct_field:
if (!(t & VT_STRUCT)) if ((t & VT_BTYPE) != VT_STRUCT)
expect("struct/union type"); expect("struct/union type");
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT); s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
l |= SYM_FIELD; l |= SYM_FIELD;
@ -3419,9 +3435,9 @@ void init_putv(int t, int c, int v, int is_expr)
v = expr_const(); v = expr_const();
global_expr = saved_global_expr; global_expr = saved_global_expr;
} }
if (t & VT_BYTE) if ((t & VT_BTYPE) == VT_BYTE)
*(char *)c = v; *(char *)c = v;
else if (t & VT_SHORT) else if ((t & VT_BTYPE) == VT_SHORT)
*(short *)c = v; *(short *)c = v;
else else
*(int *)c = v; *(int *)c = v;
@ -3485,9 +3501,9 @@ void decl_initializer(int t, int c, int first, int size_only)
/* only parse strings here if correct type (otherwise: handle /* only parse strings here if correct type (otherwise: handle
them as ((w)char *) expressions */ them as ((w)char *) expressions */
if ((tok == TOK_LSTR && if ((tok == TOK_LSTR &&
(t1 & VT_TYPE & ~VT_UNSIGNED) == VT_INT) || (t1 & VT_BTYPE) == VT_INT) ||
(tok == TOK_STR && (tok == TOK_STR &&
(t1 & VT_TYPE & ~VT_UNSIGNED) == VT_BYTE)) { (t1 & VT_BTYPE) == VT_BYTE)) {
/* XXX: move multiple string parsing in parser ? */ /* XXX: move multiple string parsing in parser ? */
while (tok == TOK_STR || tok == TOK_LSTR) { while (tok == TOK_STR || tok == TOK_LSTR) {
ts = (TokenSym *)tokc; ts = (TokenSym *)tokc;
@ -3549,7 +3565,7 @@ void decl_initializer(int t, int c, int first, int size_only)
/* patch type size if needed */ /* patch type size if needed */
if (n < 0) if (n < 0)
s->c = array_length; s->c = array_length;
} else if ((t & VT_STRUCT) && tok == '{') { } else if ((t & VT_BTYPE) == VT_STRUCT && tok == '{') {
/* XXX: union needs only one init */ /* XXX: union needs only one init */
next(); next();
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT); s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
@ -3700,7 +3716,9 @@ void decl(int l)
break; break;
b = VT_INT; b = VT_INT;
} }
if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') { if (((b & VT_BTYPE) == VT_ENUM ||
(b & VT_BTYPE) == VT_STRUCT) &&
tok == ';') {
/* we accept no variable after */ /* we accept no variable after */
next(); next();
continue; continue;
@ -3731,7 +3749,7 @@ void decl(int l)
/* if the function returns a structure, then add an /* if the function returns a structure, then add an
implicit pointer parameter */ implicit pointer parameter */
func_vt = sym->t; func_vt = sym->t;
if (func_vt & VT_STRUCT) { if ((func_vt & VT_BTYPE) == VT_STRUCT) {
func_vc = addr; func_vc = addr;
addr += 4; addr += 4;
} }
@ -3740,7 +3758,7 @@ void decl(int l)
sym_push(sym->v & ~SYM_FIELD, sym_push(sym->v & ~SYM_FIELD,
u | VT_LOCAL | VT_LVAL, u | VT_LOCAL | VT_LVAL,
addr); addr);
if (u & VT_STRUCT) { if ((u & VT_BTYPE) == VT_STRUCT) {
#ifdef FUNC_STRUCT_PARAM_AS_PTR #ifdef FUNC_STRUCT_PARAM_AS_PTR
/* structs are passed as pointer */ /* structs are passed as pointer */
size = 4; size = 4;
@ -3775,7 +3793,7 @@ void decl(int l)
/* save typedefed type */ /* save typedefed type */
/* XXX: test storage specifiers ? */ /* XXX: test storage specifiers ? */
sym_push(v, t | VT_TYPEDEF, 0); sym_push(v, t | VT_TYPEDEF, 0);
} else if (t & VT_FUNC) { } else if ((t & VT_BTYPE) == VT_FUNC) {
/* external function definition */ /* external function definition */
external_sym(v, t); external_sym(v, t);
} else { } else {