diff --git a/riscv64-gen.c b/riscv64-gen.c index 6a5a80e..bc2f983 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -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); } } diff --git a/tccgen.c b/tccgen.c index 745df99..5ea91f6 100644 --- a/tccgen.c +++ b/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