win64: va_arg with structures

master
grischka 2010-12-17 13:15:01 +01:00
parent aa80e5b1ff
commit 8d107d9ffd
3 changed files with 51 additions and 41 deletions

16
tcc.h
View File

@ -583,14 +583,14 @@ struct TCCState {
}; };
/* The current value can be: */ /* The current value can be: */
#define VT_VALMASK 0x00ff #define VT_VALMASK 0x001f
#define VT_CONST 0x00f0 /* constant in vc #define VT_CONST 0x0010 /* constant in vc
(must be first non register value) */ (must be first non register value) */
#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ #define VT_LLOCAL 0x0011 /* lvalue, offset on stack */
#define VT_LOCAL 0x00f2 /* offset on stack */ #define VT_LOCAL 0x0012 /* offset on stack */
#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ #define VT_CMP 0x0013 /* the value is stored in processor flags (in vc) */
#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ #define VT_JMP 0x0014 /* value is the consequence of jmp true (even) */
#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ #define VT_JMPI 0x0015 /* value is the consequence of jmp false (odd) */
#define VT_LVAL 0x0100 /* var is an lvalue */ #define VT_LVAL 0x0100 /* var is an lvalue */
#define VT_SYM 0x0200 /* a symbol value is added */ #define VT_SYM 0x0200 /* a symbol value is added */
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for #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_UNSIGNED 0x4000 /* lvalue is unsigned */
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
#define VT_REF 0x0020
/* types */ /* types */
#define VT_INT 0 /* integer type */ #define VT_INT 0 /* integer type */
#define VT_BYTE 1 /* signed byte type */ #define VT_BYTE 1 /* signed byte type */

View File

@ -608,10 +608,14 @@ static void move_reg(int r, int s)
/* get address of vtop (vtop MUST BE an lvalue) */ /* get address of vtop (vtop MUST BE an lvalue) */
static void gaddrof(void) static void gaddrof(void)
{ {
if (vtop->r & VT_REF)
gv(RC_INT);
vtop->r &= ~VT_LVAL; vtop->r &= ~VT_LVAL;
/* tricky: if saved lvalue, then we can go back to lvalue */ /* tricky: if saved lvalue, then we can go back to lvalue */
if ((vtop->r & VT_VALMASK) == VT_LLOCAL) if ((vtop->r & VT_VALMASK) == VT_LLOCAL)
vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL;
} }
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK

View File

@ -592,22 +592,16 @@ void gen_offs_sp(int b, int r, int d)
void gfunc_call(int nb_args) 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; int nb_reg_args, gen_reg;
/* calculate the number of integer/float arguments */ nb_reg_args = nb_args;
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++;
}
args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE; args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE;
/* for struct arguments, we need to call memcpy and the function /* for struct arguments, we need to call memcpy and the function
call breaks register passing arguments we are preparing. call breaks register passing arguments we are preparing.
So, we process arguments which will be passed by stack first. */ So, we process arguments which will be passed by stack first. */
struct_size = args_size;
for(i = 0; i < nb_args; i++) { for(i = 0; i < nb_args; i++) {
SValue *sv = &vtop[-i]; SValue *sv = &vtop[-i];
bt = (sv->type.t & VT_BTYPE); bt = (sv->type.t & VT_BTYPE);
@ -617,8 +611,8 @@ void gfunc_call(int nb_args)
size = (size + 15) & ~15; size = (size + 15) & ~15;
/* generate structure store */ /* generate structure store */
r = get_reg(RC_INT); r = get_reg(RC_INT);
gen_offs_sp(0x8d, r, args_size); gen_offs_sp(0x8d, r, struct_size);
args_size += size; struct_size += size;
/* generate memcpy call */ /* generate memcpy call */
vset(&sv->type, r | VT_LVAL, 0); vset(&sv->type, r | VT_LVAL, 0);
@ -629,23 +623,43 @@ void gfunc_call(int nb_args)
} else if (bt == VT_LDOUBLE) { } else if (bt == VT_LDOUBLE) {
gv(RC_ST0); gv(RC_ST0);
gen_offs_sp(0xdb, 0x107, args_size); gen_offs_sp(0xdb, 0x107, struct_size);
args_size += 16; struct_size += 16;
} }
} }
if (func_scratch < args_size) if (func_scratch < struct_size)
func_scratch = args_size; func_scratch = struct_size;
#if 1
for (i = 0; i < REGN; ++i) for (i = 0; i < REGN; ++i)
save_reg(arg_regs[i]); save_reg(arg_regs[i]);
save_reg(TREG_RAX);
#endif
gen_reg = nb_reg_args; gen_reg = nb_reg_args;
struct_size = args_size;
for(i = 0; i < nb_args; i++) { for(i = 0; i < nb_args; i++) {
bt = (vtop->type.t & VT_BTYPE); bt = (vtop->type.t & VT_BTYPE);
if (bt == VT_STRUCT || bt == VT_LDOUBLE) { 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)) { } else if (is_sse_float(vtop->type.t)) {
gv(RC_FLOAT); /* only one float register */ gv(RC_FLOAT); /* only one float register */
j = --gen_reg; j = --gen_reg;
@ -694,7 +708,7 @@ void gfunc_call(int nb_args)
/* generate function prolog of type 't' */ /* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type) void gfunc_prolog(CType *func_type)
{ {
int addr, align, size, reg_param_index, bt; int addr, reg_param_index, bt;
Sym *sym; Sym *sym;
CType *type; CType *type;
@ -722,13 +736,15 @@ void gfunc_prolog(CType *func_type)
while ((sym = sym->next) != NULL) { while ((sym = sym->next) != NULL) {
type = &sym->type; type = &sym->type;
bt = type->t & VT_BTYPE; bt = type->t & VT_BTYPE;
if (bt == VT_STRUCT || bt == VT_LDOUBLE)
continue;
if (reg_param_index < REGN) { if (reg_param_index < REGN) {
/* save arguments passed by register */ /* save arguments passed by register */
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); 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++; reg_param_index++;
addr += PTR_SIZE; addr += PTR_SIZE;
} }
@ -739,18 +755,6 @@ void gfunc_prolog(CType *func_type)
reg_param_index++; reg_param_index++;
addr += PTR_SIZE; 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 */ /* generate function epilog */