Skip to content

Commit 7f34d48

Browse files
committed
RISCV64: Add build infra and initial port
Contributed by infiWang.
1 parent a42c79a commit 7f34d48

17 files changed

+5664
-9
lines changed

cmake/LuaJITUtils.cmake

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ endfunction()
3535

3636
function(LuaJITArch outvar testarch)
3737
# XXX: Please do not change the order of the architectures.
38-
foreach(TRYARCH X64 X86 ARM64 ARM PPC MIPS64 MIPS)
38+
foreach(TRYARCH X64 X86 ARM64 ARM PPC MIPS64 MIPS RISCV64)
3939
string(FIND "${testarch}" "LJ_TARGET_${TRYARCH}" FOUND)
4040
# FIXME: <continue> is introduced in CMake version 3.2, but
4141
# the minimum required version now is 3.1. This is not such a

src/Makefile.original

+8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ CCOPT_arm=
5353
CCOPT_arm64=
5454
CCOPT_ppc=
5555
CCOPT_mips=
56+
CCOPT_riscv64=
5657
#
5758
CCDEBUG=
5859
# Uncomment the next line to generate debug information:
@@ -276,6 +277,9 @@ ifneq (,$(findstring LJ_TARGET_MIPS ,$(TARGET_TESTARCH)))
276277
else
277278
TARGET_LJARCH= mips
278279
endif
280+
else
281+
ifneq (,$(findstring LJ_TARGET_RISCV64 ,$(TARGET_TESTARCH)))
282+
TARGET_LJARCH= riscv64
279283
else
280284
$(error Unsupported target architecture)
281285
endif
@@ -284,6 +288,7 @@ endif
284288
endif
285289
endif
286290
endif
291+
endif
287292

288293
ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH)))
289294
TARGET_SYS= PS3
@@ -478,6 +483,9 @@ ifeq (ppc,$(TARGET_LJARCH))
478483
DASM_ARCH= ppc64
479484
endif
480485
endif
486+
ifneq (,$(findstring LJ_TARGET_RISCV64 ,$(TARGET_TESTARCH)))
487+
DASM_AFLAGS+= -D RISCV64
488+
endif
481489
endif
482490
endif
483491

src/host/buildvm.c

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
6969
#include "../dynasm/dasm_ppc.h"
7070
#elif LJ_TARGET_MIPS
7171
#include "../dynasm/dasm_mips.h"
72+
#elif LJ_TARGET_RISCV64
73+
#include "../dynasm/dasm_riscv.h"
7274
#else
7375
#error "No support for this architecture (yet)"
7476
#endif

src/host/buildvm_asm.c

+31
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,34 @@ static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
164164
"Error: unsupported opcode %08x for %s symbol relocation.\n",
165165
ins, sym);
166166
exit(1);
167+
#elif LJ_TARGET_RISCV64
168+
if ((ins & 0x7f) == 0x17u) {
169+
fprintf(ctx->fp, "\tauipc x%d, %s\n", (ins >> 7) & 31, sym);
170+
} else if ((ins & 0x7f) == 0x67u) {
171+
fprintf(ctx->fp, "\tjalr x%d, x%d, %s\n", (ins >> 7) & 31, (ins >> 15) & 31, sym);
172+
} else if ((ins & 0x7f) == 0x6fu) {
173+
fprintf(ctx->fp, "\tjal x%d, %s\n", (ins >> 7) & 31, sym);
174+
} else if ((ins & 0x7f) == 0x03u) {
175+
uint8_t funct3 = (ins >> 12) & 7;
176+
uint8_t rd = (ins >> 7) & 31, rs1 = (ins >> 15) & 31;
177+
switch (funct3) {
178+
case 0: fprintf(ctx->fp, "\tlb"); break;
179+
case 1: fprintf(ctx->fp, "\tlh"); break;
180+
case 2: fprintf(ctx->fp, "\tlw"); break;
181+
case 3: fprintf(ctx->fp, "\tld"); break;
182+
case 4: fprintf(ctx->fp, "\tlbu"); break;
183+
case 5: fprintf(ctx->fp, "\tlhu"); break;
184+
case 6: fprintf(ctx->fp, "\tlwu"); break;
185+
default: goto rv_reloc_err;
186+
}
187+
fprintf(ctx->fp, " x%d, %s(x%d)\n", rd, sym, rs1);
188+
} else {
189+
rv_reloc_err:
190+
fprintf(stderr,
191+
"Error: unsupported opcode %08x for %s symbol relocation.\n",
192+
ins, sym);
193+
exit(1);
194+
}
167195
#else
168196
#error "missing relocation support for this architecture"
169197
#endif
@@ -254,6 +282,9 @@ void emit_asm(BuildCtx *ctx)
254282
fprintf(ctx->fp, "\t.abiversion 2\n");
255283
#endif
256284
fprintf(ctx->fp, "\t.text\n");
285+
#if LJ_TARGET_RISCV64
286+
fprintf(ctx->fp, ".option arch, -c\n.option norelax\n");
287+
#endif
257288
emit_asm_align(ctx, 4);
258289

259290
#if LJ_TARGET_PS3

src/jit/bcsave.lua

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ local map_arch = {
7979
mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
8080
mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
8181
mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
82+
riscv64 = { e = "le", b = 64, m = 243, f = 0x00000004, },
8283
}
8384

