| @@ -433,32 +433,36 @@ static void gcall_or_jmp(int docall) · 432 unmodified lines |
| 433 | 433 | } |
| 434 | 434 | } |
| 435 | 435 | |
| 436 | | −static int pass_in_freg(CType *type, int regs) |
| 436 | +static void reg_pass(CType *type, int *rc, int *fieldofs, int ofs) |
| 437 | 437 | { |
| 438 | | − int tr; |
| 439 | | − int toplevel = !regs; |
| 440 | 438 | if ((type->t & VT_BTYPE) == VT_STRUCT) { |
| 441 | 439 | Sym *f; |
| 442 | 440 | 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; |
| 441 | + rc[0] = -1; |
| 442 | + else for (f = type->ref->next; f; f = f->next) |
| 443 | + reg_pass(&f->type, rc, fieldofs, ofs + f->c); |
| 451 | 444 | } else if (type->t & VT_ARRAY) { |
| 452 | 445 | 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 | | − ? 1 : toplevel ? 0 : -1; |
| 446 | + rc[0] = -1; |
| 447 | + else { |
| 448 | + int a, sz = type_size(&type->ref->type, &a); |
| 449 | + reg_pass(&type->ref->type, rc, fieldofs, ofs); |
| 450 | + if (rc[0] > 2 || (rc[0] == 2 && type->ref->c > 1)) |
| 451 | + rc[0] = -1; |
| 452 | + else if (type->ref->c == 2 && rc[0] && rc[1] == RC_FLOAT) { |
| 453 | + rc[++rc[0]] = RC_FLOAT; |
| 454 | + fieldofs[rc[0]] = ((ofs + sz) << 4) |
| 455 | + | (type->ref->type.t & VT_BTYPE); |
| 456 | + } else if (type->ref->c == 2) |
| 457 | + rc[0] = -1; |
| 458 | + } |
| 459 | + } else if (rc[0] == 2 || rc[0] < 0 || (type->t & VT_BTYPE) == VT_LDOUBLE) |
| 460 | + rc[0] = -1; |
| 461 | + else if (!rc[0] || rc[1] == RC_FLOAT || is_float(type->t)) { |
| 462 | + rc[++rc[0]] = is_float(type->t) ? RC_FLOAT : RC_INT; |
| 463 | + fieldofs[rc[0]] = (ofs << 4) | (type->t & VT_BTYPE); |
| 464 | + } else |
| 465 | + rc[0] = -1; |
| 462 | 466 | } |
| 463 | 467 | |
| 464 | 468 | ST_FUNC void gfunc_call(int nb_args) |
| @@ -472,7 +476,9 @@ ST_FUNC void gfunc_call(int nb_args) · 7 unmodified lines |
| 472 | 476 | aireg = afreg = 0; |
| 473 | 477 | sa = vtop[-nb_args].type.ref->next; |
| 474 | 478 | for (i = 0; i < nb_args; i++) { |
| 475 | | − int *pareg, nregs, infreg = 0, byref = 0, tempofs; |
| 479 | + int *pareg, nregs, byref = 0, tempofs; |
| 480 | + int prc[3], fieldofs[3]; |
| 481 | + prc[0] = 0; |
| 476 | 482 | sv = &vtop[1 + i - nb_args]; |
| 477 | 483 | sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c |
| 478 | 484 | size = type_size(&sv->type, &align); |
| @@ -490,31 +496,43 @@ ST_FUNC void gfunc_call(int nb_args) · 11 unmodified lines |
| 490 | 496 | else |
| 491 | 497 | nregs = 1; |
| 492 | 498 | if (!sa) { |
| 493 | | − infreg = 0; |
| 499 | + prc[0] = nregs, prc[1] = prc[2] = RC_INT; |
| 494 | 500 | } else { |
| 495 | | − infreg = pass_in_freg(&sv->type, 0); |
| 501 | + reg_pass(&sv->type, prc, fieldofs, 0); |
| 502 | + if (prc[0] < 0) |
| 503 | + prc[0] = nregs, prc[1] = prc[2] = RC_INT; |
| 496 | 504 | } |
| 497 | | − if (!infreg && !sa && align == 2*XLEN && size <= 2*XLEN) |
| 505 | + if (!sa && align == 2*XLEN && size <= 2*XLEN) |
| 498 | 506 | aireg = (aireg + 1) & ~1; |
| 499 | | − pareg = infreg ? &afreg : &aireg; |
| 500 | | − if ((*pareg < 8 && (!infreg || (*pareg + nregs) <= 8)) && !force_stack) { |
| 501 | | − info[i] = *pareg + (infreg ? 8 : 0); |
| 502 | | − (*pareg)++; |
| 503 | | − if (nregs == 1) |
| 504 | | − ; |
| 505 | | − else if (*pareg < 8) |
| 506 | | − (*pareg)++; |
| 507 | | − else { |
| 508 | | − info[i] |= 16; |
| 509 | | − stack_adj += 8; |
| 510 | | − } |
| 511 | | − } else { |
| 507 | + nregs = prc[0]; |
| 508 | + assert(nregs); |
| 509 | + if (!nregs |
| 510 | + || (prc[1] == RC_INT && aireg >= 8) |
| 511 | + || (prc[1] == RC_FLOAT && afreg >= 8) |
| 512 | + || (nregs == 2 && prc[2] == RC_FLOAT && afreg >= 7) |
| 513 | + || (nregs == 2 && prc[1] != prc[2] && (afreg >= 8 || aireg >= 8)) |
| 514 | + || force_stack) { |
| 512 | 515 | info[i] = 32; |
| 513 | 516 | if (align < XLEN) |
| 514 | 517 | align = XLEN; |
| 515 | 518 | stack_adj += (size + align - 1) & -align; |
| 516 | 519 | if (!sa) |
| 517 | 520 | force_stack = 1; |
| 521 | + } else { |
| 522 | + if (prc[1] == RC_FLOAT) |
| 523 | + info[i] = 8 + afreg++; |
| 524 | + else |
| 525 | + info[i] = aireg++; |
| 526 | + if (nregs == 2) { |
| 527 | + if (prc[2] == RC_FLOAT) |
| 528 | + info[i] |= (1 + 8 + afreg++) << 7; |
| 529 | + else if (aireg < 8) |
| 530 | + info[i] |= (1 + aireg++) << 7; |
| 531 | + else { |
| 532 | + info[i] |= 16; |
| 533 | + stack_adj += 8; |
| 534 | + } |
| 535 | + } |
| 518 | 536 | } |
| 519 | 537 | if (byref) |
| 520 | 538 | info[i] |= 64 | (tempofs << 7); |
| @@ -569,62 +587,72 @@ ST_FUNC void gfunc_call(int nb_args) · 48 unmodified lines |
| 569 | 587 | } |
| 570 | 588 | } |
| 571 | 589 | for (i = 0; i < nb_args; i++) { |
| 572 | | − int r = info[nb_args - 1 - i]; |
| 590 | + int r = info[nb_args - 1 - i], r2 = r; |
| 573 | 591 | if (!(r & 32)) { |
| 574 | 592 | CType origtype; |
| 593 | + int prc[3], fieldofs[3], loadt; |
| 594 | + prc[0] = 0; |
| 575 | 595 | r &= 15; |
| 596 | + r2 = r2 & 64 ? 0 : r2 >> 7; |
| 576 | 597 | vrotb(i+1); |
| 577 | 598 | origtype = vtop->type; |
| 578 | 599 | size = type_size(&vtop->type, &align); |
| 579 | | − if (r >= 8 && (vtop->r & VT_LVAL)) { |
| 580 | | − int infreg = pass_in_freg(&vtop->type, 0); |
| 581 | | − int loadt = vtop->type.t & VT_BTYPE; |
| 600 | + reg_pass(&vtop->type, prc, fieldofs, 0); |
| 601 | + if (prc[0] <= 0 || (!r2 && prc[0] > 1)) { |
| 602 | + prc[0] = (size + 7) >> 3; |
| 603 | + prc[1] = prc[2] = RC_INT; |
| 604 | + fieldofs[1] = (0 << 4) | (size <= 1 ? VT_BYTE : size <= 2 ? VT_SHORT : size <= 4 ? VT_INT : VT_LLONG); |
| 605 | + fieldofs[2] = (8 << 4) | (size <= 9 ? VT_BYTE : size <= 10 ? VT_SHORT : size <= 12 ? VT_INT : VT_LLONG); |
| 606 | + } |
| 607 | + loadt = vtop->type.t & VT_BTYPE; |
| 608 | + if (loadt == VT_STRUCT) { |
| 609 | + loadt = fieldofs[1] & VT_BTYPE; |
| 610 | + } |
| 611 | + if (info[nb_args - 1 - i] & 16) { |
| 612 | + assert(!r2); |
| 613 | + r2 = 1 + TREG_RA; |
| 614 | + } |
| 615 | + if (loadt == VT_LDOUBLE) { |
| 616 | + assert(r2); |
| 617 | + r2--; |
| 618 | + } else if (r2) { |
| 619 | + test_lvalue(); |
| 620 | + vpushv(vtop); |
| 621 | + } |
| 622 | + vtop->type.t = loadt; |
| 623 | + gv(r < 8 ? RC_R(r) : RC_F(r - 8)); |
| 624 | + vtop->type = origtype; |
| 625 | + |
| 626 | + if (r2 && loadt != VT_LDOUBLE) { |
| 627 | + r2--; |
| 628 | + assert(r2 < 16 || r2 == TREG_RA); |
| 629 | + vswap(); |
| 630 | + gaddrof(); |
| 631 | + vtop->type = char_pointer_type; |
| 632 | + vpushi(fieldofs[2] >> 4); |
| 633 | + gen_op('+'); |
| 634 | + indir(); |
| 635 | + vtop->type = origtype; |
| 636 | + loadt = vtop->type.t & VT_BTYPE; |
| 582 | 637 | if (loadt == VT_STRUCT) { |
| 583 | | − if (infreg == 1) |
| 584 | | − loadt = size == 4 ? VT_FLOAT : VT_DOUBLE; |
| 585 | | − else |
| 586 | | − loadt = size == 8 ? VT_FLOAT : VT_DOUBLE; |
| 638 | + loadt = fieldofs[2] & VT_BTYPE; |
| 587 | 639 | } |
| 640 | + save_reg_upstack(r2, 1); |
| 588 | 641 | vtop->type.t = loadt; |
| 589 | | − assert (infreg && infreg <= 2); |
| 590 | | − save_reg_upstack(r, 1); |
| 591 | | − if (infreg > 1) { |
| 592 | | − save_reg_upstack(r + 1, 1); |
| 593 | | − test_lvalue(); |
| 594 | | − } |
| 595 | | − load(r, vtop); |
| 596 | | − vset(&origtype, r, 0); |
| 597 | | − vswap(); |
| 598 | | − if (infreg > 1) { |
| 599 | | − assert(r + 1 < 16); |
| 600 | | − gaddrof(); |
| 601 | | − mk_pointer(&vtop->type); |
| 602 | | − vpushi(1); |
| 603 | | − gen_op('+'); |
| 604 | | − indir(); |
| 605 | | − load(r + 1, vtop); |
| 606 | | − vtop[-1].r2 = r + 1; |
| 607 | | − } |
| 642 | + load(r2, vtop); |
| 643 | + assert(r2 < VT_CONST); |
| 608 | 644 | vtop--; |
| 609 | | − } else { |
| 610 | | − if (r < 8 && size > 8 && (vtop->type.t & VT_BTYPE) == VT_STRUCT) |
| 611 | | − vtop->type.t = VT_LDOUBLE; // force loading a pair of regs |
| 612 | | − gv(r < 8 ? RC_R(r) : RC_F(r - 8)); |
| 613 | | − vtop->type = origtype; |
| 614 | | − if (size > 8) { |
| 615 | | − assert((vtop->type.t & VT_BTYPE) == VT_LDOUBLE |
| 616 | | − || (vtop->type.t & VT_BTYPE) == VT_STRUCT); |
| 617 | | − assert(vtop->r2 < VT_CONST); |
| 618 | | − if (info[nb_args - 1 - i] & 16) { |
| 619 | | − ES(0x23, 3, 2, ireg(vtop->r2), splitofs); // sd t0, ofs(sp) |
| 620 | | − } else if (vtop->r2 != 1 + vtop->r) { |
| 621 | | − assert(vtop->r < 7); |
| 622 | | − /* XXX we'd like to have 'gv' move directly into |
| 623 | | − the right class instead of us fixing it up. */ |
| 624 | | − EI(0x13, 0, ireg(vtop->r) + 1, ireg(vtop->r2), 0); // mv Ra+1, RR2 |
| 625 | | − vtop->r2 = 1 + vtop->r; |
| 626 | | − } |
| 645 | + vtop->r2 = r2; |
| 627 | 646 | } |
| 647 | + if (info[nb_args - 1 - i] & 16) { |
| 648 | + ES(0x23, 3, 2, ireg(vtop->r2), splitofs); // sd t0, ofs(sp) |
| 649 | + vtop->r2 = VT_CONST; |
| 650 | + } else if (loadt == VT_LDOUBLE && vtop->r2 != r2) { |
| 651 | + assert(vtop->r2 <= 7 && r2 <= 7); |
| 652 | + /* XXX we'd like to have 'gv' move directly into |
| 653 | + the right class instead of us fixing it up. */ |
| 654 | + EI(0x13, 0, ireg(r2), ireg(vtop->r2), 0); // mv Ra+1, RR2 |
| 655 | + vtop->r2 = r2; |
| 628 | 656 | } |
| 629 | 657 | vrott(i+1); |
| 630 | 658 | } |
| @@ -681,19 +709,29 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 50 unmodified lines |
| 681 | 709 | param_addr = addr; |
| 682 | 710 | addr += size; |
| 683 | 711 | } else { |
| 684 | | − int regcount = 1, *pareg = &aireg; |
| 685 | | − if ((regcount = pass_in_freg(type, 0))) |
| 686 | | − pareg = &afreg; |
| 687 | | − else { |
| 688 | | − regcount = 1; |
| 712 | + int regcount, *pareg; |
| 713 | + int prc[3], fieldofs[3]; |
| 714 | + prc[0] = 0; |
| 715 | + reg_pass(type, prc, fieldofs, 0); |
| 716 | + if (prc[0] <= 0) { |
| 717 | + prc[0] = (size + 7) >> 3; |
| 718 | + prc[1] = prc[2] = RC_INT; |
| 719 | + fieldofs[1] = (0 << 4) | (size <= 1 ? VT_BYTE : size <= 2 ? VT_SHORT : size <= 4 ? VT_INT : VT_LLONG); |
| 720 | + fieldofs[2] = (8 << 4) | (size <= 9 ? VT_BYTE : size <= 10 ? VT_SHORT : size <= 12 ? VT_INT : VT_LLONG); |
| 689 | 721 | } |
| 690 | | − if (regcount + *pareg > 8) |
| 722 | + regcount = prc[0]; |
| 723 | + if (!regcount |
| 724 | + || (prc[1] == RC_INT && aireg >= 8) |
| 725 | + || (prc[1] == RC_FLOAT && afreg >= 8) |
| 726 | + || (regcount == 2 && prc[2] == RC_FLOAT && afreg >= 7) |
| 727 | + || (regcount == 2 && prc[1] != prc[2] && (afreg >= 8 || aireg >= 8))) |
| 691 | 728 | goto from_stack; |
| 692 | | − if (size > XLEN && pareg == &aireg) |
| 693 | | − regcount++; |
| 729 | + if (size > XLEN) |
| 730 | + assert(regcount == 2); |
| 694 | 731 | loc -= regcount * 8; // XXX could reserve only 'size' bytes |
| 695 | 732 | param_addr = loc; |
| 696 | 733 | for (i = 0; i < regcount; i++) { |
| 734 | + pareg = prc[1+i] == RC_INT ? &aireg : &afreg; |
| 697 | 735 | if (*pareg >= 8) { |
| 698 | 736 | assert(i == 1 && regcount == 2 && !(addr & 7)); |
| 699 | 737 | EI(0x03, 3, 5, 8, addr); // ld t0, addr(s0) |
| @@ -703,11 +741,10 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 3 unmodified lines |
| 703 | 741 | } |
| 704 | 742 | if (pareg == &afreg) { |
| 705 | 743 | //assert(type->t == VT_FLOAT || type->t == VT_DOUBLE); |
| 706 | | − ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + *pareg, loc + i*(size / regcount)); // fs[wd] FAi, loc(s0) |
| 744 | + ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + afreg++, loc + (fieldofs[i+1] >> 4)); // fs[wd] FAi, loc(s0) |
| 707 | 745 | } else { |
| 708 | | − ES(0x23, 3, 8, 10 + *pareg, loc + i*8); // sd aX, loc(s0) // XXX |
| 746 | + ES(0x23, 3, 8, 10 + aireg++, loc + i*8); // sd aX, loc(s0) // XXX |
| 709 | 747 | } |
| 710 | | − (*pareg)++; |
| 711 | 748 | } |
| 712 | 749 | } |
| 713 | 750 | sym_push(sym->v & ~SYM_FIELD, &sym->type, |
| @@ -727,57 +764,50 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 13 unmodified lines |
| 727 | 764 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, |
| 728 | 765 | int *ret_align, int *regsize) |
| 729 | 766 | { |
| 730 | | − /* generic code can only deal with structs of pow(2) sizes |
| 731 | | − (it always deals with whole registers), so go through our own |
| 732 | | − code. */ |
| 733 | | − int align, size = type_size(vt, &align), infreg; |
| 767 | + int align, size = type_size(vt, &align), infreg, nregs; |
| 768 | + int prc[3], fieldofs[3]; |
| 734 | 769 | *ret_align = 1; |
| 735 | 770 | *regsize = 8; |
| 736 | 771 | if (size > 16) |
| 737 | 772 | return 0; |
| 738 | | − infreg = pass_in_freg(vt, 0); |
| 739 | | − if (infreg) { |
| 740 | | − *regsize = size / infreg; |
| 741 | | − ret->t = (size / infreg) == 4 ? VT_FLOAT : VT_DOUBLE; |
| 742 | | − return infreg; |
| 773 | + prc[0] = 0; |
| 774 | + reg_pass(vt, prc, fieldofs, 0); |
| 775 | + if (prc[0] <= 0) { |
| 776 | + prc[0] = (size + 7) >> 3; |
| 777 | + prc[1] = prc[2] = RC_INT; |
| 778 | + fieldofs[1] = (0 << 4) | (size <= 1 ? VT_BYTE : size <= 2 ? VT_SHORT : size <= 4 ? VT_INT : VT_LLONG); |
| 779 | + fieldofs[2] = (8 << 4) | (size <= 9 ? VT_BYTE : size <= 10 ? VT_SHORT : size <= 12 ? VT_INT : VT_LLONG); |
| 743 | 780 | } |
| 744 | | − if (size > 8) |
| 745 | | − ret->t = VT_LLONG; |
| 746 | | − else if (size > 4) |
| 747 | | − ret->t = VT_LLONG; |
| 748 | | − else if (size > 2) |
| 749 | | − ret->t = VT_INT; |
| 750 | | − else if (size > 1) |
| 751 | | − ret->t = VT_SHORT; |
| 752 | | − else |
| 753 | | − ret->t = VT_BYTE; |
| 754 | | − return (size + 7) / 8; |
| 781 | + nregs = prc[0]; |
| 782 | + assert(nregs > 0); |
| 783 | + if (nregs == 2 && prc[1] != prc[2]) |
| 784 | + return -1; /* generic code can't deal with this case */ |
| 785 | + if (prc[1] == RC_FLOAT) { |
| 786 | + *regsize = size / nregs; |
| 787 | + } |
| 788 | + ret->t = fieldofs[1] & VT_BTYPE; |
| 789 | + return nregs; |
| 755 | 790 | } |
| 756 | 791 | |
| 757 | | −ST_FUNC void gfunc_return2(CType *func_type) |
| 792 | +ST_FUNC void arch_transfer_ret_regs(int aftercall) |
| 758 | 793 | { |
| 759 | | − int align, size = type_size(func_type, &align), nregs; |
| 760 | | − CType type = *func_type; |
| 761 | | − if (size > 2 * XLEN) { |
| 762 | | − mk_pointer(&type); |
| 763 | | − vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
| 764 | | − indir(); |
| 765 | | − vswap(); |
| 766 | | − vstore(); |
| 767 | | − vpop(); |
| 768 | | − return; |
| 769 | | − } |
| 770 | | − nregs = pass_in_freg(func_type, 0); |
| 771 | | − if (!nregs) { |
| 772 | | − nregs = (size + 7) / 8; |
| 773 | | − if (nregs == 2) |
| 774 | | − vtop->type.t = VT_LDOUBLE; |
| 775 | | − } |
| 776 | | − |
| 777 | | − if (is_float(func_type->t) && (vtop->type.t & VT_BTYPE) != VT_LDOUBLE) |
| 778 | | − gv(RC_FRET); |
| 794 | + int prc[3], fieldofs[3]; |
| 795 | + prc[0] = 0; |
| 796 | + reg_pass(&vtop->type, prc, fieldofs, 0); |
| 797 | + assert(prc[0] == 2 && prc[1] != prc[2] && !(fieldofs[1] >> 4)); |
| 798 | + assert(vtop->r == (VT_LOCAL | VT_LVAL)); |
| 799 | + vpushv(vtop); |
| 800 | + vtop->type.t = fieldofs[1] & VT_BTYPE; |
| 801 | + if (aftercall) |
| 802 | + store(prc[1] == RC_INT ? REG_IRET : REG_FRET, vtop); |
| 803 | + else |
| 804 | + load(prc[1] == RC_INT ? REG_IRET : REG_FRET, vtop); |
| 805 | + vtop->c.i += fieldofs[2] >> 4; |
| 806 | + vtop->type.t = fieldofs[2] & VT_BTYPE; |
| 807 | + if (aftercall) |
| 808 | + store(prc[2] == RC_INT ? REG_IRET : REG_FRET, vtop); |
| 779 | 809 | else |
| 780 | | − gv(RC_IRET); |
| 810 | + load(prc[2] == RC_INT ? REG_IRET : REG_FRET, vtop); |
| 781 | 811 | vtop--; |
| 782 | 812 | } |
| 783 | 813 | |