From ebdec645a8881006812e31eae39d569397e9304b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 2 Dec 2001 21:24:43 +0000 Subject: [PATCH] added structure assignment (for = and function calls) - added cast handling for short/char (still not complete) --- tcc.c | 207 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 161 insertions(+), 46 deletions(-) diff --git a/tcc.c b/tcc.c index 1a0a850..f2b6b76 100644 --- a/tcc.c +++ b/tcc.c @@ -40,8 +40,13 @@ /* number of available temporary registers */ #define NB_REGS 3 +/* return register for functions */ +#define FUNC_RET_REG 0 /* defined if function parameters must be evaluated in reverse order */ #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 */ typedef struct TokenSym { @@ -99,6 +104,8 @@ int tok, tok1, tokc, rsym, anon_sym, prog, ind, loc, glo, vt, vc, const_wanted, line_num; int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ +int func_vt, func_vc; /* current function return type (used by + return instruction) */ int tok_ident; TokenSym **table_ident; TokenSym *hash_ident[521]; @@ -273,9 +280,12 @@ int decl_initializer_alloc(int t, int has_init); int gv(void); void move_reg(); void save_reg(); +void vpush(void); +int get_reg(void); void macro_subst(int **tok_str, int *tok_len, Sym **nested_list, int *macro_str); int save_reg_forced(int r); +void vstore(void); int type_size(int t, int *a); int pointed_type(int t); int pointed_size(int t); @@ -1437,7 +1447,7 @@ void vset(t, v) /* X86 code generator */ typedef struct GFuncContext { - int nb_args; + int args_size; } GFuncContext; void g(c) @@ -1562,14 +1572,39 @@ void store(r, ft, fc) /* start function call and return function call context */ void gfunc_start(GFuncContext *c) { - c->nb_args = 0; + c->args_size = 0; } /* push function parameter which is in (vt, vc) */ void gfunc_param(GFuncContext *c) { - o(0x50 + gv()); /* push r */ - c->nb_args++; + int size, align, ft, fc, r; + + 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 */ @@ -1587,11 +1622,11 @@ void gfunc_call(GFuncContext *c, int ft, int fc) oad(0x95ff, fc); /* call *xxx(%ebp) */ } else { /* not actually used */ - o(0xff); /* call *reg */ + o(0xff); /* call *r */ o(0xd0 + r); } - if (c->nb_args) - oad(0xc481, c->nb_args * 4); /* addl $xxx, %esp */ + if (c->args_size) + oad(0xc481, c->args_size); /* add $xxx, %esp */ } int gjmp(int t) @@ -1743,7 +1778,7 @@ void save_reg(r) } /* find a free register. If none, save one register */ -int get_reg() +int get_reg(void) { int r, i, *p; @@ -1807,7 +1842,7 @@ int gvp(int *p) return r; } -void vpush() +void vpush(void) { if (vstack_ptr >= vstack + VSTACK_SIZE) 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' */ int type_size(int t, int *a) { @@ -2032,7 +2097,7 @@ int mk_pointer(int t) } /* store value in lvalue pushed on stack */ -void vstore() +void vstore(void) { int ft, fc, r, t, size, align; GFuncContext gf; @@ -2240,15 +2305,15 @@ int ist(void) int post_type(t) { - int p, n, pt, l, a; - Sym *last, *s; + int p, n, pt, l; + Sym **plast, *s, *first; if (tok == '(') { /* function declaration */ next(); - a = 4; l = 0; - last = NULL; + first = NULL; + plast = &first; while (tok != ')') { /* read param name and compute offset */ if (l != FUNC_OLD) { @@ -2267,16 +2332,14 @@ int post_type(t) } else { old_proto: n = tok; - pt = 0; /* int type */ + pt = VT_INT; next(); } /* array must be transformed to pointer according to ANSI C */ pt &= ~VT_ARRAY; - /* XXX: size will be different someday */ - a = a + 4; - s = sym_push(n | SYM_FIELD, VT_LOCAL | VT_LVAL | pt, a); - s->next = last; - last = s; + s = sym_push(n | SYM_FIELD, pt, 0); + *plast = s; + plast = &s->next; if (tok == ',') { next(); 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 */ p = anon_sym++; s = sym_push(p, t, l); - s->next = last; + s->next = first; t = VT_FUNC | (p << VT_STRUCT_SHIFT); } else if (tok == '[') { /* array definition */ @@ -2398,7 +2461,7 @@ void indir() void unary() { - int n, t, ft, fc, p, align; + int n, t, ft, fc, p, align, size; Sym *s; GFuncContext gf; @@ -2449,7 +2512,7 @@ void unary() vset(ft, fc); } else { unary(); - vt = (vt & VT_TYPEN) | ft; + gen_cast(ft); } } else { expr(); @@ -2566,7 +2629,14 @@ void unary() indir(); skip(']'); } else if (tok == '(') { + int rett, retc; + /* 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 */ vpush(); /* push function address */ save_regs(); /* save used temporary registers */ @@ -2619,7 +2689,23 @@ void unary() /* restore token */ 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 != ')') { expr_eq(); gfunc_param(&gf); @@ -2630,23 +2716,9 @@ void unary() skip(')'); vpop(&ft, &fc); gfunc_call(&gf, ft, fc); -#if 0 - if ((ft & VT_VALMASK) == VT_CONST) { - /* forward reference */ - 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 */ + /* return value */ + vt = rett; + vc = retc; } else { 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) { next(); 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(); - 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(';'); 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 */ 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; while (1) { @@ -3381,8 +3466,37 @@ void decl(l) sym_push1(&local_stack, 0, 0, 0); /* define parameters */ sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); - while (sym = sym->next) - sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c); + /* XXX: the following is x86 dependant -> move it to + 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; o(0xe58955); /* push %ebp, mov %esp, %ebp */ a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */ @@ -3394,7 +3508,8 @@ void decl(l) save local variables */ sym_pop(&label_stack, 0); /* reset label stack */ sym_pop(&local_stack, 0); /* reset local stack */ - funcname = ""; + funcname = ""; /* for safety */ + func_vt = VT_VOID; /* for safety */ break; } else { if (b & VT_TYPEDEF) {