8485
local map_os = {

src/lib_jit.c

+2
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,8 @@ static uint32_t jit_cpudetect(lua_State *L)
728728
}
729729
#endif
730730
#endif
731+
#elif LJ_TARGET_RISCV64
732+
/* No optional CPU features to detect (for now). */
731733
#else
732734
#error "Missing CPU detection for this architecture"
733735
#endif

src/lj_alloc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ static void *CALL_MREMAP_(void *ptr, size_t osz, size_t nsz, int flags)
379379
#define CALL_MREMAP(addr, osz, nsz, mv) CALL_MREMAP_((addr), (osz), (nsz), (mv))
380380
#define CALL_MREMAP_NOMOVE 0
381381
#define CALL_MREMAP_MAYMOVE 1
382-
#if LJ_64 && (!LJ_GC64 || LJ_TARGET_ARM64)
382+
#if LJ_64 && (!LJ_GC64 || LJ_TARGET_ARM64 || LJ_TARGET_RISCV64)
383383
#define CALL_MREMAP_MV CALL_MREMAP_NOMOVE
384384
#else
385385
#define CALL_MREMAP_MV CALL_MREMAP_MAYMOVE

src/lj_arch.h

+27
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#define LUAJIT_ARCH_mips32 6
3030
#define LUAJIT_ARCH_MIPS64 7
3131
#define LUAJIT_ARCH_mips64 7
32+
#define LUAJIT_ARCH_riscv64 8
33+
#define LUAJIT_ARCH_RISCV64 8
3234

3335
/* Target OS. */
3436
#define LUAJIT_OS_OTHER 0
@@ -55,6 +57,8 @@
5557
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS64
5658
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
5759
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS32
60+
#elif (defined(__riscv) || defined(__riscv__)) && __riscv_xlen == 64
61+
#define LUAJIT_TARGET LUAJIT_ARCH_RISCV64
5862
#else
5963
#error "No support for this architecture (yet)"
6064
#endif
@@ -421,6 +425,25 @@
421425
#define LJ_ARCH_NOMEMPROF 1
422426
#define LJ_ARCH_NOSYSPROF 1
423427

428+
#elif LUAJIT_TARGET == LUAJIT_ARCH_RISCV64
429+
430+
#define LJ_ARCH_NAME "riscv64"
431+
#define LJ_ARCH_BITS 64
432+
#define LJ_ARCH_ENDIAN LUAJIT_LE /* Forget about BE for now */
433+
#define LJ_TARGET_RISCV64 1
434+
#define LJ_TARGET_GC64 1
435+
#define LJ_TARGET_EHRETREG 10
436+
#define LJ_TARGET_EHRAREG 1
437+
#define LJ_TARGET_JUMPRANGE 30 /* JAL +-2^20 = +-1MB,\
438+
AUIPC+JALR +-2^31 = +-2GB, leave 1 bit to avoid AUIPC corner case */
439+
#define LJ_TARGET_MASKSHIFT 1
440+
#define LJ_TARGET_MASKROT 1
441+
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
442+
#define LJ_ARCH_NOJIT 1 /* NYI */
443+
444+
#define LJ_ARCH_NOMEMPROF 1
445+
#define LJ_ARCH_NOSYSPROF 1
446+
424447
#else
425448
#error "No target architecture defined"
426449
#endif
@@ -503,6 +526,10 @@
503526
/* MIPS32ON64 aka n32 ABI support might be desirable, but difficult. */
504527
#error "Only n64 ABI supported for MIPS64"
505528
#endif
529+
#elif LJ_TARGET_RISCV64
530+
#if !defined(__riscv_float_abi_double)
531+
#error "Only RISC-V 64 double float supported for now"
532+
#endif
506533
#endif
507534
#endif
508535

src/lj_ccall.c

+154-2
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,97 @@
574574
goto done; \
575575
}
576576

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+
577668
#else
578669
#error "Missing calling convention definitions for this architecture"
579670
#endif
@@ -888,6 +979,51 @@ void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp, int ft)
888979

889980
#endif
890981

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+
8911027
/* -- Common C call handling ---------------------------------------------- */
8921028

8931029
/* Infer the destination CTypeID for a vararg argument. */
@@ -934,6 +1070,10 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
9341070
#endif
9351071
#endif
9361072

1073+
#if LJ_TARGET_RISCV64
1074+
int nff = 0;
1075+
#endif
1076+
9371077
/* Clear unused regs to get some determinism in case of misdeclaration. */
9381078
memset(cc->gpr, 0, sizeof(cc->gpr));
9391079
#if CCALL_NUM_FPR
@@ -1059,7 +1199,11 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
10591199
if (isfp && d->size == sizeof(float))
10601200
((float *)dp)[1] = ((float *)dp)[0]; /* Floats occupy high slot. */
10611201
#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
10631207
if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info)
10641208
#if LJ_TARGET_MIPS64
10651209
|| (isfp && nsp == 0)
@@ -1089,13 +1233,21 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
10891233
CTSize i = (sz >> 2) - 1;
10901234
do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
10911235
}
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+
}
10921244
#else
10931245
UNUSED(isfp);
10941246
#endif
10951247
}
10961248
if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */
10971249

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
10991251
cc->nfpr = nfpr; /* Required for vararg functions. */
11001252
#endif
11011253
cc->nsp = nsp;

0 commit comments

Comments
 (0)