simpler function call API

tcc-xref
bellard 2003-04-16 21:16:20 +00:00
parent 0d6f8021ee
commit 214ccccea7
2 changed files with 112 additions and 186 deletions

View File

@ -73,12 +73,6 @@ int reg_classes[NB_REGS] = {
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_386_32
/* function call context */
typedef struct GFuncContext {
int args_size;
int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */
} GFuncContext;
/******************************************************/
static unsigned long func_sub_sp_offset;
@ -282,65 +276,6 @@ void store(int r, SValue *v)
}
}
/* start function call and return function call context */
void gfunc_start(GFuncContext *c, int func_call)
{
c->args_size = 0;
c->func_call = func_call;
}
/* push function parameter which is in (vtop->t, vtop->c). Stack entry
is then popped. */
void gfunc_param(GFuncContext *c)
{
int size, align, r;
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &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(RC_INT);
o(0x89); /* mov %esp, r */
o(0xe0 + r);
vset(&vtop->type, r | VT_LVAL, 0);
vswap();
vstore();
c->args_size += size;
} else if (is_float(vtop->type.t)) {
gv(RC_FLOAT); /* only one float register */
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
size = 4;
else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
size = 8;
else
size = 12;
oad(0xec81, size); /* sub $xxx, %esp */
if (size == 12)
o(0x7cdb);
else
o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
g(0x24);
g(0x00);
c->args_size += size;
} else {
/* simple type (currently always same size) */
/* XXX: implicit cast ? */
r = gv(RC_INT);
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
size = 8;
o(0x50 + vtop->r2); /* push r */
} else {
size = 4;
}
o(0x50 + r); /* push r */
c->args_size += size;
}
vtop--;
}
static void gadd_sp(int val)
{
if (val == (char)val) {
@ -375,13 +310,66 @@ static void gcall_or_jmp(int is_jmp)
}
}
/* generate function call with address in (vtop->t, vtop->c) and free function
context. Stack entry is popped */
void gfunc_call(GFuncContext *c)
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
void gfunc_call(int nb_args)
{
int size, align, r, args_size, i;
Sym *func_sym;
args_size = 0;
for(i = 0;i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &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(RC_INT);
o(0x89); /* mov %esp, r */
o(0xe0 + r);
vset(&vtop->type, r | VT_LVAL, 0);
vswap();
vstore();
args_size += size;
} else if (is_float(vtop->type.t)) {
gv(RC_FLOAT); /* only one float register */
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
size = 4;
else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
size = 8;
else
size = 12;
oad(0xec81, size); /* sub $xxx, %esp */
if (size == 12)
o(0x7cdb);
else
o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
g(0x24);
g(0x00);
args_size += size;
} else {
/* simple type (currently always same size) */
/* XXX: implicit cast ? */
r = gv(RC_INT);
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
size = 8;
o(0x50 + vtop->r2); /* push r */
} else {
size = 4;
}
o(0x50 + r); /* push r */
args_size += size;
}
vtop--;
}
save_regs(0); /* save used temporary registers */
func_sym = vtop->type.ref;
gcall_or_jmp(0);
if (c->args_size && c->func_call == FUNC_CDECL)
gadd_sp(c->args_size);
if (args_size && func_sym->r == FUNC_CDECL)
gadd_sp(args_size);
vtop--;
}

170
tcc.c
View File

