factor and cleanup the param passing code somewhat.
Unified · Split
| @@ -433,20 +433,20 @@ static void gcall_or_jmp(int docall) · 432 unmodified lines | ||
| 433 | 433 | } |
| 434 | 434 | } |
| 435 | 435 | |
| 436 | −static void reg_pass(CType *type, int *rc, int *fieldofs, int ofs) | |
| 436 | +static void reg_pass_rec(CType *type, int *rc, int *fieldofs, int ofs) | |
| 437 | 437 | { |
| 438 | 438 | if ((type->t & VT_BTYPE) == VT_STRUCT) { |
| 439 | 439 | Sym *f; |
| 440 | 440 | if (type->ref->type.t == VT_UNION) |
| 441 | 441 | rc[0] = -1; |
| 442 | 442 | else for (f = type->ref->next; f; f = f->next) |
| 443 | − reg_pass(&f->type, rc, fieldofs, ofs + f->c); | |
| 443 | + reg_pass_rec(&f->type, rc, fieldofs, ofs + f->c); | |
| 444 | 444 | } else if (type->t & VT_ARRAY) { |
| 445 | 445 | if (type->ref->c < 0 || type->ref->c > 2) |
| 446 | 446 | rc[0] = -1; |
| 447 | 447 | else { |
| 448 | 448 | int a, sz = type_size(&type->ref->type, &a); |
| 449 | − reg_pass(&type->ref->type, rc, fieldofs, ofs); | |
| 449 | + reg_pass_rec(&type->ref->type, rc, fieldofs, ofs); | |
| 450 | 450 | if (rc[0] > 2 || (rc[0] == 2 && type->ref->c > 1)) |
| 451 | 451 | rc[0] = -1; |
| 452 | 452 | else if (type->ref->c == 2 && rc[0] && rc[1] == RC_FLOAT) { |
| @@ -465,20 +465,32 @@ static void reg_pass(CType *type, int *rc, int *fieldofs, int ofs) · 12 unmodified lines | ||
| 465 | 465 | rc[0] = -1; |
| 466 | 466 | } |
| 467 | 467 | |
| 468 | +static void reg_pass(CType *type, int *prc, int *fieldofs, int named) | |
| 469 | +{ | |
| 470 | + prc[0] = 0; | |
| 471 | + reg_pass_rec(type, prc, fieldofs, 0); | |
| 472 | + if (prc[0] <= 0 || !named) { | |
| 473 | + int align, size = type_size(type, &align); | |
| 474 | + prc[0] = (size + 7) >> 3; | |
| 475 | + prc[1] = prc[2] = RC_INT; | |
| 476 | + fieldofs[1] = (0 << 4) | (size <= 1 ? VT_BYTE : size <= 2 ? VT_SHORT : size <= 4 ? VT_INT : VT_LLONG); | |
| 477 | + fieldofs[2] = (8 << 4) | (size <= 9 ? VT_BYTE : size <= 10 ? VT_SHORT : size <= 12 ? VT_INT : VT_LLONG); | |
| 478 | + } | |
| 479 | +} | |
| 480 | + | |
| 468 | 481 | ST_FUNC void gfunc_call(int nb_args) |
| 469 | 482 | { |
| 470 | − int i, align, size, aireg, afreg; | |
| 483 | + int i, align, size, areg[2]; | |
| 471 | 484 | int info[nb_args ? nb_args : 1]; |
| 472 | 485 | int stack_adj = 0, tempspace = 0, ofs, splitofs = 0; |
| 473 | − int force_stack = 0; | |
| 474 | 486 | SValue *sv; |
| 475 | 487 | Sym *sa; |
| 476 | − aireg = afreg = 0; | |
| 488 | + areg[0] = 0; /* int arg regs */ | |
| 489 | + areg[1] = 8; /* float arg regs */ | |
| 477 | 490 | sa = vtop[-nb_args].type.ref->next; |
| 478 | 491 | for (i = 0; i < nb_args; i++) { |
| 479 | − int *pareg, nregs, byref = 0, tempofs; | |
| 492 | + int nregs, byref = 0, tempofs; | |
| 480 | 493 | int prc[3], fieldofs[3]; |
| 481 | − prc[0] = 0; | |
| 482 | 494 | sv = &vtop[1 + i - nb_args]; |
| 483 | 495 | sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c |
| 484 | 496 | size = type_size(&sv->type, &align); |
| @@ -489,53 +501,43 @@ ST_FUNC void gfunc_call(int nb_args) · 4 unmodified lines | ||
| 489 | 501 | tempofs = tempspace; |
| 490 | 502 | tempspace += size; |
| 491 | 503 | size = align = 8; |
| 492 | − byref = 1; | |
| 493 | − } | |
| 494 | − if (size > 8) | |
| 495 | − nregs = 2; | |
| 496 | − else | |
| 497 | − nregs = 1; | |
| 498 | − if (!sa) { | |
| 499 | − prc[0] = nregs, prc[1] = prc[2] = RC_INT; | |
| 500 | − } else { | |
| 501 | − reg_pass(&sv->type, prc, fieldofs, 0); | |
| 502 | − if (prc[0] < 0) | |
| 503 | − prc[0] = nregs, prc[1] = prc[2] = RC_INT; | |
| 504 | + byref = 64 | (tempofs << 7); | |
| 504 | 505 | } |
| 506 | + reg_pass(&sv->type, prc, fieldofs, sa != 0); | |
| 505 | 507 | if (!sa && align == 2*XLEN && size <= 2*XLEN) |
| 506 | − aireg = (aireg + 1) & ~1; | |
| 508 | + areg[0] = (areg[0] + 1) & ~1; | |
| 507 | 509 | 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) { | |
| 510 | + if ((prc[1] == RC_INT && areg[0] >= 8) | |
| 511 | + || (prc[1] == RC_FLOAT && areg[1] >= 16) | |
| 512 | + || (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT | |
| 513 | + && areg[1] >= 15) | |
| 514 | + || (nregs == 2 && prc[1] != prc[2] | |
| 515 | + && (areg[1] >= 16 || areg[0] >= 8))) { | |
| 515 | 516 | info[i] = 32; |
| 516 | 517 | if (align < XLEN) |
| 517 | 518 | align = XLEN; |
| 518 | 519 | stack_adj += (size + align - 1) & -align; |
| 519 | − if (!sa) | |
| 520 | − force_stack = 1; | |
| 520 | + if (!sa) /* one vararg on stack forces the rest on stack */ | |
| 521 | + areg[0] = 8, areg[1] = 16; | |
| 521 | 522 | } else { |
| 522 | − if (prc[1] == RC_FLOAT) | |
| 523 | − info[i] = 8 + afreg++; | |
| 524 | − else | |
| 525 | − info[i] = aireg++; | |
| 523 | + info[i] = areg[prc[1] - 1]++; | |
| 524 | + if (!byref) | |
| 525 | + info[i] |= (fieldofs[1] & VT_BTYPE) << 12; | |
| 526 | + assert(!(fieldofs[1] >> 4)); | |
| 526 | 527 | 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; | |
| 528 | + if (prc[2] == RC_FLOAT || areg[0] < 8) | |
| 529 | + info[i] |= (1 + areg[prc[2] - 1]++) << 7; | |
| 531 | 530 | else { |
| 532 | 531 | info[i] |= 16; |
| 533 | 532 | stack_adj += 8; |
| 534 | 533 | } |
| 534 | + if (!byref) { | |
| 535 | + assert((fieldofs[2] >> 4) < 2048); | |
| 536 | + info[i] |= fieldofs[2] << (12 + 4); // includes offset | |
| 537 | + } | |
| 535 | 538 | } |
| 536 | 539 | } |
| 537 | − if (byref) | |
| 538 | − info[i] |= 64 | (tempofs << 7); | |
| 540 | + info[i] |= byref; | |
| 539 | 541 | if (sa) |
| 540 | 542 | sa = sa->next; |
| 541 | 543 | } |
| @@ -544,7 +546,7 @@ ST_FUNC void gfunc_call(int nb_args) · 2 unmodified lines | ||
| 544 | 546 | if (stack_adj + tempspace) { |
| 545 | 547 | EI(0x13, 0, 2, 2, -(stack_adj + tempspace)); // addi sp, sp, -adj |
| 546 | 548 | for (i = ofs = 0; i < nb_args; i++) { |
| 547 | − if (info[i] >= 32) { | |
| 549 | + if (info[i] & (64 | 32)) { | |
| 548 | 550 | vrotb(nb_args - i); |
| 549 | 551 | size = type_size(&vtop->type, &align); |
| 550 | 552 | if (info[i] & 64) { |
| @@ -587,26 +589,19 @@ ST_FUNC void gfunc_call(int nb_args) · 36 unmodified lines | ||
| 587 | 589 | } |
| 588 | 590 | } |
| 589 | 591 | for (i = 0; i < nb_args; i++) { |
| 590 | − int r = info[nb_args - 1 - i], r2 = r; | |
| 592 | + int ii = info[nb_args - 1 - i], r = ii, r2 = r; | |
| 591 | 593 | if (!(r & 32)) { |
| 592 | 594 | CType origtype; |
| 593 | − int prc[3], fieldofs[3], loadt; | |
| 594 | − prc[0] = 0; | |
| 595 | + int loadt; | |
| 595 | 596 | r &= 15; |
| 596 | − r2 = r2 & 64 ? 0 : r2 >> 7; | |
| 597 | + r2 = r2 & 64 ? 0 : (r2 >> 7) & 31; | |
| 598 | + assert(r2 <= 16); | |
| 597 | 599 | vrotb(i+1); |
| 598 | 600 | origtype = vtop->type; |
| 599 | 601 | size = type_size(&vtop->type, &align); |
| 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 | 602 | loadt = vtop->type.t & VT_BTYPE; |
| 608 | 603 | if (loadt == VT_STRUCT) { |
| 609 | − loadt = fieldofs[1] & VT_BTYPE; | |
| 604 | + loadt = (ii >> 12) & VT_BTYPE; | |
| 610 | 605 | } |
| 611 | 606 | if (info[nb_args - 1 - i] & 16) { |
| 612 | 607 | assert(!r2); |
| @@ -629,13 +624,13 @@ ST_FUNC void gfunc_call(int nb_args) · 16 unmodified lines | ||
| 629 | 624 | vswap(); |
| 630 | 625 | gaddrof(); |
| 631 | 626 | vtop->type = char_pointer_type; |
| 632 | − vpushi(fieldofs[2] >> 4); | |
| 627 | + vpushi(ii >> 20); | |
| 633 | 628 | gen_op('+'); |
| 634 | 629 | indir(); |
| 635 | 630 | vtop->type = origtype; |
| 636 | 631 | loadt = vtop->type.t & VT_BTYPE; |
| 637 | 632 | if (loadt == VT_STRUCT) { |
| 638 | − loadt = fieldofs[2] & VT_BTYPE; | |
| 633 | + loadt = (ii >> 16) & VT_BTYPE; | |
| 639 | 634 | } |
| 640 | 635 | save_reg_upstack(r2, 1); |
| 641 | 636 | vtop->type.t = loadt; |
| @@ -671,7 +666,7 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 29 unmodified lines | ||
| 671 | 666 | { |
| 672 | 667 | int i, addr, align, size; |
| 673 | 668 | int param_addr = 0; |
| 674 | − int aireg, afreg; | |
| 669 | + int areg[2]; | |
| 675 | 670 | Sym *sym; |
| 676 | 671 | CType *type; |
| 677 | 672 | |
| @@ -681,69 +676,51 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 3 unmodified lines | ||
| 681 | 676 | func_sub_sp_offset = ind; |
| 682 | 677 | ind += 5 * 4; |
| 683 | 678 | |
| 684 | − aireg = afreg = 0; | |
| 685 | − addr = 0; // XXX not correct | |
| 679 | + areg[0] = 0, areg[1] = 0; | |
| 680 | + addr = 0; | |
| 686 | 681 | /* if the function returns by reference, then add an |
| 687 | 682 | implicit pointer parameter */ |
| 688 | 683 | size = type_size(&func_vt, &align); |
| 689 | 684 | if (size > 2 * XLEN) { |
| 690 | 685 | loc -= 8; |
| 691 | 686 | func_vc = loc; |
| 692 | − ES(0x23, 3, 8, 10 + aireg, loc); // sd a0, loc(s0) | |
| 693 | − aireg++; | |
| 687 | + ES(0x23, 3, 8, 10 + areg[0]++, loc); // sd a0, loc(s0) | |
| 694 | 688 | } |
| 695 | 689 | /* define parameters */ |
| 696 | 690 | while ((sym = sym->next) != NULL) { |
| 697 | 691 | int byref = 0; |
| 692 | + int regcount; | |
| 693 | + int prc[3], fieldofs[3]; | |
| 698 | 694 | type = &sym->type; |
| 699 | 695 | size = type_size(type, &align); |
| 700 | 696 | if (size > 2 * XLEN) { |
| 701 | 697 | type = &char_pointer_type; |
| 702 | 698 | size = align = byref = 8; |
| 703 | 699 | } |
| 704 | − if (size > 2 * XLEN) { | |
| 705 | − from_stack: | |
| 700 | + reg_pass(type, prc, fieldofs, 1); | |
| 701 | + regcount = prc[0]; | |
| 702 | + if (areg[prc[1] - 1] >= 8 | |
| 703 | + || (regcount == 2 | |
| 704 | + && ((prc[1] == RC_FLOAT && prc[2] == RC_FLOAT && areg[1] >= 7) | |
| 705 | + || (prc[1] != prc[2] && (areg[1] >= 8 || areg[0] >= 8))))) { | |
| 706 | 706 | if (align < XLEN) |
| 707 | 707 | align = XLEN; |
| 708 | 708 | addr = (addr + align - 1) & -align; |
| 709 | 709 | param_addr = addr; |
| 710 | 710 | addr += size; |
| 711 | 711 | } else { |
| 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); | |
| 721 | − } | |
| 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))) | |
| 728 | − goto from_stack; | |
| 729 | − if (size > XLEN) | |
| 730 | − assert(regcount == 2); | |
| 731 | 712 | loc -= regcount * 8; // XXX could reserve only 'size' bytes |
| 732 | 713 | param_addr = loc; |
| 733 | 714 | for (i = 0; i < regcount; i++) { |
| 734 | − pareg = prc[1+i] == RC_INT ? &aireg : &afreg; | |
| 735 | − if (*pareg >= 8) { | |
| 715 | + if (areg[prc[1+i] - 1] >= 8) { | |
| 736 | 716 | assert(i == 1 && regcount == 2 && !(addr & 7)); |
| 737 | 717 | EI(0x03, 3, 5, 8, addr); // ld t0, addr(s0) |
| 738 | 718 | addr += 8; |
| 739 | 719 | ES(0x23, 3, 8, 5, loc + i*8); // sd t0, loc(s0) |
| 740 | − continue; | |
| 741 | − } | |
| 742 | − if (pareg == &afreg) { | |
| 743 | − //assert(type->t == VT_FLOAT || type->t == VT_DOUBLE); | |
| 744 | − ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + afreg++, loc + (fieldofs[i+1] >> 4)); // fs[wd] FAi, loc(s0) | |
| 720 | + } else if (prc[1+i] == RC_FLOAT) { | |
| 721 | + ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + areg[1]++, loc + (fieldofs[i+1] >> 4)); // fs[wd] FAi, loc(s0) | |
| 745 | 722 | } else { |
| 746 | − ES(0x23, 3, 8, 10 + aireg++, loc + i*8); // sd aX, loc(s0) // XXX | |
| 723 | + ES(0x23, 3, 8, 10 + areg[0]++, loc + i*8); // sd aX, loc(s0) // XXX | |
| 747 | 724 | } |
| 748 | 725 | } |
| 749 | 726 | } |
| @@ -754,9 +731,9 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 4 unmodified lines | ||
| 754 | 731 | func_va_list_ofs = addr; |
| 755 | 732 | num_va_regs = 0; |
| 756 | 733 | if (func_type->ref->f.func_type == FUNC_ELLIPSIS) { |
| 757 | − for (; aireg < 8; aireg++) { | |
| 734 | + for (; areg[0] < 8; areg[0]++) { | |
| 758 | 735 | num_va_regs++; |
| 759 | − ES(0x23, 3, 8, 10 + aireg, -8 + num_va_regs * 8); // sd aX, loc(s0) | |
| 736 | + ES(0x23, 3, 8, 10 + areg[0], -8 + num_va_regs * 8); // sd aX, loc(s0) | |
| 760 | 737 | } |
| 761 | 738 | } |
| 762 | 739 | } |
| @@ -764,22 +741,14 @@ ST_FUNC void gfunc_prolog(CType *func_type) · 1 unmodified line | ||
| 764 | 741 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, |
| 765 | 742 | int *ret_align, int *regsize) |
| 766 | 743 | { |
| 767 | − int align, size = type_size(vt, &align), infreg, nregs; | |
| 744 | + int align, size = type_size(vt, &align), nregs; | |
| 768 | 745 | int prc[3], fieldofs[3]; |
| 769 | 746 | *ret_align = 1; |
| 770 | 747 | *regsize = 8; |
| 771 | 748 | if (size > 16) |
| 772 | 749 | return 0; |
| 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); | |
| 780 | − } | |
| 750 | + reg_pass(vt, prc, fieldofs, 1); | |
| 781 | 751 | nregs = prc[0]; |
| 782 | − assert(nregs > 0); | |
| 783 | 752 | if (nregs == 2 && prc[1] != prc[2]) |
| 784 | 753 | return -1; /* generic code can't deal with this case */ |
| 785 | 754 | if (prc[1] == RC_FLOAT) { |
| @@ -792,22 +761,15 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, · 6 unmodified lines | ||
| 792 | 761 | ST_FUNC void arch_transfer_ret_regs(int aftercall) |
| 793 | 762 | { |
| 794 | 763 | int prc[3], fieldofs[3]; |
| 795 | − prc[0] = 0; | |
| 796 | − reg_pass(&vtop->type, prc, fieldofs, 0); | |
| 764 | + reg_pass(&vtop->type, prc, fieldofs, 1); | |
| 797 | 765 | assert(prc[0] == 2 && prc[1] != prc[2] && !(fieldofs[1] >> 4)); |
| 798 | 766 | assert(vtop->r == (VT_LOCAL | VT_LVAL)); |
| 799 | 767 | vpushv(vtop); |
| 800 | 768 | 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); | |
| 769 | + (aftercall ? store : load)(prc[1] == RC_INT ? REG_IRET : REG_FRET, vtop); | |
| 805 | 770 | vtop->c.i += fieldofs[2] >> 4; |
| 806 | 771 | vtop->type.t = fieldofs[2] & VT_BTYPE; |
| 807 | − if (aftercall) | |
| 808 | − store(prc[2] == RC_INT ? REG_IRET : REG_FRET, vtop); | |
| 809 | − else | |
| 810 | − load(prc[2] == RC_INT ? REG_IRET : REG_FRET, vtop); | |
| 772 | + (aftercall ? store : load)(prc[2] == RC_INT ? REG_IRET : REG_FRET, vtop); | |
| 811 | 773 | vtop--; |
| 812 | 774 | } |
| 813 | 775 | |
| @@ -857,11 +819,6 @@ ST_FUNC void gen_va_start(void) · 43 unmodified lines | ||
| 857 | 819 | vset(&char_pointer_type, VT_LOCAL, func_va_list_ofs); |
| 858 | 820 | } |
| 859 | 821 | |
| 860 | −ST_FUNC void gen_va_arg(CType *t) | |
| 861 | −{ | |
| 862 | − tcc_error("implement me: %s", __FUNCTION__); | |
| 863 | −} | |
| 864 | − | |
| 865 | 822 | ST_FUNC void gen_fill_nops(int bytes) |
| 866 | 823 | { |
| 867 | 824 | if ((bytes & 3)) |
| @@ -1606,7 +1606,6 @@ ST_FUNC void gen_cvt_sxtw(void); · 1605 unmodified lines | ||
| 1606 | 1606 | ST_FUNC void gen_opl(int op); |
| 1607 | 1607 | //ST_FUNC void gfunc_return(CType *func_type); |
| 1608 | 1608 | ST_FUNC void gen_va_start(void); |
| 1609 | −ST_FUNC void gen_va_arg(CType *t); | |
| 1610 | 1609 | ST_FUNC void arch_transfer_ret_regs(int); |
| 1611 | 1610 | #endif |
| 1612 | 1611 | /* ------------ c67-gen.c ------------ */ |