|
574 | 574 | goto done; \
|
575 | 575 | }
|
576 | 576 |
|
| 577 | +#elif LJ_TARGET_RISCV64 |
| 578 | +/* -- RISC-V lp64d calling conventions ------------------------------------ */ |
| 579 | + |
| 580 | +#define CCALL_HANDLE_STRUCTRET \ |
| 581 | + /* Return structs of size > 16 by reference. */ \ |
| 582 | + cc->retref = !(sz <= 16); \ |
| 583 | + if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; |
| 584 | + |
| 585 | +#define CCALL_HANDLE_STRUCTRET2 \ |
| 586 | + unsigned int cl = ccall_classify_struct(cts, ctr); \ |
| 587 | + if ((cl & 4) && (cl >> 8) <= 2) { \ |
| 588 | + CTSize i = (cl >> 8) - 1; \ |
| 589 | + do { ((float *)dp)[i] = cc->fpr[i].f; } while (i--); \ |
| 590 | + } else { \ |
| 591 | + if (cl > 1) { \ |
| 592 | + sp = (uint8_t *)&cc->fpr[0]; \ |
| 593 | + if ((cl >> 8) > 2) \ |
| 594 | + sp = (uint8_t *)&cc->gpr[0]; \ |
| 595 | + } \ |
| 596 | + memcpy(dp, sp, ctr->size); \ |
| 597 | + } \ |
| 598 | + |
| 599 | +#define CCALL_HANDLE_COMPLEXRET \ |
| 600 | + /* Complex values are returned in 1 or 2 FPRs. */ \ |
| 601 | + cc->retref = 0; |
| 602 | + |
| 603 | +#define CCALL_HANDLE_COMPLEXRET2 \ |
| 604 | + if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPRs. */ \ |
| 605 | + ((float *)dp)[0] = cc->fpr[0].f; \ |
| 606 | + ((float *)dp)[1] = cc->fpr[1].f; \ |
| 607 | + } else { /* Copy complex double from FPRs. */ \ |
| 608 | + ((double *)dp)[0] = cc->fpr[0].d; \ |
| 609 | + ((double *)dp)[1] = cc->fpr[1].d; \ |
| 610 | + } |
| 611 | + |
| 612 | +#define CCALL_HANDLE_COMPLEXARG \ |
| 613 | + /* Pass long double complex by reference. */ \ |
| 614 | + if (sz == 2*sizeof(long double)) { \ |
| 615 | + rp = cdataptr(lj_cdata_new(cts, did, sz)); \ |
| 616 | + sz = CTSIZE_PTR; \ |
| 617 | + } \ |
| 618 | + /* Pass complex in two FPRs or on stack. */ \ |
| 619 | + else if (sz == 2*sizeof(float)) { \ |
| 620 | + isfp = 2; \ |
| 621 | + sz = 2*CTSIZE_PTR; \ |
| 622 | + } else { \ |
| 623 | + isfp = 1; \ |
| 624 | + sz = 2*CTSIZE_PTR; \ |
| 625 | + } |
| 626 | + |
| 627 | +#define CCALL_HANDLE_RET \ |
| 628 | + if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ |
| 629 | + sp = (uint8_t *)&cc->fpr[0].f; |
| 630 | + |
| 631 | +#define CCALL_HANDLE_STRUCTARG \ |
| 632 | + /* Pass structs of size >16 by reference. */ \ |
| 633 | + unsigned int cl = ccall_classify_struct(cts, d); \ |
| 634 | + nff = cl >> 8; \ |
| 635 | + if (sz > 16) { \ |
| 636 | + rp = cdataptr(lj_cdata_new(cts, did, sz)); \ |
| 637 | + sz = CTSIZE_PTR; \ |
| 638 | + } \ |
| 639 | + /* Pass struct in FPRs. */ \ |
| 640 | + if (cl > 1) { \ |
| 641 | + isfp = (cl & 4) ? 2 : 1; \ |
| 642 | + } |
| 643 | + |
| 644 | + |
| 645 | +#define CCALL_HANDLE_REGARG \ |
| 646 | + if (isfp && (!isva)) { /* Try to pass argument in FPRs. */ \ |
| 647 | + int n2 = ctype_isvector(d->info) ? 1 : \ |
| 648 | + isfp == 1 ? n : 2; \ |
| 649 | + if (nfpr + n2 <= CCALL_NARG_FPR && nff <= 2) { \ |
| 650 | + dp = &cc->fpr[nfpr]; \ |
| 651 | + nfpr += n2; \ |
| 652 | + goto done; \ |
| 653 | + } else { \ |
| 654 | + if (ngpr + n2 <= maxgpr) { \ |
| 655 | + dp = &cc->gpr[ngpr]; \ |
| 656 | + ngpr += n2; \ |
| 657 | + goto done; \ |
| 658 | + } \ |
| 659 | + } \ |
| 660 | + } else { /* Try to pass argument in GPRs. */ \ |
| 661 | + if (ngpr + n <= maxgpr) { \ |
| 662 | + dp = &cc->gpr[ngpr]; \ |
| 663 | + ngpr += n; \ |
| 664 | + goto done; \ |
| 665 | + } \ |
| 666 | + } |
| 667 | + |
577 | 668 | #else
|
578 | 669 | #error "Missing calling convention definitions for this architecture"
|
579 | 670 | #endif
|
@@ -888,6 +979,51 @@ void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp, int ft)
|
888 | 979 |
|
889 | 980 | #endif
|
890 | 981 |
|
| 982 | +/* -- RISC-V ABI struct classification ---------------------------- */ |
| 983 | + |
| 984 | +#if LJ_TARGET_RISCV64 |
| 985 | + |
| 986 | +static unsigned int ccall_classify_struct(CTState *cts, CType *ct) |
| 987 | +{ |
| 988 | + CTSize sz = ct->size; |
| 989 | + unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); |
| 990 | + while (ct->sib) { |
| 991 | + CType *sct; |
| 992 | + ct = ctype_get(cts, ct->sib); |
| 993 | + if (ctype_isfield(ct->info)) { |
| 994 | + sct = ctype_rawchild(cts, ct); |
| 995 | + if (ctype_isfp(sct->info)) { |
| 996 | + r |= sct->size; |
| 997 | + if (!isu) n++; else if (n == 0) n = 1; |
| 998 | + } else if (ctype_iscomplex(sct->info)) { |
| 999 | + r |= (sct->size >> 1); |
| 1000 | + if (!isu) n += 2; else if (n < 2) n = 2; |
| 1001 | + } else if (ctype_isstruct(sct->info)) { |
| 1002 | + goto substruct; |
| 1003 | + } else { |
| 1004 | + goto noth; |
| 1005 | + } |
| 1006 | + } else if (ctype_isbitfield(ct->info)) { |
| 1007 | + goto noth; |
| 1008 | + } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { |
| 1009 | + sct = ctype_rawchild(cts, ct); |
| 1010 | + substruct: |
| 1011 | + if (sct->size > 0) { |
| 1012 | + unsigned int s = ccall_classify_struct(cts, sct); |
| 1013 | + if (s <= 1) goto noth; |
| 1014 | + r |= (s & 255); |
| 1015 | + if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8); |
| 1016 | + } |
| 1017 | + } |
| 1018 | + } |
| 1019 | + if ((r == 4 || r == 8) && n <= 4) |
| 1020 | + return r + (n << 8); |
| 1021 | +noth: /* Not a homogeneous float/double aggregate. */ |
| 1022 | + return (sz <= 16); /* Return structs of size <= 16 in GPRs. */ |
| 1023 | +} |
| 1024 | + |
| 1025 | +#endif |
| 1026 | + |
891 | 1027 | /* -- Common C call handling ---------------------------------------------- */
|
892 | 1028 |
|
893 | 1029 | /* Infer the destination CTypeID for a vararg argument. */
|
@@ -934,6 +1070,10 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
|
934 | 1070 | #endif
|
935 | 1071 | #endif
|
936 | 1072 |
|
| 1073 | +#if LJ_TARGET_RISCV64 |
| 1074 | + int nff = 0; |
| 1075 | +#endif |
| 1076 | + |
937 | 1077 | /* Clear unused regs to get some determinism in case of misdeclaration. */
|
938 | 1078 | memset(cc->gpr, 0, sizeof(cc->gpr));
|
939 | 1079 | #if CCALL_NUM_FPR
|
@@ -1059,7 +1199,11 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
|
1059 | 1199 | if (isfp && d->size == sizeof(float))
|
1060 | 1200 | ((float *)dp)[1] = ((float *)dp)[0]; /* Floats occupy high slot. */
|
1061 | 1201 | #endif
|
1062 |
| -#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE) |
| 1202 | +#if LJ_TARGET_RISCV64 |
| 1203 | + if (isfp && d->size == sizeof(float)) |
| 1204 | + ((uint32_t *)dp)[1] = 0xffffffffu; /* Float NaN boxing */ |
| 1205 | +#endif |
| 1206 | +#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE) || LJ_TARGET_RISCV64 |
1063 | 1207 | if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info)
|
1064 | 1208 | #if LJ_TARGET_MIPS64
|
1065 | 1209 | || (isfp && nsp == 0)
|
@@ -1089,13 +1233,21 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
|
1089 | 1233 | CTSize i = (sz >> 2) - 1;
|
1090 | 1234 | do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
|
1091 | 1235 | }
|
| 1236 | +#elif LJ_TARGET_RISCV64 |
| 1237 | + if (isfp == 2 && nff <= 2) { |
| 1238 | + /* Split complex float into separate registers. */ |
| 1239 | + CTSize i = (sz >> 2) - 1; |
| 1240 | + do { |
| 1241 | + ((uint64_t *)dp)[i] = 0xffffffff00000000ul | ((uint32_t *)dp)[i]; |
| 1242 | + } while (i--); |
| 1243 | + } |
1092 | 1244 | #else
|
1093 | 1245 | UNUSED(isfp);
|
1094 | 1246 | #endif
|
1095 | 1247 | }
|
1096 | 1248 | if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
|
1097 | 1249 |
|
1098 |
| -#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP) |
| 1250 | +#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP) || LJ_TARGET_RISCV64 |
1099 | 1251 | cc->nfpr = nfpr; /* Required for vararg functions. */
|
1100 | 1252 | #endif
|
1101 | 1253 | cc->nsp = nsp;
|
|
0 commit comments