@ -4589,7 +4589,9 @@ void lbuild(int t)
vpop();
}
/* rotate n first stack elements to the bottom */
/* rotate n first stack elements to the bottom
I1 ... In -> I2 ... In I1 [top is right]
*/
void vrotb(int n)
{
int i;
@ -4601,6 +4603,20 @@ void vrotb(int n)
vtop[0] = tmp;
}
/* rotate n first stack elements to the top
I1 ... In -> In I1 ... I(n-1) [top is right]
*/
void vrott(int n)
{
int i;
SValue tmp;
tmp = vtop[0];
for(i = 0;i < n - 1; i++)
vtop[-i] = vtop[-i - 1];
vtop[-n + 1] = tmp;
}
/* pop stack value */
void vpop(void)
{
@ -4665,7 +4681,6 @@ void gen_opl(int op)
{
int t, a, b, op1, c, i;
int func;
GFuncContext gf;
SValue tmp;
switch(op) {
@ -4683,11 +4698,9 @@ void gen_opl(int op)
func = TOK___umoddi3;
gen_func:
/* call generic long long function */
gfunc_start(&gf, FUNC_CDECL);
gfunc_param(&gf);
gfunc_param(&gf);
vpush_global_sym(&func_old_type, func);
gfunc_call(&gf);
vrott(3);
gfunc_call(2);
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = REG_LRET;
@ -5227,20 +5240,17 @@ void gen_op(int op)
/* generic itof for unsigned long long case */
void gen_cvt_itof1(int t)
{
GFuncContext gf;
if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
(VT_LLONG | VT_UNSIGNED)) {
gfunc_start(&gf, FUNC_CDECL);
gfunc_param(&gf);
if (t == VT_FLOAT)
vpush_global_sym(&func_old_type, TOK___ulltof);
else if (t == VT_DOUBLE)
vpush_global_sym(&func_old_type, TOK___ulltod);
else
vpush_global_sym(&func_old_type, TOK___ulltold);
gfunc_call(&gf);
vrott(2);
gfunc_call(1);
vpushi(0);
vtop->r = REG_FRET;
} else {
@ -5251,21 +5261,19 @@ void gen_cvt_itof1(int t)
/* generic ftoi for unsigned long long case */
void gen_cvt_ftoi1(int t)
{
GFuncContext gf;
int st;
if (t == (VT_LLONG | VT_UNSIGNED)) {
/* not handled natively */
gfunc_start(&gf, FUNC_CDECL);
st = vtop->type.t & VT_BTYPE;
gfunc_param(&gf);
if (st == VT_FLOAT)
vpush_global_sym(&func_old_type, TOK___fixunssfdi);
else if (st == VT_DOUBLE)
vpush_global_sym(&func_old_type, TOK___fixunsdfdi);
else
vpush_global_sym(&func_old_type, TOK___fixunsxfdi);
gfunc_call(&gf);
vrott(2);
gfunc_call(1);
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = REG_LRET;
@ -5700,7 +5708,6 @@ static void gen_assign_cast(CType *dt)
void vstore(void)
{
int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast;
GFuncContext gf;
ft = vtop[-1].type.t;
sbt = vtop->type.t & VT_BTYPE;
@ -5720,25 +5727,24 @@ void vstore(void)
/* structure assignment : generate memcpy */
/* XXX: optimize if small size */
if (!nocode_wanted) {
vdup();
gfunc_start(&gf, FUNC_CDECL);
/* type size */
size = type_size(&vtop->type, &align);
vpushi(size);
gfunc_param(&gf);
/* source */
vtop->type.t = VT_INT;
gaddrof();
gfunc_param(&gf);
/* destination */
vswap();
vtop->type.t = VT_INT;
gaddrof();
gfunc_param(&gf);
save_regs(0);
vpush_global_sym(&func_old_type, TOK_memcpy);
gfunc_call(&gf);
/* destination */
vpushv(vtop - 2);
vtop->type.t = VT_INT;
gaddrof();
/* source */
vpushv(vtop - 2);
vtop->type.t = VT_INT;
gaddrof();
/* type size */
vpushi(size);
gfunc_call(3);
vswap();
vpop();
} else {
vswap();
vpop();
@ -6436,7 +6442,7 @@ static void indir(void)
}
/* pass a parameter to a function and do type checking and casting */
void gfunc_param_typed(GFuncContext *gf, Sym *func, Sym *arg)
static void gfunc_param_typed(Sym *func, Sym *arg)
{
int func_type;
CType type;
@ -6454,11 +6460,6 @@ void gfunc_param_typed(GFuncContext *gf, Sym *func, Sym *arg)
} else {
gen_assign_cast(&arg->type);
}
if (!nocode_wanted) {
gfunc_param(gf);
} else {
vpop();
}
}
/* parse an expression of the form '(type)' or '(expr)' and return its
@ -6489,7 +6490,6 @@ static void unary(void)
int n, t, align, size, r;
CType type;
Sym *s;
GFuncContext gf;
AttributeDef ad;
/* XXX: GCC 2.95.3 does not generate a table although it should be
@ -6764,6 +6764,7 @@ static void unary(void)
} else if (tok == '(') {
SValue ret;
Sym *sa;
int nb_args;
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@ -6781,63 +6782,9 @@ static void unary(void)
}
/* get return type */
s = vtop->type.ref;
if (!nocode_wanted) {
save_regs(0); /* save used temporary registers */
gfunc_start(&gf, s->r);
}
next();
sa = s->next; /* first parameter */
#ifdef INVERT_FUNC_PARAMS
{
int parlevel;
Sym *args, *s1;
ParseState saved_parse_state;
TokenString str;
/* read each argument and store it on a stack */
args = NULL;
if (tok != ')') {
for(;;) {
tok_str_new(&str);
parlevel = 0;
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
tok != TOK_EOF) {
if (tok == '(')
parlevel++;
else if (tok == ')')
parlevel--;
tok_str_add_tok(&str);
next();
}
tok_str_add(&str, -1); /* end of file added */
tok_str_add(&str, 0);
s1 = sym_push2(&args, 0, 0, (int)str.str);
s1->next = sa; /* add reference to argument */
if (sa)
sa = sa->next;
if (tok == ')')
break;
skip(',');
}
}
/* now generate code in reverse order by reading the stack */
save_parse_state(&saved_parse_state);
while (args) {
macro_ptr = (int *)args->c;
next();
expr_eq();
if (tok != -1)
expect("',' or ')'");
gfunc_param_typed(&gf, s, args->next);
s1 = args->prev;
tok_str_free((int *)args->c);
tcc_free(args);
args = s1;
}
restore_parse_state(&saved_parse_state);
}
#endif
nb_args = 0;
/* compute first implicit argument if a structure is returned */
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
/* get some space for the returned structure */
@ -6849,10 +6796,7 @@ static void unary(void)
problems */
vseti(VT_LOCAL, loc);
ret.c = vtop->c;
if (!nocode_wanted)
gfunc_param(&gf);
else
vtop--;
nb_args++;
} else {
ret.type = s->type;
ret.r2 = VT_CONST;
@ -6866,11 +6810,11 @@ static void unary(void)
}
ret.c.i = 0;
}
#ifndef INVERT_FUNC_PARAMS
if (tok != ')') {
for(;;) {
expr_eq();
gfunc_param_typed(&gf, s, sa);
gfunc_param_typed(s, sa);
nb_args++;
if (sa)
sa = sa->next;
if (tok == ')')
@ -6878,14 +6822,14 @@ static void unary(void)
skip(',');
}
}
#endif
if (sa)
error("too few arguments to function");
skip(')');
if (!nocode_wanted)
gfunc_call(&gf);
else
vtop--;
if (!nocode_wanted) {
gfunc_call(nb_args);
} else {
vtop -= (nb_args + 1);
}
/* return value */
vsetc(&ret.type, ret.r, &ret.c);
vtop->r2 = ret.r2;
@ -7793,20 +7737,14 @@ static void init_putv(CType *type, Section *sec, unsigned long c,
/* put zeros for variable based init */
static void init_putz(CType *t, Section *sec, unsigned long c, int size)
{
GFuncContext gf;
if (sec) {
/* nothing to do because globals are already set to zero */
} else {
gfunc_start(&gf, FUNC_CDECL);
vpushi(size);
gfunc_param(&gf);
vpushi(0);
gfunc_param(&gf);
vseti(VT_LOCAL, c);
gfunc_param(&gf);
vpush_global_sym(&func_old_type, TOK_memset);
gfunc_call(&gf);
vseti(VT_LOCAL, c);
vpushi(0);
vpushi(size);
gfunc_call(3);
}
}