From 8d107d9ffd8126d82b1c56be47431a6bcef39f08 Mon Sep 17 00:00:00 2001 From: grischka Date: Fri, 17 Dec 2010 13:15:01 +0100 Subject: [PATCH] win64: va_arg with structures --- tcc.h | 16 +++++++----- tccgen.c | 4 +++ x86_64-gen.c | 72 +++++++++++++++++++++++++++------------------------- 3 files changed, 51 insertions(+), 41 deletions(-) diff --git a/tcc.h b/tcc.h index 3e577aa..c2a69ca 100644 --- a/tcc.h +++ b/tcc.h @@ -583,14 +583,14 @@ struct TCCState { }; /* The current value can be: */ -#define VT_VALMASK 0x00ff -#define VT_CONST 0x00f0 /* constant in vc +#define VT_VALMASK 0x001f +#define VT_CONST 0x0010 /* constant in vc (must be first non register value) */ -#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ -#define VT_LOCAL 0x00f2 /* offset on stack */ -#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ -#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ -#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ +#define VT_LLOCAL 0x0011 /* lvalue, offset on stack */ +#define VT_LOCAL 0x0012 /* offset on stack */ +#define VT_CMP 0x0013 /* the value is stored in processor flags (in vc) */ +#define VT_JMP 0x0014 /* value is the consequence of jmp true (even) */ +#define VT_JMPI 0x0015 /* value is the consequence of jmp false (odd) */ #define VT_LVAL 0x0100 /* var is an lvalue */ #define VT_SYM 0x0200 /* a symbol value is added */ #define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for @@ -604,6 +604,8 @@ struct TCCState { #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) +#define VT_REF 0x0020 + /* types */ #define VT_INT 0 /* integer type */ #define VT_BYTE 1 /* signed byte type */ diff --git a/tccgen.c b/tccgen.c index fe4a070..a7f943d 100644 --- a/tccgen.c +++ b/tccgen.c @@ -608,10 +608,14 @@ static void move_reg(int r, int s) /* get address of vtop (vtop MUST BE an lvalue) */ static void gaddrof(void) { + if (vtop->r & VT_REF) + gv(RC_INT); vtop->r &= ~VT_LVAL; /* tricky: if saved lvalue, then we can go back to lvalue */ if ((vtop->r & VT_VALMASK) == VT_LLOCAL) vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; + + } #ifdef CONFIG_TCC_BCHECK diff --git a/x86_64-gen.c b/x86_64-gen.c index 247027a..4d2521d 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -592,22 +592,16 @@ void gen_offs_sp(int b, int r, int d) void gfunc_call(int nb_args) { - int size, align, r, args_size, i, d, j, bt; + int size, align, r, args_size, i, d, j, bt, struct_size; int nb_reg_args, gen_reg; - /* calculate the number of integer/float arguments */ - nb_reg_args = 0; - for(i = 0; i < nb_args; i++) { - bt = (vtop[-i].type.t & VT_BTYPE); - if (bt != VT_STRUCT && bt != VT_LDOUBLE) - nb_reg_args++; - } - + nb_reg_args = nb_args; args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE; /* for struct arguments, we need to call memcpy and the function call breaks register passing arguments we are preparing. So, we process arguments which will be passed by stack first. */ + struct_size = args_size; for(i = 0; i < nb_args; i++) { SValue *sv = &vtop[-i]; bt = (sv->type.t & VT_BTYPE); @@ -617,8 +611,8 @@ void gfunc_call(int nb_args) size = (size + 15) & ~15; /* generate structure store */ r = get_reg(RC_INT); - gen_offs_sp(0x8d, r, args_size); - args_size += size; + gen_offs_sp(0x8d, r, struct_size); + struct_size += size; /* generate memcpy call */ vset(&sv->type, r | VT_LVAL, 0); @@ -629,23 +623,43 @@ void gfunc_call(int nb_args) } else if (bt == VT_LDOUBLE) { gv(RC_ST0); - gen_offs_sp(0xdb, 0x107, args_size); - args_size += 16; + gen_offs_sp(0xdb, 0x107, struct_size); + struct_size += 16; } } - if (func_scratch < args_size) - func_scratch = args_size; - + if (func_scratch < struct_size) + func_scratch = struct_size; +#if 1 for (i = 0; i < REGN; ++i) save_reg(arg_regs[i]); - + save_reg(TREG_RAX); +#endif gen_reg = nb_reg_args; + struct_size = args_size; + for(i = 0; i < nb_args; i++) { bt = (vtop->type.t & VT_BTYPE); + if (bt == VT_STRUCT || bt == VT_LDOUBLE) { - ; /* done */ + if (bt == VT_LDOUBLE) + size = 16; + else + size = type_size(&vtop->type, &align); + /* align to stack align size */ + size = (size + 15) & ~15; + j = --gen_reg; + if (j >= REGN) { + d = TREG_RAX; + gen_offs_sp(0x8d, d, struct_size); + gen_offs_sp(0x89, d, j*8); + } else { + d = arg_regs[j]; + gen_offs_sp(0x8d, d, struct_size); + } + struct_size += size; + } else if (is_sse_float(vtop->type.t)) { gv(RC_FLOAT); /* only one float register */ j = --gen_reg; @@ -694,7 +708,7 @@ void gfunc_call(int nb_args) /* generate function prolog of type 't' */ void gfunc_prolog(CType *func_type) { - int addr, align, size, reg_param_index, bt; + int addr, reg_param_index, bt; Sym *sym; CType *type; @@ -722,13 +736,15 @@ void gfunc_prolog(CType *func_type) while ((sym = sym->next) != NULL) { type = &sym->type; bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT || bt == VT_LDOUBLE) - continue; if (reg_param_index < REGN) { /* save arguments passed by register */ gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); } - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); + if (bt == VT_STRUCT || bt == VT_LDOUBLE) { + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr); + } else { + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); + } reg_param_index++; addr += PTR_SIZE; } @@ -739,18 +755,6 @@ void gfunc_prolog(CType *func_type) reg_param_index++; addr += PTR_SIZE; } - - sym = func_type->ref; - while ((sym = sym->next) != NULL) { - type = &sym->type; - bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT || bt == VT_LDOUBLE) { - size = type_size(type, &align); - size = (size + 15) & -16; - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); - addr += size; - } - } } /* generate function epilog */