fix-mixed-struct (patch by Pip Cet)
Jsut for testing. It works for me (don't break anything)
Small fixes for x86_64-gen.c in "tccpp: fix issues, add tests"
are dropped in flavor of this patch.
Pip Cet:
Okay, here's a first patch that fixes the problem (but I've found
another bug, yet unfixed, in the process), though it's not
particularly pretty code (I tried hard to keep the changes to the
minimum necessary). If we decide to actually get rid of VT_QLONG and
VT_QFLOAT (please, can we?), there are some further simplifications in
tccgen.c that might offset some of the cost of this patch.
The idea is that an integer is no longer enough to describe how an
argument is stored in registers. There are a number of possibilities
(none, integer register, two integer registers, float register, two
float registers, integer register plus float register, float register
plus integer register), and instead of enumerating them I've
introduced a RegArgs type that stores the offsets for each of our
registers (for the other architectures, it's simply an int specifying
the number of registers). If someone strongly prefers an enum, we
could do that instead, but I believe this is a place where keeping
things general is worth it, because this way it should be doable to
add SSE or AVX support.
There is one line in the patch that looks suspicious:
} else {
addr = (addr + align - 1) & -align;
param_addr = addr;
addr += size;
- sse_param_index += reg_count;
}
break;
However, this actually fixes one half of a bug we have when calling a
function with eight double arguments "interrupted" by a two-double
structure after the seventh double argument:
f(double,double,double,double,double,double,double,struct { double
x,y; },double);
In this case, the last argument should be passed in %xmm7. This patch
fixes the problem in gfunc_prolog, but not the corresponding problem
in gfunc_call, which I'll try tackling next.
This commit is contained in:
86
tccgen.c
86
tccgen.c
@ -525,7 +525,7 @@ ST_FUNC void vpushv(SValue *v)
|
||||
*vtop = *v;
|
||||
}
|
||||
|
||||
static void vdup(void)
|
||||
ST_FUNC void vdup(void)
|
||||
{
|
||||
vpushv(vtop);
|
||||
}
|
||||
@ -4200,6 +4200,7 @@ ST_FUNC void unary(void)
|
||||
SValue ret;
|
||||
Sym *sa;
|
||||
int nb_args, ret_nregs, ret_align, regsize, variadic;
|
||||
RegArgs args;
|
||||
|
||||
/* function call */
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||
@ -4224,8 +4225,10 @@ ST_FUNC void unary(void)
|
||||
/* compute first implicit argument if a structure is returned */
|
||||
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
variadic = (s->c == FUNC_ELLIPSIS);
|
||||
ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
|
||||
&ret_align, ®size);
|
||||
gfunc_sret(&s->type, variadic, &ret.type,
|
||||
&ret_align, ®size, &args);
|
||||
ret_nregs = regargs_nregs(&args);
|
||||
|
||||
if (!ret_nregs) {
|
||||
/* get some space for the returned structure */
|
||||
size = type_size(&s->type, &align);
|
||||
@ -4303,6 +4306,10 @@ ST_FUNC void unary(void)
|
||||
/* handle packed struct return */
|
||||
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
|
||||
int addr, offset;
|
||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
|
||||
int i;
|
||||
#endif
|
||||
|
||||
|
||||
size = type_size(&s->type, &align);
|
||||
/* We're writing whole regs often, make sure there's enough
|
||||
@ -4311,6 +4318,34 @@ ST_FUNC void unary(void)
|
||||
align = regsize;
|
||||
loc = (loc - size) & -align;
|
||||
addr = loc;
|
||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
|
||||
for (i=0; i<REG_ARGS_MAX; i++) {
|
||||
offset = args.ireg[i];
|
||||
|
||||
if (offset == -1)
|
||||
break;
|
||||
|
||||
ret.type.t = VT_LLONG;
|
||||
vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
|
||||
vsetc(&ret.type, i ? REG_LRET : REG_IRET, &ret.c);
|
||||
vstore();
|
||||
vtop--;
|
||||
vtop--;
|
||||
}
|
||||
for (i=0; i<REG_ARGS_MAX; i++) {
|
||||
offset = args.freg[i];
|
||||
|
||||
if (offset == -1)
|
||||
break;
|
||||
|
||||
ret.type.t = VT_DOUBLE;
|
||||
vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
|
||||
vsetc(&ret.type, i ? REG_QRET : REG_FRET, &ret.c);
|
||||
vstore();
|
||||
vtop--;
|
||||
vtop--;
|
||||
}
|
||||
#else
|
||||
offset = 0;
|
||||
for (;;) {
|
||||
vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
|
||||
@ -4321,6 +4356,7 @@ ST_FUNC void unary(void)
|
||||
break;
|
||||
offset += regsize;
|
||||
}
|
||||
#endif
|
||||
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
||||
}
|
||||
} else {
|
||||
@ -4891,8 +4927,11 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
CType type, ret_type;
|
||||
int ret_align, ret_nregs, regsize;
|
||||
ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
|
||||
&ret_align, ®size);
|
||||
RegArgs args;
|
||||
|
||||
gfunc_sret(&func_vt, func_var, &ret_type,
|
||||
&ret_align, ®size, &args);
|
||||
ret_nregs = regargs_nregs(&args);
|
||||
if (0 == ret_nregs) {
|
||||
/* if returning structure, must copy it to implicit
|
||||
first pointer arg location */
|
||||
@ -4906,6 +4945,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
} else {
|
||||
/* returning structure packed into registers */
|
||||
int r, size, addr, align;
|
||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
|
||||
int i;
|
||||
#endif
|
||||
size = type_size(&func_vt,&align);
|
||||
if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
|
||||
&& (align & (ret_align-1))) {
|
||||
@ -4919,6 +4961,39 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
|
||||
}
|
||||
vtop->type = ret_type;
|
||||
#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
|
||||
for (i=0; i<REG_ARGS_MAX; i++) {
|
||||
int off = args.ireg[i];
|
||||
|
||||
if (off == -1)
|
||||
break;
|
||||
|
||||
r = i ? RC_LRET : RC_IRET;
|
||||
|
||||
vdup();
|
||||
vtop->c.i += off;
|
||||
vtop->type.t = VT_LLONG;
|
||||
gv(r);
|
||||
vpop();
|
||||
}
|
||||
for (i=0; i<REG_ARGS_MAX; i++) {
|
||||
int off = args.freg[i];
|
||||
|
||||
if (off == -1)
|
||||
break;
|
||||
|
||||
/* We assume that when a structure is returned in multiple
|
||||
registers, their classes are consecutive values of the
|
||||
suite s(n) = 2^n */
|
||||
r = rc_fret(ret_type.t) << i;
|
||||
|
||||
vdup();
|
||||
vtop->c.i += off;
|
||||
vtop->type.t = VT_DOUBLE;
|
||||
gv(r);
|
||||
vpop();
|
||||
}
|
||||
#else
|
||||
if (is_float(ret_type.t))
|
||||
r = rc_fret(ret_type.t);
|
||||
else
|
||||
@ -4935,6 +5010,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
vtop->c.i += regsize;
|
||||
vtop->r = VT_LOCAL | VT_LVAL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else if (is_float(func_vt.t)) {
|
||||
gv(rc_fret(func_vt.t));
|
||||
|
||||
Reference in New Issue
Block a user