History

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.

Michael Matz committed 7 years ago

Commit 98f1b831 parent 98dc4c13 files · +88 −18Browse files

Unified · Split

3 files
  1. riscv64-gen.c +87 −15
  2. tcc.h +1 −1
  3. tccgen.c +0 −2
riscv64-gen.c+87−15
@@ -147,8 +147,8 @@ ST_FUNC void load(int r, SValue *sv) · 146 unmodified lines
147147 if (fr & VT_LVAL) {
148148 int func3, opcode = 0x03, doload = 0;
149149 if (is_freg(r)) {
150− assert(bt == VT_DOUBLE || bt == VT_FLOAT);
151150 opcode = 0x07;
151+ assert(bt == VT_DOUBLE || bt == VT_FLOAT);
152152 func3 = bt == VT_DOUBLE ? 3 : 2;
153153 } else {
154154 assert(is_ireg(r));
@@ -433,6 +433,33 @@ static void gcall_or_jmp(int docall) · 278 unmodified lines
433433 }
434434 }
435435
436+static int pass_in_freg(CType *type, int regs)
437+{
438+ int tr;
439+ int toplevel = !regs;
440+ if ((type->t & VT_BTYPE) == VT_STRUCT) {
441+ Sym *f;
442+ if (type->ref->type.t == VT_UNION)
443+ return toplevel ? 0 : -1;
444+ for (f = type->ref->next; f; f = f->next) {
445+ tr = pass_in_freg(&f->type, regs);
446+ if (tr < 0 || (regs + tr) > 2)
447+ return toplevel ? 0 : -1;
448+ regs += tr;
449+ }
450+ return regs;
451+ } else if (type->t & VT_ARRAY) {
452+ if (type->ref->c < 0 || type->ref->c > 2)
453+ return toplevel ? 0 : -1;
454+ tr = pass_in_freg(&type->ref->type, regs);
455+ tr *= type->ref->c;
456+ if (tr < 0 || (regs + tr) > 2)
457+ return toplevel ? 0 : -1;
458+ return regs + tr;
459+ }
460+ return is_float(type->t) && (type->t & VT_BTYPE) != VT_LDOUBLE;
461+}
462+
436463 ST_FUNC void gfunc_call(int nb_args)
437464 {
438465 int i, align, size, aireg, afreg;
@@ -461,14 +488,15 @@ ST_FUNC void gfunc_call(int nb_args) · 22 unmodified lines
461488 nregs = 2;
462489 else
463490 nregs = 1;
464− if ((sv->type.t & VT_BTYPE) == VT_LDOUBLE) {
491+ if (!sa) {
465492 infreg = 0;
466− } else
467− infreg = sa && is_float(sv->type.t);
493+ } else {
494+ infreg = pass_in_freg(&sv->type, 0);
495+ }
468496 if (!infreg && !sa && align == 2*XLEN && size <= 2*XLEN)
469497 aireg = (aireg + 1) & ~1;
470498 pareg = infreg ? &afreg : &aireg;
471− if ((*pareg < 8) && !force_stack) {
499+ if ((*pareg < 8 && (!infreg || (*pareg + nregs) <= 8)) && !force_stack) {
472500 info[i] = *pareg + (infreg ? 8 : 0);
473501 (*pareg)++;
474502 if (nregs == 1)
@@ -547,7 +575,38 @@ ST_FUNC void gfunc_call(int nb_args) · 72 unmodified lines
547575 vrotb(i+1);
548576 origtype = vtop->type;
549577 size = type_size(&vtop->type, &align);
550− if (size > 8 && (vtop->type.t & VT_BTYPE) == VT_STRUCT)
578+ if (r >= 8 && (vtop->r & VT_LVAL)) {
579+ int infreg = pass_in_freg(&vtop->type, 0);
580+ int loadt = vtop->type.t & VT_BTYPE;
581+ if (loadt == VT_STRUCT) {
582+ if (infreg == 1)
583+ loadt = size == 4 ? VT_FLOAT : VT_DOUBLE;
584+ else
585+ loadt = size == 8 ? VT_FLOAT : VT_DOUBLE;
586+ }
587+ vtop->type.t = loadt;
588+ assert (infreg && infreg <= 2);
589+ save_reg_upstack(r, 1);
590+ if (infreg > 1) {
591+ save_reg_upstack(r + 1, 1);
592+ test_lvalue();
593+ }
594+ load(r, vtop);
595+ vset(&origtype, r, 0);
596+ vswap();
597+ if (infreg > 1) {
598+ assert(r + 1 < 16);
599+ gaddrof();
600+ mk_pointer(&vtop->type);
601+ vpushi(1);
602+ gen_op('+');
603+ indir();
604+ load(r + 1, vtop);
605+ vtop[-1].r2 = r + 1;
606+ }
607+ vtop--;
608+ } else {
609+ if (r < 8 && size > 8 && (vtop->type.t & VT_BTYPE) == VT_STRUCT)
551610 vtop->type.t = VT_LDOUBLE; // force loading a pair of regs
552611 gv(r < 8 ? RC_R(r) : RC_F(r - 8));
553612 vtop->type = origtype;
@@ -565,6 +624,7 @@ ST_FUNC void gfunc_call(int nb_args) · 11 unmodified lines
565624 vtop->r2 = 1 + vtop->r;
566625 }
567626 }
627+ }
568628 vrott(i+1);
569629 }
570630 }
@@ -621,11 +681,14 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 50 unmodified lines
621681 addr += size;
622682 } else {
623683 int regcount = 1, *pareg = &aireg;
624− if (is_float(type->t) && (type->t & VT_BTYPE) != VT_LDOUBLE)
684+ if ((regcount = pass_in_freg(type, 0)))
625685 pareg = &afreg;
686+ else {
687+ regcount = 1;
688+ }
626689 if (regcount + *pareg > 8)
627690 goto from_stack;
628− if (size > XLEN)
691+ if (size > XLEN && pareg == &aireg)
629692 regcount++;
630693 loc -= regcount * 8; // XXX could reserve only 'size' bytes
631694 param_addr = loc;
@@ -638,8 +701,8 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 6 unmodified lines
638701 continue;
639702 }
640703 if (pareg == &afreg) {
641− assert(type->t == VT_FLOAT || type->t == VT_DOUBLE);
642− ES(0x27, size == 4 ? 2 : 3, 8, 10 + *pareg, loc + i*8); // fs[wd] FAi, loc(s0)
704+ //assert(type->t == VT_FLOAT || type->t == VT_DOUBLE);
705+ ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + *pareg, loc + i*(size / regcount)); // fs[wd] FAi, loc(s0)
643706 } else {
644707 ES(0x23, 3, 8, 10 + *pareg, loc + i*8); // sd aX, loc(s0) // XXX
645708 }
@@ -666,11 +729,17 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, · 20 unmodified lines
666729 /* generic code can only deal with structs of pow(2) sizes
667730 (it always deals with whole registers), so go through our own
668731 code. */
669− int align, size = type_size(vt, &align);
732+ int align, size = type_size(vt, &align), infreg;
670733 *ret_align = 1;
671734 *regsize = 8;
672735 if (size > 16)
673736 return 0;
737+ infreg = pass_in_freg(vt, 0);
738+ if (infreg) {
739+ *regsize = size / infreg;
740+ ret->t = (size / infreg) == 4 ? VT_FLOAT : VT_DOUBLE;
741+ return infreg;
742+ }
674743 if (size > 8)
675744 ret->t = VT_LLONG;
676745 else if (size > 4)
@@ -684,7 +753,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, · 7 unmodified lines
684753 return (size + 7) / 8;
685754 }
686755
687−ST_FUNC void gfunc_return(CType *func_type)
756+ST_FUNC void gfunc_return2(CType *func_type)
688757 {
689758 int align, size = type_size(func_type, &align), nregs;
690759 CType type = *func_type;
@@ -697,9 +766,12 @@ ST_FUNC void gfunc_return(CType *func_type) · 6 unmodified lines
697766 vpop();
698767 return;
699768 }
700− nregs = (size + 7) / 8;
701− if (nregs == 2)
702− vtop->type.t = VT_LDOUBLE;
769+ nregs = pass_in_freg(func_type, 0);
770+ if (!nregs) {
771+ nregs = (size + 7) / 8;
772+ if (nregs == 2)
773+ vtop->type.t = VT_LDOUBLE;
774+ }
703775
704776 if (is_float(func_type->t) && (vtop->type.t & VT_BTYPE) != VT_LDOUBLE)
705777 gv(RC_FRET);
tcc.h+1−1
@@ -1604,7 +1604,7 @@ ST_FUNC void gen_clear_cache(void); · 1603 unmodified lines
16041604 #ifdef TCC_TARGET_RISCV64
16051605 ST_FUNC void gen_cvt_sxtw(void);
16061606 ST_FUNC void gen_opl(int op);
1607−ST_FUNC void gfunc_return(CType *func_type);
1607+//ST_FUNC void gfunc_return(CType *func_type);
16081608 ST_FUNC void gen_va_start(void);
16091609 ST_FUNC void gen_va_arg(CType *t);
16101610 #endif
tccgen.c+0−2
@@ -6083,7 +6083,6 @@ ST_FUNC int expr_const(void) · 6082 unmodified lines
60836083 /* return from function */
60846084
60856085 #ifndef TCC_TARGET_ARM64
6086−#ifndef TCC_TARGET_RISCV64
60876086 static void gfunc_return(CType *func_type)
60886087 {
60896088 if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
@@ -6148,7 +6147,6 @@ static void gfunc_return(CType *func_type) · 58 unmodified lines
61486147 vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
61496148 }
61506149 #endif
6151−#endif
61526150
61536151 static void check_func_return(void)
61546152 {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t