| @@ -147,8 +147,8 @@ ST_FUNC void load(int r, SValue *sv) · 146 unmodified lines |
| 147 | 147 | if (fr & VT_LVAL) { |
| 148 | 148 | int func3, opcode = 0x03, doload = 0; |
| 149 | 149 | if (is_freg(r)) { |
| 150 | | − assert(bt == VT_DOUBLE || bt == VT_FLOAT); |
| 151 | 150 | opcode = 0x07; |
| 151 | + assert(bt == VT_DOUBLE || bt == VT_FLOAT); |
| 152 | 152 | func3 = bt == VT_DOUBLE ? 3 : 2; |
| 153 | 153 | } else { |
| 154 | 154 | assert(is_ireg(r)); |
| @@ -433,6 +433,33 @@ static void gcall_or_jmp(int docall) · 278 unmodified lines |
| 433 | 433 | } |
| 434 | 434 | } |
| 435 | 435 | |
| 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 | + |
| 436 | 463 | ST_FUNC void gfunc_call(int nb_args) |
| 437 | 464 | { |
| 438 | 465 | int i, align, size, aireg, afreg; |
| @@ -461,14 +488,15 @@ ST_FUNC void gfunc_call(int nb_args) · 22 unmodified lines |
| 461 | 488 | nregs = 2; |
| 462 | 489 | else |
| 463 | 490 | nregs = 1; |
| 464 | | − if ((sv->type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 491 | + if (!sa) { |
| 465 | 492 | infreg = 0; |
| 466 | | − } else |
| 467 | | − infreg = sa && is_float(sv->type.t); |
| 493 | + } else { |
| 494 | + infreg = pass_in_freg(&sv->type, 0); |
| 495 | + } |
| 468 | 496 | if (!infreg && !sa && align == 2*XLEN && size <= 2*XLEN) |
| 469 | 497 | aireg = (aireg + 1) & ~1; |
| 470 | 498 | pareg = infreg ? &afreg : &aireg; |
| 471 | | − if ((*pareg < 8) && !force_stack) { |
| 499 | + if ((*pareg < 8 && (!infreg || (*pareg + nregs) <= 8)) && !force_stack) { |
| 472 | 500 | info[i] = *pareg + (infreg ? 8 : 0); |
| 473 | 501 | (*pareg)++; |
| 474 | 502 | if (nregs == 1) |
| @@ -547,7 +575,38 @@ ST_FUNC void gfunc_call(int nb_args) · 72 unmodified lines |
| 547 | 575 | vrotb(i+1); |
| 548 | 576 | origtype = vtop->type; |
| 549 | 577 | 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) |
| 551 | 610 | vtop->type.t = VT_LDOUBLE; // force loading a pair of regs |
| 552 | 611 | gv(r < 8 ? RC_R(r) : RC_F(r - 8)); |
| 553 | 612 | vtop->type = origtype; |
| @@ -565,6 +624,7 @@ ST_FUNC void gfunc_call(int nb_args) · 11 unmodified lines |
| 565 | 624 | vtop->r2 = 1 + vtop->r; |
| 566 | 625 | } |
| 567 | 626 | } |
| 627 | + } |
| 568 | 628 | vrott(i+1); |
| 569 | 629 | } |
| 570 | 630 | } |
| @@ -621,11 +681,14 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 50 unmodified lines |
| 621 | 681 | addr += size; |
| 622 | 682 | } else { |
| 623 | 683 | 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))) |
| 625 | 685 | pareg = &afreg; |
| 686 | + else { |
| 687 | + regcount = 1; |
| 688 | + } |
| 626 | 689 | if (regcount + *pareg > 8) |
| 627 | 690 | goto from_stack; |
| 628 | | − if (size > XLEN) |
| 691 | + if (size > XLEN && pareg == &aireg) |
| 629 | 692 | regcount++; |
| 630 | 693 | loc -= regcount * 8; // XXX could reserve only 'size' bytes |
| 631 | 694 | param_addr = loc; |
| @@ -638,8 +701,8 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 6 unmodified lines |
| 638 | 701 | continue; |
| 639 | 702 | } |
| 640 | 703 | 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) |
| 643 | 706 | } else { |
| 644 | 707 | ES(0x23, 3, 8, 10 + *pareg, loc + i*8); // sd aX, loc(s0) // XXX |
| 645 | 708 | } |
| @@ -666,11 +729,17 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, · 20 unmodified lines |
| 666 | 729 | /* generic code can only deal with structs of pow(2) sizes |
| 667 | 730 | (it always deals with whole registers), so go through our own |
| 668 | 731 | code. */ |
| 669 | | − int align, size = type_size(vt, &align); |
| 732 | + int align, size = type_size(vt, &align), infreg; |
| 670 | 733 | *ret_align = 1; |
| 671 | 734 | *regsize = 8; |
| 672 | 735 | if (size > 16) |
| 673 | 736 | 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 | + } |
| 674 | 743 | if (size > 8) |
| 675 | 744 | ret->t = VT_LLONG; |
| 676 | 745 | else if (size > 4) |
| @@ -684,7 +753,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, · 7 unmodified lines |
| 684 | 753 | return (size + 7) / 8; |
| 685 | 754 | } |
| 686 | 755 | |
| 687 | | −ST_FUNC void gfunc_return(CType *func_type) |
| 756 | +ST_FUNC void gfunc_return2(CType *func_type) |
| 688 | 757 | { |
| 689 | 758 | int align, size = type_size(func_type, &align), nregs; |
| 690 | 759 | CType type = *func_type; |
| @@ -697,9 +766,12 @@ ST_FUNC void gfunc_return(CType *func_type) · 6 unmodified lines |
| 697 | 766 | vpop(); |
| 698 | 767 | return; |
| 699 | 768 | } |
| 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 | + } |
| 703 | 775 | |
| 704 | 776 | if (is_float(func_type->t) && (vtop->type.t & VT_BTYPE) != VT_LDOUBLE) |
| 705 | 777 | gv(RC_FRET); |