mirror of
https://github.com/frida/tinycc
synced 2024-12-24 05:56:49 +03:00
riscv: Start fixing float struct passing/returnig
this fixes ret_2float_test, ret_2double_test and ret_8plus2double_test of abitest.c. The common gfunc_return actually works for these cases, so let's use that for now. The ret_mixed_test (as well as mixed2 and mixed3) are left broken, and tccgen.c:gfunc_return can't be used for that as is, so I'll leave the gfunc_return implementation in riscv64-gen.c for now, I'll have to think about this some more.
This commit is contained in:
parent
98dc4c123d
commit
98f1b83ffe
102
riscv64-gen.c
102
riscv64-gen.c
@ -147,8 +147,8 @@ ST_FUNC void load(int r, SValue *sv)
|
||||
if (fr & VT_LVAL) {
|
||||
int func3, opcode = 0x03, doload = 0;
|
||||
if (is_freg(r)) {
|
||||
assert(bt == VT_DOUBLE || bt == VT_FLOAT);
|
||||
opcode = 0x07;
|
||||
assert(bt == VT_DOUBLE || bt == VT_FLOAT);
|
||||
func3 = bt == VT_DOUBLE ? 3 : 2;
|
||||
} else {
|
||||
assert(is_ireg(r));
|
||||
@ -433,6 +433,33 @@ static void gcall_or_jmp(int docall)
|
||||
}
|
||||
}
|
||||
|
||||
static int pass_in_freg(CType *type, int regs)
|
||||
{
|
||||
int tr;
|
||||
int toplevel = !regs;
|
||||
if ((type->t & VT_BTYPE) == VT_STRUCT) {
|
||||
Sym *f;
|
||||
if (type->ref->type.t == VT_UNION)
|
||||
return toplevel ? 0 : -1;
|
||||
for (f = type->ref->next; f; f = f->next) {
|
||||
tr = pass_in_freg(&f->type, regs);
|
||||
if (tr < 0 || (regs + tr) > 2)
|
||||
return toplevel ? 0 : -1;
|
||||
regs += tr;
|
||||
}
|
||||
return regs;
|
||||
} else if (type->t & VT_ARRAY) {
|
||||
if (type->ref->c < 0 || type->ref->c > 2)
|
||||
return toplevel ? 0 : -1;
|
||||
tr = pass_in_freg(&type->ref->type, regs);
|
||||
tr *= type->ref->c;
|
||||
if (tr < 0 || (regs + tr) > 2)
|
||||
return toplevel ? 0 : -1;
|
||||
return regs + tr;
|
||||
}
|
||||
return is_float(type->t) && (type->t & VT_BTYPE) != VT_LDOUBLE;
|
||||
}
|
||||
|
||||
ST_FUNC void gfunc_call(int nb_args)
|
||||
{
|
||||
int i, align, size, aireg, afreg;
|
||||
@ -461,14 +488,15 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
nregs = 2;
|
||||
else
|
||||
nregs = 1;
|
||||
if ((sv->type.t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
if (!sa) {
|
||||
infreg = 0;
|
||||
} else
|
||||
infreg = sa && is_float(sv->type.t);
|
||||
} else {
|
||||
infreg = pass_in_freg(&sv->type, 0);
|
||||
}
|
||||
if (!infreg && !sa && align == 2*XLEN && size <= 2*XLEN)
|
||||
aireg = (aireg + 1) & ~1;
|
||||
pareg = infreg ? &afreg : &aireg;
|
||||
if ((*pareg < 8) && !force_stack) {
|
||||
if ((*pareg < 8 && (!infreg || (*pareg + nregs) <= 8)) && !force_stack) {
|
||||
info[i] = *pareg + (infreg ? 8 : 0);
|
||||
(*pareg)++;
|
||||
if (nregs == 1)
|
||||
@ -547,7 +575,38 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
vrotb(i+1);
|
||||
origtype = vtop->type;
|
||||
size = type_size(&vtop->type, &align);
|
||||
if (size > 8 && (vtop->type.t & VT_BTYPE) == VT_STRUCT)
|
||||
if (r >= 8 && (vtop->r & VT_LVAL)) {
|
||||
int infreg = pass_in_freg(&vtop->type, 0);
|
||||
int loadt = vtop->type.t & VT_BTYPE;
|
||||
if (loadt == VT_STRUCT) {
|
||||
if (infreg == 1)
|
||||
loadt = size == 4 ? VT_FLOAT : VT_DOUBLE;
|
||||
else
|
||||
loadt = size == 8 ? VT_FLOAT : VT_DOUBLE;
|
||||
}
|
||||
vtop->type.t = loadt;
|
||||
assert (infreg && infreg <= 2);
|
||||
save_reg_upstack(r, 1);
|
||||
if (infreg > 1) {
|
||||
save_reg_upstack(r + 1, 1);
|
||||
test_lvalue();
|
||||
}
|
||||
load(r, vtop);
|
||||
vset(&origtype, r, 0);
|
||||
vswap();
|
||||
if (infreg > 1) {
|
||||
assert(r + 1 < 16);
|
||||
gaddrof();
|
||||
mk_pointer(&vtop->type);
|
||||
vpushi(1);
|
||||
gen_op('+');
|
||||
indir();
|
||||
load(r + 1, vtop);
|
||||
vtop[-1].r2 = r + 1;
|
||||
}
|
||||
vtop--;
|
||||
} else {
|
||||
if (r < 8 && size > 8 && (vtop->type.t & VT_BTYPE) == VT_STRUCT)
|
||||
vtop->type.t = VT_LDOUBLE; // force loading a pair of regs
|
||||
gv(r < 8 ? RC_R(r) : RC_F(r - 8));
|
||||
vtop->type = origtype;
|
||||
@ -565,6 +624,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
vtop->r2 = 1 + vtop->r;
|
||||
}
|
||||
}
|
||||
}
|
||||
vrott(i+1);
|
||||
}
|
||||
}
|
||||
@ -621,11 +681,14 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
addr += size;
|
||||
} else {
|
||||
int regcount = 1, *pareg = &aireg;
|
||||
if (is_float(type->t) && (type->t & VT_BTYPE) != VT_LDOUBLE)
|
||||
if ((regcount = pass_in_freg(type, 0)))
|
||||
pareg = &afreg;
|
||||
else {
|
||||
regcount = 1;
|
||||
}
|
||||
if (regcount + *pareg > 8)
|
||||
goto from_stack;
|
||||
if (size > XLEN)
|
||||
if (size > XLEN && pareg == &aireg)
|
||||
regcount++;
|
||||
loc -= regcount * 8; // XXX could reserve only 'size' bytes
|
||||
param_addr = loc;
|
||||
@ -638,8 +701,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
continue;
|
||||
}
|
||||
if (pareg == &afreg) {
|
||||
assert(type->t == VT_FLOAT || type->t == VT_DOUBLE);
|
||||
ES(0x27, size == 4 ? 2 : 3, 8, 10 + *pareg, loc + i*8); // fs[wd] FAi, loc(s0)
|
||||
//assert(type->t == VT_FLOAT || type->t == VT_DOUBLE);
|
||||
ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + *pareg, loc + i*(size / regcount)); // fs[wd] FAi, loc(s0)
|
||||
} else {
|
||||
ES(0x23, 3, 8, 10 + *pareg, loc + i*8); // sd aX, loc(s0) // XXX
|
||||
}
|
||||
@ -666,11 +729,17 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
|
||||
/* generic code can only deal with structs of pow(2) sizes
|
||||
(it always deals with whole registers), so go through our own
|
||||
code. */
|
||||
int align, size = type_size(vt, &align);
|
||||
int align, size = type_size(vt, &align), infreg;
|
||||
*ret_align = 1;
|
||||
*regsize = 8;
|
||||
if (size > 16)
|
||||
return 0;
|
||||
infreg = pass_in_freg(vt, 0);
|
||||
if (infreg) {
|
||||
*regsize = size / infreg;
|
||||
ret->t = (size / infreg) == 4 ? VT_FLOAT : VT_DOUBLE;
|
||||
return infreg;
|
||||
}
|
||||
if (size > 8)
|
||||
ret->t = VT_LLONG;
|
||||
else if (size > 4)
|
||||
@ -684,7 +753,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
|
||||
return (size + 7) / 8;
|
||||
}
|
||||
|
||||
ST_FUNC void gfunc_return(CType *func_type)
|
||||
ST_FUNC void gfunc_return2(CType *func_type)
|
||||
{
|
||||
int align, size = type_size(func_type, &align), nregs;
|
||||
CType type = *func_type;
|
||||
@ -697,9 +766,12 @@ ST_FUNC void gfunc_return(CType *func_type)
|
||||
vpop();
|
||||
return;
|
||||
}
|
||||
nregs = (size + 7) / 8;
|
||||
if (nregs == 2)
|
||||
vtop->type.t = VT_LDOUBLE;
|
||||
nregs = pass_in_freg(func_type, 0);
|
||||
if (!nregs) {
|
||||
nregs = (size + 7) / 8;
|
||||
if (nregs == 2)
|
||||
vtop->type.t = VT_LDOUBLE;
|
||||
}
|
||||
|
||||
if (is_float(func_type->t) && (vtop->type.t & VT_BTYPE) != VT_LDOUBLE)
|
||||
gv(RC_FRET);
|
||||
|
2
tcc.h
2
tcc.h
@ -1604,7 +1604,7 @@ ST_FUNC void gen_clear_cache(void);
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
ST_FUNC void gen_cvt_sxtw(void);
|
||||
ST_FUNC void gen_opl(int op);
|
||||
ST_FUNC void gfunc_return(CType *func_type);
|
||||
//ST_FUNC void gfunc_return(CType *func_type);
|
||||
ST_FUNC void gen_va_start(void);
|
||||
ST_FUNC void gen_va_arg(CType *t);
|
||||
#endif
|
||||
|
2
tccgen.c
2
tccgen.c
@ -6083,7 +6083,6 @@ ST_FUNC int expr_const(void)
|
||||
/* return from function */
|
||||
|
||||
#ifndef TCC_TARGET_ARM64
|
||||
#ifndef TCC_TARGET_RISCV64
|
||||
static void gfunc_return(CType *func_type)
|
||||
{
|
||||
if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
|
||||
@ -6148,7 +6147,6 @@ static void gfunc_return(CType *func_type)
|
||||
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void check_func_return(void)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user