first stage for structure assign - added more generic function call code generation

This commit is contained in:
bellard 2001-12-02 16:25:49 +00:00
parent f22a32342b
commit cb1c8c892c

145
tcc.c
View File

@ -270,7 +270,7 @@ void expr();
void decl(); void decl();
void decl_initializer(int t, int c, int first, int size_only); void decl_initializer(int t, int c, int first, int size_only);
int decl_initializer_alloc(int t, int has_init); int decl_initializer_alloc(int t, int has_init);
int gv(); int gv(void);
void move_reg(); void move_reg();
void save_reg(); void save_reg();
void macro_subst(int **tok_str, int *tok_len, void macro_subst(int **tok_str, int *tok_len,
@ -1436,6 +1436,10 @@ void vset(t, v)
/******************************************************/ /******************************************************/
/* X86 code generator */ /* X86 code generator */
typedef struct GFuncContext {
int nb_args;
} GFuncContext;
void g(c) void g(c)
{ {
*(char *)ind++ = c; *(char *)ind++ = c;
@ -1555,12 +1559,42 @@ void store(r, ft, fc)
} }
} }
void gfunc_param(void) /* start function call and return function call context */
void gfunc_start(GFuncContext *c)
{ {
o(0x50 + gv()); /* push r */ c->nb_args = 0;
} }
int gjmp(t) /* push function parameter which is in (vt, vc) */
void gfunc_param(GFuncContext *c)
{
o(0x50 + gv()); /* push r */
c->nb_args++;
}
/* generate function call with address in (ft, fc) and free function */
void gfunc_call(GFuncContext *c, int ft, int fc)
{
int r;
r = ft & VT_VALMASK;
if (r == VT_CONST) {
/* forward reference */
if (ft & VT_FORWARD) {
*(int *)fc = psym(0xe8, *(int *)fc);
} else
oad(0xe8, fc - ind - 5);
} else if (r == VT_LOCAL) {
oad(0x95ff, fc); /* call *xxx(%ebp) */
} else {
/* not actually used */
o(0xff); /* call *reg */
o(0xd0 + r);
}
if (c->nb_args)
oad(0xc481, c->nb_args * 4); /* addl $xxx, %esp */
}
int gjmp(int t)
{ {
return psym(0xe9, t); return psym(0xe9, t);
} }
@ -1758,13 +1792,16 @@ void move_reg(r, s)
} }
} }
/* convert a stack entry in register */ /* convert a stack entry in register. lvalues are converted as
values. Cannot be used if cannot be converted to register value
(such as structures). */
int gvp(int *p) int gvp(int *p)
{ {
int r; int r;
r = p[0] & VT_VALMASK; r = p[0] & VT_VALMASK;
if (r >= VT_CONST || (p[0] & VT_LVAL)) if (r >= VT_CONST || (p[0] & VT_LVAL))
r = get_reg(); r = get_reg();
/* NOTE: get_reg can modify p[] */
load(r, p[0], p[1]); load(r, p[0], p[1]);
p[0] = (p[0] & VT_TYPE) | r; p[0] = (p[0] & VT_TYPE) | r;
return r; return r;
@ -1788,7 +1825,7 @@ void vpop(int *ft, int *fc)
} }
/* generate a value in a register from vt and vc */ /* generate a value in a register from vt and vc */
int gv() int gv(void)
{ {
int r; int r;
vpush(); vpush();
@ -1997,19 +2034,50 @@ int mk_pointer(int t)
/* store value in lvalue pushed on stack */ /* store value in lvalue pushed on stack */
void vstore() void vstore()
{ {
int ft, fc, r, t; int ft, fc, r, t, size, align;
GFuncContext gf;
r = gv(); /* generate value */ if (vt & VT_STRUCT) {
vpush(); /* if structure, only generate pointer */
ft = vstack_ptr[-4]; /* structure assignment : generate memcpy */
fc = vstack_ptr[-3]; /* XXX: optimize if small size */
if ((ft & VT_VALMASK) == VT_LLOCAL) {
t = get_reg(); gfunc_start(&gf);
load(t, VT_LOCAL | VT_LVAL, fc); /* type size */
ft = (ft & ~VT_VALMASK) | t; ft = vt;
fc = vc;
size = type_size(vt, &align);
vset(VT_CONST, size);
gfunc_param(&gf);
/* source */
vt = ft & ~VT_LVAL;
vc = fc;
gfunc_param(&gf);
/* destination */
vpop(&vt, &vc);
vt &= ~VT_LVAL;
gfunc_param(&gf);
save_regs();
gfunc_call(&gf, VT_CONST, (int)&memcpy);
/* generate again current type */
vt = ft;
vc = fc;
} else {
r = gv(); /* generate value */
vpush();
ft = vstack_ptr[-4];
fc = vstack_ptr[-3];
/* if lvalue was saved on stack, must read it */
if ((ft & VT_VALMASK) == VT_LLOCAL) {
t = get_reg();
load(t, VT_LOCAL | VT_LVAL, fc);
ft = (ft & ~VT_VALMASK) | t;
}
store(r, ft, fc);
vstack_ptr -= 4;
} }
store(r, ft, fc);
vstack_ptr -= 4;
} }
/* post defines POST/PRE add. c is the token ++ or -- */ /* post defines POST/PRE add. c is the token ++ or -- */
@ -2330,8 +2398,9 @@ void indir()
void unary() void unary()
{ {
int n, t, ft, fc, p, r, align; int n, t, ft, fc, p, align;
Sym *s; Sym *s;
GFuncContext gf;
if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) { if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) {
vset(VT_CONST, tokc); vset(VT_CONST, tokc);
@ -2498,16 +2567,10 @@ void unary()
skip(']'); skip(']');
} else if (tok == '(') { } else if (tok == '(') {
/* function call */ /* function call */
vt &= ~VT_LVAL; /* no lvalue */
vpush(); /* push function address */
save_regs(); /* save used temporary registers */ save_regs(); /* save used temporary registers */
/* lvalue is implied */ gfunc_start(&gf);
vt = vt & VT_LVALN;
if ((vt & VT_VALMASK) != VT_CONST) {
/* evaluate function address */
r = gv();
o(0x50 + r); /* push r */
}
ft = vt;
fc = vc;
next(); next();
#ifdef INVERT_FUNC_PARAMS #ifdef INVERT_FUNC_PARAMS
{ {
@ -2542,13 +2605,11 @@ void unary()
/* now generate code in reverse order by reading the stack */ /* now generate code in reverse order by reading the stack */
saved_macro_ptr = macro_ptr; saved_macro_ptr = macro_ptr;
t = 0;
while (args) { while (args) {
t += 4;
macro_ptr = (int *)args->c; macro_ptr = (int *)args->c;
next(); next();
expr_eq(); expr_eq();
gfunc_param(); gfunc_param(&gf);
s1 = args->prev; s1 = args->prev;
free((int *)args->c); free((int *)args->c);
free(args); free(args);
@ -2559,16 +2620,17 @@ void unary()
tok = ')'; tok = ')';
} }
#else #else
t = 0;
while (tok != ')') { while (tok != ')') {
t += 4;
expr_eq(); expr_eq();
gfunc_param(); gfunc_param(&gf);
if (tok == ',') if (tok == ',')
next(); next();
} }
#endif #endif
skip(')'); skip(')');
vpop(&ft, &fc);
gfunc_call(&gf, ft, fc);
#if 0
if ((ft & VT_VALMASK) == VT_CONST) { if ((ft & VT_VALMASK) == VT_CONST) {
/* forward reference */ /* forward reference */
if (ft & VT_FORWARD) { if (ft & VT_FORWARD) {
@ -2581,6 +2643,7 @@ void unary()
} }
if (t) if (t)
oad(0xc481, t); oad(0xc481, t);
#endif
/* get return type */ /* get return type */
s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT); s = sym_find((unsigned)ft >> VT_STRUCT_SHIFT);
vt = s->t | 0; /* return register is eax */ vt = s->t | 0; /* return register is eax */
@ -3041,23 +3104,19 @@ void init_putv(int t, int c, int v, int is_expr)
/* put zeros for variable based init */ /* put zeros for variable based init */
void init_putz(int t, int c, int size) void init_putz(int t, int c, int size)
{ {
int memset_addr, r; GFuncContext gf;
if ((t & VT_VALMASK) == VT_CONST) { if ((t & VT_VALMASK) == VT_CONST) {
/* nothing to do because global are already set to zero */ /* nothing to do because global are already set to zero */
} else { } else {
gfunc_start(&gf);
vset(VT_CONST, size); vset(VT_CONST, size);
r = gv(); gfunc_param(&gf);
o(0x50 + r);
vset(VT_CONST, 0); vset(VT_CONST, 0);
r = gv(); gfunc_param(&gf);
o(0x50 + r);
vset(VT_LOCAL, c); vset(VT_LOCAL, c);
r = gv(); gfunc_param(&gf);
o(0x50 + r); gfunc_call(&gf, VT_CONST, (int)&memset);
memset_addr = (int)&memset;
oad(0xe8, memset_addr - ind - 5);
oad(0xc481, 3 * 4);
} }
} }