long double on risc-v is 128bit, but there are no registers for that type (without the Q ISA extension). They are passed like two 64bit integers values (with an exception for varargs, where it's an aligned register pair). This all requires some hacks in generic code as otherwise RC_FLOAT regs are tried for holding values of long double type, but we need a RC_INT register pair. This really could all use some cleanup for all archs. This doesn't implement any conversions of operations for long double, but it's enough to get 70_floating_point_literals working.
Unified · Split
| @@ -345,24 +345,45 @@ ST_FUNC void gfunc_call(int nb_args) · 344 unmodified lines | ||
| 345 | 345 | int i, align, size, aireg, afreg; |
| 346 | 346 | int info[nb_args ? nb_args : 1]; |
| 347 | 347 | int stack_adj = 0, ofs; |
| 348 | + int force_stack = 0; | |
| 348 | 349 | SValue *sv; |
| 349 | 350 | Sym *sa; |
| 350 | 351 | aireg = afreg = 0; |
| 351 | 352 | sa = vtop[-nb_args].type.ref->next; |
| 352 | 353 | for (i = 0; i < nb_args; i++) { |
| 353 | − int *pareg; | |
| 354 | + int *pareg, nregs, infreg = 0; | |
| 354 | 355 | sv = &vtop[1 + i - nb_args]; |
| 355 | 356 | sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c |
| 356 | 357 | size = type_size(&sv->type, &align); |
| 357 | − if (size > 8 || ((sv->type.t & VT_BTYPE) == VT_STRUCT)) | |
| 358 | + if ((size > 8 && ((sv->type.t & VT_BTYPE) != VT_LDOUBLE)) | |
| 359 | + || ((sv->type.t & VT_BTYPE) == VT_STRUCT)) | |
| 358 | 360 | tcc_error("unimp: call arg %d wrong type", nb_args - i); |
| 359 | − pareg = sa && is_float(sv->type.t) ? &afreg : &aireg; | |
| 360 | − if (*pareg < 8) { | |
| 361 | − info[i] = *pareg + (sa && is_float(sv->type.t) ? 8 : 0); | |
| 361 | + nregs = 1; | |
| 362 | + if ((sv->type.t & VT_BTYPE) == VT_LDOUBLE) { | |
| 363 | + infreg = 0, nregs = 2; | |
| 364 | + if (!sa) { | |
| 365 | + aireg = (aireg + 1) & ~1; | |
| 366 | + } | |
| 367 | + } else | |
| 368 | + infreg = sa && is_float(sv->type.t); | |
| 369 | + pareg = infreg ? &afreg : &aireg; | |
| 370 | + if ((*pareg < 8) && !force_stack) { | |
| 371 | + info[i] = *pareg + (infreg ? 8 : 0); | |
| 362 | 372 | (*pareg)++; |
| 373 | + if (nregs == 1) | |
| 374 | + ; | |
| 375 | + else if (*pareg < 8) | |
| 376 | + (*pareg)++; | |
| 377 | + else { | |
| 378 | + info[i] |= 16; | |
| 379 | + stack_adj += 8; | |
| 380 | + tcc_error("unimp: param passing half in reg, half on stack"); | |
| 381 | + } | |
| 363 | 382 | } else { |
| 364 | − info[i] = 16; | |
| 383 | + info[i] = 32; | |
| 365 | 384 | stack_adj += (size + align - 1) & -align; |
| 385 | + if (!sa) | |
| 386 | + force_stack = 1; | |
| 366 | 387 | } |
| 367 | 388 | if (sa) |
| 368 | 389 | sa = sa->next; |
| @@ -371,7 +392,7 @@ ST_FUNC void gfunc_call(int nb_args) · 2 unmodified lines | ||
| 371 | 392 | if (stack_adj) { |
| 372 | 393 | EI(0x13, 0, 2, 2, -stack_adj); // addi sp, sp, -adj |
| 373 | 394 | for (i = ofs = 0; i < nb_args; i++) { |
| 374 | − if (1 && info[i] >= 16) { | |
| 395 | + if (1 && info[i] >= 32) { | |
| 375 | 396 | vrotb(nb_args - i); |
| 376 | 397 | size = type_size(&vtop->type, &align); |
| 377 | 398 | /* Once we support offseted regs we can do this: |
| @@ -393,9 +414,20 @@ ST_FUNC void gfunc_call(int nb_args) · 15 unmodified lines | ||
| 393 | 414 | } |
| 394 | 415 | for (i = 0; i < nb_args; i++) { |
| 395 | 416 | int r = info[nb_args - 1 - i]; |
| 396 | − if (r < 16) { | |
| 417 | + if (r < 32) { | |
| 418 | + r &= 15; | |
| 397 | 419 | vrotb(i+1); |
| 398 | 420 | gv(r < 8 ? RC_R(r) : RC_F(r - 8)); |
| 421 | + if (vtop->r2 < VT_CONST) { | |
| 422 | + assert((vtop->type.t & VT_BTYPE) == VT_LDOUBLE); | |
| 423 | + assert(vtop->r < 7); | |
| 424 | + if (vtop->r2 != 1 + vtop->r) { | |
| 425 | + /* XXX we'd like to have 'gv' move directly into | |
| 426 | + the right class instead of us fixing it up. */ | |
| 427 | + EI(0x13, 0, ireg(vtop->r) + 1, ireg(vtop->r2), 0); // mv Ra+1, RR2 | |
| 428 | + vtop->r2 = 1 + vtop->r; | |
| 429 | + } | |
| 430 | + } | |
| 399 | 431 | vrott(i+1); |
| 400 | 432 | } |
| 401 | 433 | } |
| @@ -1548,6 +1548,11 @@ ST_FUNC int gv(int rc) · 1547 unmodified lines | ||
| 1548 | 1548 | if (vtop->r & VT_MUSTBOUND) |
| 1549 | 1549 | gbound(); |
| 1550 | 1550 | #endif |
| 1551 | +#ifdef TCC_TARGET_RISCV64 | |
| 1552 | + /* XXX mega hack */ | |
| 1553 | + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && rc == RC_FLOAT) | |
| 1554 | + rc = RC_INT; | |
| 1555 | +#endif | |
| 1551 | 1556 | |
| 1552 | 1557 | r = vtop->r & VT_VALMASK; |
| 1553 | 1558 | rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; |
| @@ -1568,7 +1573,10 @@ ST_FUNC int gv(int rc) · 14 unmodified lines | ||
| 1568 | 1573 | if (r >= VT_CONST |
| 1569 | 1574 | || (vtop->r & VT_LVAL) |
| 1570 | 1575 | || !(reg_classes[r] & rc) |
| 1571 | −#if PTR_SIZE == 8 | |
| 1576 | +#ifdef TCC_TARGET_RISCV64 | |
| 1577 | + || ((vtop->type.t & VT_BTYPE) == VT_QLONG && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2))) | |
| 1578 | + || ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE && (vtop->r2 >= NB_REGS || !(reg_classes[vtop->r2] & rc2))) | |
| 1579 | +#elif PTR_SIZE == 8 | |
| 1572 | 1580 | || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) |
| 1573 | 1581 | || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) |
| 1574 | 1582 | #else |
| @@ -1577,7 +1585,10 @@ ST_FUNC int gv(int rc) · 2 unmodified lines | ||
| 1577 | 1585 | ) |
| 1578 | 1586 | { |
| 1579 | 1587 | r = get_reg(rc); |
| 1580 | −#if PTR_SIZE == 8 | |
| 1588 | +#ifdef TCC_TARGET_RISCV64 | |
| 1589 | + if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)) { | |
| 1590 | + int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG; | |
| 1591 | +#elif PTR_SIZE == 8 | |
| 1581 | 1592 | if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { |
| 1582 | 1593 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
| 1583 | 1594 | #else |
| @@ -1708,6 +1719,9 @@ static int rc_fret(int t) · 124 unmodified lines | ||
| 1708 | 1719 | if (t == VT_LDOUBLE) { |
| 1709 | 1720 | return RC_ST0; |
| 1710 | 1721 | } |
| 1722 | +#elif defined TCC_TARGET_RISCV64 | |
| 1723 | + if (t == VT_LDOUBLE) | |
| 1724 | + return RC_IRET; | |
| 1711 | 1725 | #endif |
| 1712 | 1726 | return RC_FRET; |
| 1713 | 1727 | } |
| @@ -1720,6 +1734,9 @@ static int reg_fret(int t) · 6 unmodified lines | ||
| 1720 | 1734 | if (t == VT_LDOUBLE) { |
| 1721 | 1735 | return TREG_ST0; |
| 1722 | 1736 | } |
| 1737 | +#elif defined TCC_TARGET_RISCV64 | |
| 1738 | + if (t == VT_LDOUBLE) | |
| 1739 | + return REG_IRET; | |
| 1723 | 1740 | #endif |
| 1724 | 1741 | return REG_FRET; |
| 1725 | 1742 | } |
| @@ -1797,6 +1814,9 @@ static void gv_dup(void) · 71 unmodified lines | ||
| 1797 | 1814 | if ((t & VT_BTYPE) == VT_LDOUBLE) { |
| 1798 | 1815 | rc = RC_ST0; |
| 1799 | 1816 | } |
| 1817 | +#elif defined TCC_TARGET_RISCV64 | |
| 1818 | + if ((t & VT_BTYPE) == VT_LDOUBLE) | |
| 1819 | + rc = RC_INT; | |
| 1800 | 1820 | #endif |
| 1801 | 1821 | sv.type.t = t; |
| 1802 | 1822 | } |
| @@ -3403,6 +3423,9 @@ ST_FUNC void vstore(void) · 1600 unmodified lines | ||
| 3403 | 3423 | } else if ((ft & VT_BTYPE) == VT_QFLOAT) { |
| 3404 | 3424 | rc = RC_FRET; |
| 3405 | 3425 | } |
| 3426 | +#elif defined TCC_TARGET_RISCV64 | |
| 3427 | + if (dbt == VT_LDOUBLE) | |
| 3428 | + rc = RC_INT; | |
| 3406 | 3429 | #endif |
| 3407 | 3430 | } |
| 3408 | 3431 | r = gv(rc); /* generate value */ |
| @@ -3421,7 +3444,10 @@ ST_FUNC void vstore(void) · 12 unmodified lines | ||
| 3421 | 3444 | vtop[-1].r = t | VT_LVAL; |
| 3422 | 3445 | } |
| 3423 | 3446 | /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ |
| 3424 | −#if PTR_SIZE == 8 | |
| 3447 | +#ifdef TCC_TARGET_RISCV64 | |
| 3448 | + if (dbt == VT_QLONG || dbt == VT_LDOUBLE) { | |
| 3449 | + int addr_type = VT_LLONG, load_size = 8, load_type = VT_LLONG; | |
| 3450 | +#elif PTR_SIZE == 8 | |
| 3425 | 3451 | if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { |
| 3426 | 3452 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
| 3427 | 3453 | #else |
| @@ -5743,6 +5769,9 @@ static void expr_cond(void) · 2315 unmodified lines | ||
| 5743 | 5769 | if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 5744 | 5770 | rc = RC_ST0; |
| 5745 | 5771 | } |
| 5772 | +#elif defined TCC_TARGET_RISCV64 | |
| 5773 | + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) | |
| 5774 | + rc = RC_INT; | |
| 5746 | 5775 | #endif |
| 5747 | 5776 | } |
| 5748 | 5777 | gv(rc); |
| @@ -5914,6 +5943,9 @@ static void expr_cond(void) · 165 unmodified lines | ||
| 5914 | 5943 | if ((type.t & VT_BTYPE) == VT_LDOUBLE) { |
| 5915 | 5944 | rc = RC_ST0; |
| 5916 | 5945 | } |
| 5946 | +#elif defined TCC_TARGET_RISCV64 | |
| 5947 | + if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) | |
| 5948 | + rc = RC_INT; | |
| 5917 | 5949 | #endif |
| 5918 | 5950 | } else if ((type.t & VT_BTYPE) == VT_LLONG) { |
| 5919 | 5951 | /* for long longs, we use fixed registers to avoid having |