added structure assignment (for = and function calls) - added cast handling for short/char (still not complete)

tcc-xref
bellard 2001-12-02 21:24:43 +00:00
parent cb1c8c892c
commit ebdec645a8
1 changed files with 161 additions and 46 deletions

207
tcc.c
View File

@ -40,8 +40,13 @@
/* number of available temporary registers */ /* number of available temporary registers */
#define NB_REGS 3 #define NB_REGS 3
/* return register for functions */
#define FUNC_RET_REG 0
/* defined if function parameters must be evaluated in reverse order */ /* defined if function parameters must be evaluated in reverse order */
#define INVERT_FUNC_PARAMS #define INVERT_FUNC_PARAMS
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
//#define FUNC_STRUCT_PARAM_AS_PTR
/* token symbol management */ /* token symbol management */
typedef struct TokenSym { typedef struct TokenSym {
@ -99,6 +104,8 @@ int tok, tok1, tokc, rsym, anon_sym,
prog, ind, loc, glo, vt, vc, const_wanted, line_num; prog, ind, loc, glo, vt, vc, const_wanted, line_num;
int global_expr; /* true if compound literals must be allocated int global_expr; /* true if compound literals must be allocated
globally (used during initializers parsing */ globally (used during initializers parsing */
int func_vt, func_vc; /* current function return type (used by
return instruction) */
int tok_ident; int tok_ident;
TokenSym **table_ident; TokenSym **table_ident;
TokenSym *hash_ident[521]; TokenSym *hash_ident[521];
@ -273,9 +280,12 @@ int decl_initializer_alloc(int t, int has_init);
int gv(void); int gv(void);
void move_reg(); void move_reg();
void save_reg(); void save_reg();
void vpush(void);
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 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);
int pointed_size(int t); int pointed_size(int t);
@ -1437,7 +1447,7 @@ void vset(t, v)
/* X86 code generator */ /* X86 code generator */
typedef struct GFuncContext { typedef struct GFuncContext {
int nb_args; int args_size;
} GFuncContext; } GFuncContext;
void g(c) void g(c)
@ -1562,14 +1572,39 @@ void store(r, ft, fc)
/* start function call and return function call context */ /* start function call and return function call context */
void gfunc_start(GFuncContext *c) void gfunc_start(GFuncContext *c)
{ {
c->nb_args = 0; c->args_size = 0;
} }
/* push function parameter which is in (vt, vc) */ /* push function parameter which is in (vt, vc) */
void gfunc_param(GFuncContext *c) void gfunc_param(GFuncContext *c)
{ {
o(0x50 + gv()); /* push r */ int size, align, ft, fc, r;
c->nb_args++;
if ((vt & (VT_STRUCT | VT_LVAL)) == (VT_STRUCT | VT_LVAL)) {
size = type_size(vt, &align);
/* align to stack align size */
size = (size + 3) & ~3;
/* allocate the necessary size on stack */
oad(0xec81, size); /* sub $xxx, %esp */
/* generate structure store */
r = get_reg();
o(0x89); /* mov %esp, r */
o(0xe0 + r);
ft = vt;
fc = vc;
vset(VT_INT | r, 0);
vpush();
vt = ft;
vc = fc;
vstore();
c->args_size += size;
} else {
/* simple type (currently always same size) */
/* XXX: implicit cast ? */
r = gv();
o(0x50 + r); /* push r */
c->args_size += 4;
}
} }
/* generate function call with address in (ft, fc) and free function */ /* generate function call with address in (ft, fc) and free function */
@ -1587,11 +1622,11 @@ void gfunc_call(GFuncContext *c, int ft, int fc)
oad(0x95ff, fc); /* call *xxx(%ebp) */ oad(0x95ff, fc); /* call *xxx(%ebp) */
} else { } else {
/* not actually used */ /* not actually used */
o(0xff); /* call *reg */ o(0xff); /* call *r */
o(0xd0 + r); o(0xd0 + r);
} }
if (c->nb_args) if (c->args_size)
oad(0xc481, c->nb_args * 4); /* addl $xxx, %esp */ oad(0xc481, c->args_size); /* add $xxx, %esp */
} }
int gjmp(int t) int gjmp(int t)
@ -1743,7 +1778,7 @@ void save_reg(r)
} }
/* find a free register. If none, save one register */ /* find a free register. If none, save one register */
int get_reg() int get_reg(void)
{ {
int r, i, *p; int r, i, *p;
@ -1807,7 +1842,7 @@ int gvp(int *p)
return r; return r;
} }
void vpush() void vpush(void)
{ {
if (vstack_ptr >= vstack + VSTACK_SIZE) if (vstack_ptr >= vstack + VSTACK_SIZE)
error("memory full"); error("memory full");
@ -1987,6 +2022,36 @@ void gen_op(int op)
} }
} }
/* cast (vt, vc) to 't' type */
void gen_cast(int t)
{
int r, bits;
r = vt & VT_VALMASK;
if (!(t & VT_LVAL)) {
/* if not lvalue, then we convert now */
if ((t & VT_TYPE & ~VT_UNSIGNED) == VT_BYTE)
bits = 8;
else if ((t & VT_TYPE & ~VT_UNSIGNED) == VT_SHORT)
bits = 16;
else
goto the_end;
vpush();
if (t & VT_UNSIGNED) {
vset(VT_CONST, (1 << bits) - 1);
gen_op('&');
} else {
bits = 32 - bits;
vset(VT_CONST, bits);
gen_op(TOK_SHL);
vpush();
vset(VT_CONST, bits);
gen_op(TOK_SAR);
}
}
the_end:
vt = (vt & VT_TYPEN) | t;
}
/* return type size. Put alignment at 'a' */ /* return type size. Put alignment at 'a' */
int type_size(int t, int *a) int type_size(int t, int *a)
{ {
@ -2032,7 +2097,7 @@ int mk_pointer(int t)
} }
/* store value in lvalue pushed on stack */ /* store value in lvalue pushed on stack */
void vstore() void vstore(void)
{ {
int ft, fc, r, t, size, align; int ft, fc, r, t, size, align;
GFuncContext gf; GFuncContext gf;
@ -2240,15 +2305,15 @@ int ist(void)
int post_type(t) int post_type(t)
{ {
int p, n, pt, l, a; int p, n, pt, l;
Sym *last, *s; Sym **plast, *s, *first;
if (tok == '(') { if (tok == '(') {
/* function declaration */ /* function declaration */
next(); next();
a = 4;
l = 0; l = 0;
last = NULL; first = NULL;
plast = &first;
while (tok != ')') { while (tok != ')') {
/* read param name and compute offset */ /* read param name and compute offset */
if (l != FUNC_OLD) { if (l != FUNC_OLD) {
@ -2267,16 +2332,14 @@ int post_type(t)
} else { } else {
old_proto: old_proto:
n = tok; n = tok;
pt = 0; /* int type */ pt = VT_INT;
next(); next();
} }
/* array must be transformed to pointer according to ANSI C */ /* array must be transformed to pointer according to ANSI C */
pt &= ~VT_ARRAY; pt &= ~VT_ARRAY;
/* XXX: size will be different someday */ s = sym_push(n | SYM_FIELD, pt, 0);
a = a + 4; *plast = s;
s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a); plast = &s->next;
s->next = last;
last = s;
if (tok == ',') { if (tok == ',') {
next(); next();
if (l == FUNC_NEW && tok == TOK_DOTS) { if (l == FUNC_NEW && tok == TOK_DOTS) {
@ -2291,7 +2354,7 @@ int post_type(t)
/* we push a anonymous symbol which will contain the function prototype */ /* we push a anonymous symbol which will contain the function prototype */
p = anon_sym++; p = anon_sym++;
s = sym_push(p, t, l); s = sym_push(p, t, l);
s->next = last; s->next = first;
t = VT_FUNC | (p << VT_STRUCT_SHIFT); t = VT_FUNC | (p << VT_STRUCT_SHIFT);
} else if (tok == '[') { } else if (tok == '[') {
/* array definition */ /* array definition */
@ -2398,7 +2461,7 @@ void indir()
void unary() void unary()
{ {
int n, t, ft, fc, p, align; int n, t, ft, fc, p, align, size;
Sym *s; Sym *s;
GFuncContext gf; GFuncContext gf;
@ -2449,7 +2512,7 @@ void unary()
vset(ft, fc); vset(ft, fc);
} else { } else {
unary(); unary();
vt = (vt & VT_TYPEN) | ft; gen_cast(ft);
} }
} else { } else {
expr(); expr();
@ -2566,7 +2629,14 @@ void unary()
indir(); indir();
skip(']'); skip(']');
} else if (tok == '(') { } else if (tok == '(') {
int rett, retc;
/* function call */ /* function call */
if (!(vt & VT_FUNC))
expect("function type");
/* get return type */
s = sym_find((unsigned)vt >> VT_STRUCT_SHIFT);
vt &= ~VT_LVAL; /* no lvalue */ vt &= ~VT_LVAL; /* no lvalue */
vpush(); /* push function address */ vpush(); /* push function address */
save_regs(); /* save used temporary registers */ save_regs(); /* save used temporary registers */
@ -2619,7 +2689,23 @@ void unary()
/* restore token */ /* restore token */
tok = ')'; tok = ')';
} }
#else #endif
/* compute first implicit argument if a structure is returned */
if (s->t & VT_STRUCT) {
/* get some space for the returned structure */
size = type_size(s->t, &align);
loc = (loc - size) & -align;
rett = s->t | VT_LOCAL | VT_LVAL;
/* pass it as 'int' to avoid structure arg passing
problems */
vset(VT_INT | VT_LOCAL, loc);
retc = vc;
gfunc_param(&gf);
} else {
rett = s->t | FUNC_RET_REG; /* return in register */
retc = 0;
}
#ifndef INVERT_FUNC_PARAMS
while (tok != ')') { while (tok != ')') {
expr_eq(); expr_eq();
gfunc_param(&gf); gfunc_param(&gf);
@ -2630,23 +2716,9 @@ void unary()
skip(')'); skip(')');
vpop(&ft, &fc); vpop(&ft, &fc);
gfunc_call(&gf, ft, fc); gfunc_call(&gf, ft, fc);
#if 0 /* return value */
if ((ft & VT_VALMASK) == VT_CONST) { vt = rett;
/* forward reference */ vc = retc;
if (ft & VT_FORWARD) {
*(int *)fc = psym(0xe8, *(int *)fc);
} else
oad(0xe8, fc - ind - 5);
} else {
oad(0x2494ff, t); /* call *xxx(%esp) */
t = t + 4;
}
if (t)
oad(0xc481, t);
#endif
/* get return type */
s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
vt = s->t | 0; /* return register is eax */
} else { } else {
break; break;
} }
@ -2855,8 +2927,21 @@ 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 returning structure, must copy it to implicit
first pointer arg location */
vset(mk_pointer(func_vt) | VT_LOCAL | VT_LVAL, func_vc);
indir();
vpush();
}
expr(); expr();
move_reg(0, gv()); if (func_vt & VT_STRUCT) {
/* copy structure value to pointer */
vstore();
} else {
/* move return value to standard return register */
move_reg(FUNC_RET_REG, gv());
}
} }
skip(';'); skip(';');
rsym = gjmp(rsym); /* jmp */ rsym = gjmp(rsym); /* jmp */
@ -3345,7 +3430,7 @@ int decl_initializer_alloc(int t, int has_init)
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */ /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
void decl(l) void decl(l)
{ {
int *a, t, b, v, u, n, addr, has_init; int *a, t, b, v, u, n, addr, has_init, size, align;
Sym *sym; Sym *sym;
while (1) { while (1) {
@ -3381,8 +3466,37 @@ void decl(l)
sym_push1(&local_stack, 0, 0, 0); sym_push1(&local_stack, 0, 0, 0);
/* define parameters */ /* define parameters */
sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
while (sym = sym->next) /* XXX: the following is x86 dependant -> move it to
sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c); x86 code gen */
addr = 8;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->t;
if (func_vt & VT_STRUCT) {
func_vc = addr;
addr += 4;
}
while (sym = sym->next) {
u = sym->t;
sym_push(sym->v & ~SYM_FIELD,
u | VT_LOCAL | VT_LVAL,
addr);
if (u & VT_STRUCT) {
#ifdef FUNC_STRUCT_PARAM_AS_PTR
/* structs are passed as pointer */
size = 4;
#else
/* structs are directly put on stack (x86
like) */
size = type_size(u, &align);
size = (size + 3) & ~3;
#endif
} else {
/* XXX: size will be different someday */
size = 4;
}
addr += size;
}
loc = 0; loc = 0;
o(0xe58955); /* push %ebp, mov %esp, %ebp */ o(0xe58955); /* push %ebp, mov %esp, %ebp */
a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */ a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
@ -3394,7 +3508,8 @@ void decl(l)
save local variables */ save local variables */
sym_pop(&label_stack, 0); /* reset label stack */ sym_pop(&label_stack, 0); /* reset label stack */
sym_pop(&local_stack, 0); /* reset local stack */ sym_pop(&local_stack, 0); /* reset local stack */
funcname = ""; funcname = ""; /* for safety */
func_vt = VT_VOID; /* for safety */
break; break;
} else { } else {
if (b & VT_TYPEDEF) { if (b & VT_TYPEDEF) {