mirror of
https://github.com/frida/tinycc
synced 2025-02-10 04:14:02 +03:00
riscv: some long double support
long double on risc-v is 128bit, but there are no registers for that type (without the Q ISA extension). They are passed like two 64bit integers values (with an exception for varargs, where it's an aligned register pair). This all requires some hacks in generic code as otherwise RC_FLOAT regs are tried for holding values of long double type, but we need a RC_INT register pair. This really could all use some cleanup for all archs. This doesn't implement any conversions of operations for long double, but it's enough to get 70_floating_point_literals working.
This commit is contained in:
parent
9c1b17407f
commit
9309585dbe
@ -345,24 +345,45 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
int i, align, size, aireg, afreg;
|
||||
int info[nb_args ? nb_args : 1];
|
||||
int stack_adj = 0, ofs;
|
||||
int force_stack = 0;
|
||||
SValue *sv;
|
||||
Sym *sa;
|
||||
aireg = afreg = 0;
|
||||
sa = vtop[-nb_args].type.ref->next;
|
||||
for (i = 0; i < nb_args; i++) {
|
||||
int *pareg;
|
||||
int *pareg, nregs, infreg = 0;
|
||||
sv = &vtop[1 + i - nb_args];
|
||||
sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c
|
||||
size = type_size(&sv->type, &align);
|
||||
if (size > 8 || ((sv->type.t & VT_BTYPE) == VT_STRUCT))
|
||||
if ((size > 8 && ((sv->type.t & VT_BTYPE) != VT_LDOUBLE))
|
||||
|| ((sv->type.t & VT_BTYPE) == VT_STRUCT))
|
||||
tcc_error("unimp: call arg %d wrong type", nb_args - i);
|
||||
pareg = sa && is_float(sv->type.t) ? &afreg : &aireg;
|
||||
if (*pareg < 8) {
|
||||
info[i] = *pareg + (sa && is_float(sv->type.t) ? 8 : 0);
|
||||
nregs = 1;
|
||||
if ((sv->type.t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
infreg = 0, nregs = 2;
|
||||
if (!sa) {
|
||||
aireg = (aireg + 1) & ~1;
|
||||
}
|
||||
} else
|
||||
infreg = sa && is_float(sv->type.t);
|
||||
pareg = infreg ? &afreg : &aireg;
|
||||
if ((*pareg < 8) && !force_stack) {
|
||||
info[i] = *pareg + (infreg ? 8 : 0);
|
||||
(*pareg)++;
|
||||
if (nregs == 1)
|
||||
;
|
||||
else if (*pareg < 8)
|
||||
(*pareg)++;
|
||||
else {
|
||||
info[i] |= 16;
|
||||
stack_adj += 8;
|
||||
tcc_error("unimp: param passing half in reg, half on stack");
|
||||
}
|
||||
} else {
|
||||
info[i] = 16;
|
||||
info[i] = 32;
|
||||
stack_adj += (size + align - 1) & -align;
|
||||
if (!sa)
|
||||
force_stack = 1;
|
||||
}
|
||||
if (sa)
|
||||
sa = sa->next;
|
||||
@ -371,7 +392,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
if (stack_adj) {
|
||||
EI(0x13, 0, 2, 2, -stack_adj); // addi sp, sp, -adj
|
||||
for (i = ofs = 0; i < nb_args; i++) {
|
||||
if (1 && info[i] >= 16) {
|
||||
if (1 && info[i] >= 32) {
|
||||
vrotb(nb_args - i);
|
||||
size = type_size(&vtop->type, &align);
|
||||
/* Once we support offseted regs we can do this:
|
||||
@ -393,9 +414,20 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
}
|
||||
for (i = 0; i < nb_args; i++) {
|
||||
int r = info[nb_args - 1 - i];
|
||||
if (r < 16) {
|
||||
if (r < 32) {
|
||||
r &= 15;
|
||||
vrotb(i+1);
|
||||
gv(r < 8 ? RC_R(r) : RC_F(r - 8));
|
||||
if (vtop->r2 < VT_CONST) {
|
||||
assert((vtop->type.t & VT_BTYPE) == VT_LDOUBLE);
|
||||
assert(vtop->r < 7);
|
||||
if (vtop->r2 != 1 + vtop->r) {
|
||||
/* XXX we'd like to have 'gv' move directly into
|
||||
the right class instead of us fixing it up. */
|
||||
EI(0x13, 0, ireg(vtop->r) + 1, ireg(vtop->r2), 0); // mv Ra+1, RR2
|
||||
vtop->r2 = 1 + vtop->r;
|
||||
}
|
||||
}
|
||||
vrott(i+1);
|
||||
}
|
||||
}
|
||||
|
38
tccgen.c
38
tccgen.c
@ -1548,6 +1548,11 @@ ST_FUNC int gv(int rc)
|
||||
if (vtop->r & VT_MUSTBOUND)
|
||||
gbound();
|
||||
#endif
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
/* XXX mega hack */
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && rc == RC_FLOAT)
|
||||
rc = RC_INT;
|
||||
#endif
|
||||
|
||||
r = vtop->r & VT_VALMASK;
|
||||
rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
|
||||
@ -1568,7 +1573,10 @@ ST_FUNC int gv(int rc)
|
||||
if (r >= VT_CONST
|
||||
|| (vtop->r & VT_LVAL)
|
||||
|| !(reg_classes[r] & rc)
|
||||
#if PTR_SIZE == 8
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
|| ((vtop->type.t & VT_BTYPE) == VT_QLONG && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2)))
|
||||
|| ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2)))
|
||||
#elif PTR_SIZE == 8
|
||||
|| ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
|
||||
|| ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
|
||||
#else
|
||||
@ -1577,7 +1585,10 @@ ST_FUNC int gv(int rc)
|
||||
)
|
||||
{
|
||||
r = get_reg(rc);
|
||||
#if PTR_SIZE == 8
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)) {
|
||||
int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG;
|
||||
#elif PTR_SIZE == 8
|
||||
if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {
|
||||
int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
|
||||
#else
|
||||
@ -1708,6 +1719,9 @@ static int rc_fret(int t)
|
||||
if (t == VT_LDOUBLE) {
|
||||
return RC_ST0;
|
||||
}
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
if (t == VT_LDOUBLE)
|
||||
return RC_IRET;
|
||||
#endif
|
||||
return RC_FRET;
|
||||
}
|
||||
@ -1720,6 +1734,9 @@ static int reg_fret(int t)
|
||||
if (t == VT_LDOUBLE) {
|
||||
return TREG_ST0;
|
||||
}
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
if (t == VT_LDOUBLE)
|
||||
return REG_IRET;
|
||||
#endif
|
||||
return REG_FRET;
|
||||
}
|
||||
@ -1797,6 +1814,9 @@ static void gv_dup(void)
|
||||
if ((t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
rc = RC_ST0;
|
||||
}
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
if ((t & VT_BTYPE) == VT_LDOUBLE)
|
||||
rc = RC_INT;
|
||||
#endif
|
||||
sv.type.t = t;
|
||||
}
|
||||
@ -3403,6 +3423,9 @@ ST_FUNC void vstore(void)
|
||||
} else if ((ft & VT_BTYPE) == VT_QFLOAT) {
|
||||
rc = RC_FRET;
|
||||
}
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
if (dbt == VT_LDOUBLE)
|
||||
rc = RC_INT;
|
||||
#endif
|
||||
}
|
||||
r = gv(rc); /* generate value */
|
||||
@ -3421,7 +3444,10 @@ ST_FUNC void vstore(void)
|
||||
vtop[-1].r = t | VT_LVAL;
|
||||
}
|
||||
/* two word case handling : store second register at word + 4 (or +8 for x86-64) */
|
||||
#if PTR_SIZE == 8
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
if (dbt == VT_QLONG || dbt == VT_LDOUBLE) {
|
||||
int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG;
|
||||
#elif PTR_SIZE == 8
|
||||
if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) {
|
||||
int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
|
||||
#else
|
||||
@ -5743,6 +5769,9 @@ static void expr_cond(void)
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
rc = RC_ST0;
|
||||
}
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
|
||||
rc = RC_INT;
|
||||
#endif
|
||||
}
|
||||
gv(rc);
|
||||
@ -5914,6 +5943,9 @@ static void expr_cond(void)
|
||||
if ((type.t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
rc = RC_ST0;
|
||||
}
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
|
||||
rc = RC_INT;
|
||||
#endif
|
||||
} else if ((type.t & VT_BTYPE) == VT_LLONG) {
|
||||
/* for long longs, we use fixed registers to avoid having
|
||||
|
Loading…
x
Reference in New Issue
Block a user