win64: va_arg with structures
This commit is contained in:
parent
aa80e5b1ff
commit
8d107d9ffd
3 changed files with 51 additions and 41 deletions
16
tcc.h
16
tcc.h
|
@ -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 */
|
||||||
|
|
4
tccgen.c
4
tccgen.c
|
@ -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
|
||||||
|
|
72
x86_64-gen.c
72
x86_64-gen.c
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue