aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard>2001-12-02 16:25:49 +0000
committerbellard <bellard>2001-12-02 16:25:49 +0000
commitcb1c8c892ca6b558dc4213631eee399585de284a (patch)
tree25706038c7c408e57c2d4c651d0beb129a6024f7
parentf22a32342bbd9d3e812876e9cb30ed9c2ce6043f (diff)
downloadtinycc-cb1c8c892ca6b558dc4213631eee399585de284a.tar.gz
tinycc-cb1c8c892ca6b558dc4213631eee399585de284a.tar.bz2
first stage for structure assign - added more generic function call code generation
-rw-r--r--tcc.c143
1 files changed, 101 insertions, 42 deletions
diff --git a/tcc.c b/tcc.c
index 3d39f7e..1a0a850 100644
--- a/tcc.c
+++ b/tcc.c
@@ -270,7 +270,7 @@ void expr();
void decl();
void decl_initializer(int t, int c, int first, int size_only);
int decl_initializer_alloc(int t, int has_init);
-int gv();
+int gv(void);
void move_reg();
void save_reg();
void macro_subst(int **tok_str, int *tok_len,
@@ -1436,6 +1436,10 @@ void vset(t, v)
/******************************************************/
/* X86 code generator */
+typedef struct GFuncContext {
+ int nb_args;
+} GFuncContext;
+
void g(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)
+{
+ c->nb_args = 0;
+}
+
+/* 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(t)
+int gjmp(int 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 r;
r = p[0] & VT_VALMASK;
if (r >= VT_CONST || (p[0] & VT_LVAL))
r = get_reg();
+ /* NOTE: get_reg can modify p[] */
load(r, p[0], p[1]);
p[0] = (p[0] & VT_TYPE) | r;
return r;
@@ -1788,7 +1825,7 @@ void vpop(int *ft, int *fc)
}
/* generate a value in a register from vt and vc */
-int gv()
+int gv(void)
{
int r;
vpush();
@@ -1997,19 +2034,50 @@ int mk_pointer(int t)
/* store value in lvalue pushed on stack */
void vstore()
{
- int ft, fc, r, t;
+ int ft, fc, r, t, size, align;
+ GFuncContext gf;
- r = gv(); /* generate value */
- vpush();
- ft = vstack_ptr[-4];
- fc = vstack_ptr[-3];
- if ((ft & VT_VALMASK) == VT_LLOCAL) {
- t = get_reg();
- load(t, VT_LOCAL | VT_LVAL, fc);
- ft = (ft & ~VT_VALMASK) | t;
+ if (vt & VT_STRUCT) {
+ /* if structure, only generate pointer */
+ /* structure assignment : generate memcpy */
+ /* XXX: optimize if small size */
+
+ gfunc_start(&gf);
+ /* type size */
+ 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 -- */
@@ -2330,8 +2398,9 @@ void indir()
void unary()
{
- int n, t, ft, fc, p, r, align;
+ int n, t, ft, fc, p, align;
Sym *s;
+ GFuncContext gf;
if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) {
vset(VT_CONST, tokc);
@@ -2498,16 +2567,10 @@ void unary()
skip(']');
} else if (tok == '(') {
/* function call */
+ vt &= ~VT_LVAL; /* no lvalue */
+ vpush(); /* push function address */
save_regs(); /* save used temporary registers */
- /* lvalue is implied */
- vt = vt & VT_LVALN;
- if ((vt & VT_VALMASK) != VT_CONST) {
- /* evaluate function address */
- r = gv();
- o(0x50 + r); /* push r */
- }
- ft = vt;
- fc = vc;
+ gfunc_start(&gf);
next();
#ifdef INVERT_FUNC_PARAMS
{
@@ -2542,13 +2605,11 @@ void unary()
/* now generate code in reverse order by reading the stack */
saved_macro_ptr = macro_ptr;
- t = 0;
while (args) {
- t += 4;
macro_ptr = (int *)args->c;
next();
expr_eq();
- gfunc_param();
+ gfunc_param(&gf);
s1 = args->prev;
free((int *)args->c);
free(args);
@@ -2559,16 +2620,17 @@ void unary()
tok = ')';
}
#else
- t = 0;
while (tok != ')') {
- t += 4;
expr_eq();
- gfunc_param();
+ gfunc_param(&gf);
if (tok == ',')
next();
}
#endif
skip(')');
+ vpop(&ft, &fc);
+ gfunc_call(&gf, ft, fc);
+#if 0
if ((ft & VT_VALMASK) == VT_CONST) {
/* forward reference */
if (ft & VT_FORWARD) {
@@ -2581,6 +2643,7 @@ void unary()
}
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 */
@@ -3041,23 +3104,19 @@ void init_putv(int t, int c, int v, int is_expr)
/* put zeros for variable based init */
void init_putz(int t, int c, int size)
{
- int memset_addr, r;
+ GFuncContext gf;
if ((t & VT_VALMASK) == VT_CONST) {
/* nothing to do because global are already set to zero */
} else {
+ gfunc_start(&gf);
vset(VT_CONST, size);
- r = gv();
- o(0x50 + r);
+ gfunc_param(&gf);
vset(VT_CONST, 0);
- r = gv();
- o(0x50 + r);
+ gfunc_param(&gf);
vset(VT_LOCAL, c);
- r = gv();
- o(0x50 + r);
- memset_addr = (int)&memset;
- oad(0xe8, memset_addr - ind - 5);
- oad(0xc481, 3 * 4);
+ gfunc_param(&gf);
+ gfunc_call(&gf, VT_CONST, (int)&memset);
}
}