diff --git a/src/Makefile b/src/Makefile index 4e479ae5..6d4b33e0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -581,6 +581,14 @@ endif endif endif +ifeq (arm64,$(TARGET_LJARCH)) + GENLIBBC_FLAGS= --arm64 + LIBBC_H= host/buildvm_libbc_arm64.h +else + GENLIBBC_FLAGS= + LIBBC_H= host/buildvm_libbc.h +endif + Q= @ E= @echo #Q= @@ -600,7 +608,7 @@ clean: $(HOST_RM) $(ALL_RM) libbc: - ./$(LUAJIT_T) host/genlibbc.lua -o host/buildvm_libbc.h $(LJLIB_C) + ./$(LUAJIT_T) host/genlibbc.lua $(GENLIBBC_FLAGS) -o $(LIBBC_H) $(LJLIB_C) $(MAKE) all depend: diff --git a/src/host/buildvm_lib.c b/src/host/buildvm_lib.c index 1adc3cbd..0b892abb 100644 --- a/src/host/buildvm_lib.c +++ b/src/host/buildvm_lib.c @@ -7,7 +7,11 @@ #include "lj_obj.h" #include "lj_bc.h" #include "lj_lib.h" +#if LJ_TARGET_ARM64 +#include "buildvm_libbc_arm64.h" +#else #include "buildvm_libbc.h" +#endif /* Context for library definitions. */ static uint8_t obuf[8192]; @@ -385,6 +389,8 @@ void emit_lib(BuildCtx *ctx) ok = LJ_HASJIT; else if (!strcmp(buf, "#if LJ_HASFFI\n")) ok = LJ_HASFFI; + else if (!strcmp(buf, "#if LJ_TARGET_ARM64\n")) + ok = (LUAJIT_ARCH_ARM64 == LUAJIT_TARGET); if (!ok) { int lvl = 1; while (fgets(buf, sizeof(buf), fp) != NULL) { diff --git a/src/host/buildvm_libbc_arm64.h b/src/host/buildvm_libbc_arm64.h new file mode 100644 index 00000000..e716801c --- /dev/null +++ b/src/host/buildvm_libbc_arm64.h @@ -0,0 +1,30 @@ +/* This is a generated file. DO NOT EDIT! */ + +static const int libbc_endian = 0; + +static const uint8_t libbc_code[] = { +0,1,2,0,0,1,2,24,1,0,0,76,1,2,0,241,135,158,166,3,220,203,178,130,4,0,1,2,0, +0,1,2,24,1,0,0,76,1,2,0,243,244,148,165,20,198,190,199,252,3,0,1,2,0,0,0,3, +16,0,6,0,21,1,0,0,76,1,2,0,0,2,10,0,0,0,15,16,0,13,0,16,1,10,0,41,2,1,0,21, +3,0,0,41,4,1,0,77,2,8,128,18,6,1,0,18,8,5,0,59,9,5,0,66,6,3,2,10,6,0,0,88,7, +1,128,76,6,2,0,79,2,248,127,75,0,1,0,0,2,11,0,0,0,16,16,0,13,0,16,1,10,0,43, +2,0,0,18,3,0,0,41,4,0,0,88,5,7,128,18,7,1,0,18,9,5,0,18,10,6,0,66,7,3,2,10, +7,0,0,88,8,1,128,76,7,2,0,70,5,3,3,82,5,247,127,75,0,1,0,0,1,2,0,0,0,3,16,0, +13,0,21,1,0,0,76,1,2,0,0,2,10,0,0,2,30,16,0,13,0,21,2,0,0,11,1,0,0,88,3,7,128, +8,2,0,0,88,3,23,128,59,3,2,0,43,4,0,0,64,4,2,0,76,3,2,0,88,3,18,128,16,1,15, +0,41,3,1,0,3,3,1,0,88,3,14,128,3,1,2,0,88,3,12,128,59,3,1,0,22,4,1,1,18,5,2, +0,41,6,1,0,77,4,4,128,23,8,1,7,59,9,7,0,64,9,8,0,79,4,252,127,43,4,0,0,64,4, +2,0,76,3,2,0,75,0,1,0,0,2,0 +}; + +static const struct { const char *name; int ofs; } libbc_map[] = { +{"math_deg",0}, +{"math_rad",25}, +{"string_len",50}, +{"table_foreachi",69}, +{"table_foreach",136}, +{"table_getn",207}, +{"table_remove",226}, +{NULL,355} +}; + diff --git a/src/host/genlibbc.lua b/src/host/genlibbc.lua index 7a17a3d0..662bd369 100644 --- a/src/host/genlibbc.lua +++ b/src/host/genlibbc.lua @@ -15,9 +15,11 @@ local format = string.format local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1) +local arm64_target = false + local function usage(arg) io.stderr:write("Usage: ", arg and arg[0] or "genlibbc", - " [-o buildvm_libbc.h] lib_*.c\n") + " [-o buildvm_libbc.h] [--arm64] lib_*.c\n") os.exit(1) end @@ -26,11 +28,16 @@ local function parse_arg(arg) if not (arg and arg[1]) then usage(arg) end - if arg[1] == "-o" then - outfile = arg[2] - if not outfile then usage(arg) end - table.remove(arg, 1) - table.remove(arg, 1) + while arg[1] == "-o" or arg[1] == "--arm64" do + if arg[1] == "-o" then + outfile = arg[2] + if not outfile then usage(arg) end + table.remove(arg, 1) + table.remove(arg, 1) + elseif arg[1] == "--arm64" then + arm64_target = true + table.remove(arg, 1) + end end return outfile end @@ -74,11 +81,6 @@ local function read_uleb128(p) return p, v end --- ORDER LJ_T -local name2itype = { - str = 5, func = 9, tab = 12, int = 14, num = 15 -} - local BC = {} for i=0,#bcnames/6-1 do BC[string.gsub(string.sub(bcnames, i*6+1, i*6+6), " ", "")] = i @@ -97,6 +99,18 @@ local function fixup_dump(dump, fixup) p = read_uleb128(p) p, sizebc = read_uleb128(p) local rawtab = {} + -- ORDER LJ_T + local name2itype + if arm64_target == true then + -- Because CHECK_num is not found anywhere, num type is omitted. + name2itype = { + str = 6, func = 10, tab = 13, int = 15 + } + else + name2itype = { + str = 5, func = 9, tab = 12, int = 14, num = 15 + } + end for i=0,sizebc-1 do local op = p[xop] if op == BC.KSHORT then diff --git a/src/lib_base.c b/src/lib_base.c index 6107bde0..e38e05a0 100644 --- a/src/lib_base.c +++ b/src/lib_base.c @@ -55,6 +55,9 @@ LJLIB_ASM(assert) LJLIB_REC(.) LJLIB_PUSH("nil") LJLIB_PUSH("boolean") LJLIB_PUSH(top-1) /* boolean */ +#if LJ_TARGET_ARM64 +LJLIB_PUSH("userdata") +#endif LJLIB_PUSH("userdata") LJLIB_PUSH("string") LJLIB_PUSH("upval") diff --git a/src/lj_api.c b/src/lj_api.c index 0fbb9256..89d1dfa3 100644 --- a/src/lj_api.c +++ b/src/lj_api.c @@ -189,7 +189,7 @@ LUA_API int lua_type(lua_State *L, int idx) cTValue *o = index2adr(L, idx); if (tvisnumber(o)) { return LUA_TNUMBER; -#if LJ_64 && !LJ_GC64 +#if LJ_64 && !LJ_GC64 || LJ_TARGET_ARM64 } else if (tvislightud(o)) { return LUA_TLIGHTUSERDATA; #endif @@ -198,7 +198,11 @@ LUA_API int lua_type(lua_State *L, int idx) } else { /* Magic internal/external tag conversion. ORDER LJ_T */ uint32_t t = ~itype(o); #if LJ_64 +#if LJ_TARGET_ARM64 + int tt = (int)((U64x(75a069,80400110) >> 4*t) & 15u); +#else int tt = (int)((U64x(75a06,98042110) >> 4*t) & 15u); +#endif #else int tt = (int)(((t < 8 ? 0x98042110u : 0x75a06u) >> 4*(t&7)) & 15u); #endif diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 6d141a20..705022c8 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -196,8 +196,10 @@ static void LJ_FASTCALL recff_type(jit_State *J, RecordFFData *rd) uint32_t t; if (tvisnumber(&rd->argv[0])) t = ~LJ_TNUMX; +#if !LJ_TARGET_ARM64 else if (LJ_64 && !LJ_GC64 && tvislightud(&rd->argv[0])) t = ~LJ_TLIGHTUD; +#endif else t = ~itype(&rd->argv[0]); J->base[0] = lj_ir_kstr(J, strV(&J->fn->c.upvalue[t])); diff --git a/src/lj_ir.h b/src/lj_ir.h index e77f7b99..0ff798b9 100644 --- a/src/lj_ir.h +++ b/src/lj_ir.h @@ -303,6 +303,17 @@ LJ_DATA const uint8_t lj_ir_mode[IR__MAX+1]; ** a TValue after implicit or explicit conversion. Their types must be ** contiguous and next to IRT_NUM (see the typerange macros below). */ +#if LJ_TARGET_ARM64 +#define IRTDEF(_) \ + _(NIL, 4) _(FALSE, 4) _(TRUE, 4) _(LIGHTUD1, LJ_64 ? 8 : 4) \ + _(LIGHTUD2, LJ_64 ? 8 : 4) \ + _(STR, IRTSIZE_PGC) _(P32, 4) _(THREAD, IRTSIZE_PGC) _(PROTO, IRTSIZE_PGC) \ + _(FUNC, IRTSIZE_PGC) _(P64, 8) _(CDATA, IRTSIZE_PGC) _(TAB, IRTSIZE_PGC) \ + _(UDATA, IRTSIZE_PGC) \ + _(FLOAT, 4) _(NUM, 8) _(I8, 1) _(U8, 1) _(I16, 2) _(U16, 2) \ + _(INT, 4) _(U32, 4) _(I64, 8) _(U64, 8) \ + _(SOFTFP, 4) /* There is room for 5 more types. */ +#else #define IRTDEF(_) \ _(NIL, 4) _(FALSE, 4) _(TRUE, 4) _(LIGHTUD, LJ_64 ? 8 : 4) \ _(STR, IRTSIZE_PGC) _(P32, 4) _(THREAD, IRTSIZE_PGC) _(PROTO, IRTSIZE_PGC) \ @@ -311,6 +322,7 @@ LJ_DATA const uint8_t lj_ir_mode[IR__MAX+1]; _(FLOAT, 4) _(NUM, 8) _(I8, 1) _(U8, 1) _(I16, 2) _(U16, 2) \ _(INT, 4) _(U32, 4) _(I64, 8) _(U64, 8) \ _(SOFTFP, 4) /* There is room for 8 more types. */ +#endif /* IR result type and flags (8 bit). */ typedef enum { @@ -373,14 +385,25 @@ typedef struct IRType1 { uint8_t irt; } IRType1; #define irt_isfp(t) (irt_isnum(t) || irt_isfloat(t)) #define irt_isinteger(t) (irt_typerange((t), IRT_I8, IRT_INT)) #define irt_isgcv(t) (irt_typerange((t), IRT_STR, IRT_UDATA)) +#if LJ_TARGET_ARM64 +#define irt_isaddr(t) (irt_typerange((t), IRT_LIGHTUD1, IRT_UDATA)) +#else #define irt_isaddr(t) (irt_typerange((t), IRT_LIGHTUD, IRT_UDATA)) +#endif #define irt_isint64(t) (irt_typerange((t), IRT_I64, IRT_U64)) #if LJ_GC64 +#if LJ_TARGET_ARM64 #define IRT_IS64 \ ((1u< IRT_NUM) { return LJ_TISNUM; } else { @@ -492,7 +517,12 @@ typedef uint32_t TRef; #define tref_isnil(tr) (tref_istype((tr), IRT_NIL)) #define tref_isfalse(tr) (tref_istype((tr), IRT_FALSE)) #define tref_istrue(tr) (tref_istype((tr), IRT_TRUE)) +#if LJ_TARGET_ARM64 +#define tref_islightud(tr) (tref_istype((tr), IRT_LIGHTUD1) ||\ + tref_istype((tr), IRT_LIGHTUD2)) +#else #define tref_islightud(tr) (tref_istype((tr), IRT_LIGHTUD)) +#endif #define tref_isstr(tr) (tref_istype((tr), IRT_STR)) #define tref_isfunc(tr) (tref_istype((tr), IRT_FUNC)) #define tref_iscdata(tr) (tref_istype((tr), IRT_CDATA)) diff --git a/src/lj_obj.c b/src/lj_obj.c index 1daea817..9a9997a9 100644 --- a/src/lj_obj.c +++ b/src/lj_obj.c @@ -13,12 +13,17 @@ LJ_DATADEF const char *const lj_obj_typename[] = { /* ORDER LUA_T */ "no value", "nil", "boolean", "userdata", "number", "string", "table", "function", "userdata", "thread", "proto", "cdata" }; - +#if LJ_TARGET_ARM64 +LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */ + "nil", "boolean", "boolean", "userdata", "userdata", "string", "upval", "thread", + "proto", "function", "trace", "cdata", "table", "userdata", "number" +}; +#else LJ_DATADEF const char *const lj_obj_itypename[] = { /* ORDER LJ_T */ "nil", "boolean", "boolean", "userdata", "string", "upval", "thread", "proto", "function", "trace", "cdata", "table", "userdata", "number" }; - +#endif /* Compare two objects without calling metamethods. */ int LJ_FASTCALL lj_obj_equal(cTValue *o1, cTValue *o2) { diff --git a/src/lj_obj.h b/src/lj_obj.h index 25da9455..40acbfd4 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -254,6 +254,24 @@ typedef const TValue cTValue; ** GC objects are at the end, table/userdata must be lowest. ** Also check lj_ir.h for similar ordering constraints. */ +#if LJ_TARGET_ARM64 +#define LJ_TNIL (~0u) +#define LJ_TFALSE (~1u) +#define LJ_TTRUE (~2u) +#define LJ_TLIGHTUD1 (~3u) +#define LJ_TLIGHTUD2 (~4u) +#define LJ_TSTR (~5u) +#define LJ_TUPVAL (~6u) +#define LJ_TTHREAD (~7u) +#define LJ_TPROTO (~8u) +#define LJ_TFUNC (~9u) +#define LJ_TTRACE (~10u) +#define LJ_TCDATA (~11u) +#define LJ_TTAB (~12u) +#define LJ_TUDATA (~13u) +/* This is just the canonical number type used in some places. */ +#define LJ_TNUMX (~14u) +#else #define LJ_TNIL (~0u) #define LJ_TFALSE (~1u) #define LJ_TTRUE (~2u) @@ -269,7 +287,7 @@ typedef const TValue cTValue; #define LJ_TUDATA (~12u) /* This is just the canonical number type used in some places. */ #define LJ_TNUMX (~13u) - +#endif /* Integers have itype == LJ_TISNUM doubles have itype < LJ_TISNUM */ #if LJ_64 && !LJ_GC64 #define LJ_TISNUM 0xfffeffffu @@ -285,6 +303,10 @@ typedef const TValue cTValue; #define LJ_GCVMASK (((uint64_t)1 << 47) - 1) #endif +#if LJ_TARGET_ARM64 +#define LJ_SET47BIT ((uint64_t)1 << 47) +#endif + /* -- String object ------------------------------------------------------- */ /* String object header. String payload follows. */ @@ -749,8 +771,12 @@ typedef union GCobj { #if LJ_64 && !LJ_GC64 #define tvislightud(o) (((int32_t)itype(o) >> 15) == -2) #else +#if LJ_TARGET_ARM64 +#define tvislightud(o) (itype(o) == LJ_TLIGHTUD1 || itype(o) == LJ_TLIGHTUD2) +#else #define tvislightud(o) (itype(o) == LJ_TLIGHTUD) #endif +#endif #define tvisstr(o) (itype(o) == LJ_TSTR) #define tvisfunc(o) (itype(o) == LJ_TFUNC) #define tvisthread(o) (itype(o) == LJ_TTHREAD) @@ -795,8 +821,13 @@ typedef union GCobj { #endif #define boolV(o) check_exp(tvisbool(o), (LJ_TFALSE - itype(o))) #if LJ_64 +#if LJ_TARGET_ARM64 +#define lightudV(o) \ + check_exp(tvislightud(o), (void *)((o)->u64 & U64x(0000ffff,ffffffff))) +#else #define lightudV(o) \ check_exp(tvislightud(o), (void *)((o)->u64 & U64x(00007fff,ffffffff))) +#endif #else #define lightudV(o) check_exp(tvislightud(o), gcrefp((o)->gcr, void)) #endif @@ -827,7 +858,14 @@ typedef union GCobj { static LJ_AINLINE void setlightudV(TValue *o, void *p) { #if LJ_GC64 +#if LJ_TARGET_ARM64 + if ((uint64_t)p & ((uint64_t)0x1<<47)) + o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD2) << 47); + else + o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD1) << 47); +#else o->u64 = (uint64_t)p | (((uint64_t)LJ_TLIGHTUD) << 47); +#endif #elif LJ_64 o->u64 = (uint64_t)p | (((uint64_t)0xffff) << 48); #else @@ -836,8 +874,13 @@ static LJ_AINLINE void setlightudV(TValue *o, void *p) } #if LJ_64 +#if LJ_TARGET_ARM64 +#define checklightudptr(L, p) \ + (((uint64_t)(p) >> 48) ? (lj_err_msg(L, LJ_ERR_BADLU), NULL) : (p)) +#else #define checklightudptr(L, p) \ (((uint64_t)(p) >> 47) ? (lj_err_msg(L, LJ_ERR_BADLU), NULL) : (p)) +#endif #else #define checklightudptr(L, p) (p) #endif diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc index 7a881bdd..b06156f1 100644 --- a/src/vm_arm64.dasc +++ b/src/vm_arm64.dasc @@ -381,8 +381,9 @@ static void build_subroutines(BuildCtx *ctx) | and sp, CARG1, #CFRAME_RAWMASK |->vm_unwind_ff_eh: // Landing pad for external unwinder. | ldr L, SAVE_L - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 + | movz TISNUM, #(LJ_TISNUM)&0xffff, lsl #48 + | asr TISNUM, TISNUM, #1 + | lsr TISNUMhi, TISNUM, #32 | movn TISNIL, #0 | mov RC, #16 // 2 results: false + error message. | ldr BASE, L->base @@ -447,8 +448,9 @@ static void build_subroutines(BuildCtx *ctx) | str L, GL->cur_L | mov RA, BASE | ldp BASE, CARG1, L->base - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 + | movz TISNUM, #(LJ_TISNUM)&0xffff, lsl #48 + | asr TISNUM, TISNUM, #1 + | lsr TISNUMhi, TISNUM, #32 | ldr PC, [BASE, FRAME_PC] | strb wzr, L->status | movn TISNIL, #0 @@ -486,8 +488,9 @@ static void build_subroutines(BuildCtx *ctx) |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). | str L, GL->cur_L | ldp RB, CARG1, L->base // RB = old base (for vmeta_call). - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 + | movz TISNUM, #(LJ_TISNUM)&0xffff, lsl #48 + | asr TISNUM, TISNUM, #1 + | lsr TISNUMhi, TISNUM, #32 | add PC, PC, BASE | movn TISNIL, #0 | sub PC, PC, RB // PC = frame delta + frame type @@ -589,6 +592,7 @@ static void build_subroutines(BuildCtx *ctx) | |->vmeta_tgets: | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48 + | orr CARG2, CARG2, #LJ_SET47BIT | str CARG2, GL->tmptv | add CARG2, GL, #offsetof(global_State, tmptv) |2: @@ -647,6 +651,7 @@ static void build_subroutines(BuildCtx *ctx) | |->vmeta_tsets: | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48 + | orr CARG2, CARG2, #LJ_SET47BIT | str CARG2, GL->tmptv | add CARG2, GL, #offsetof(global_State, tmptv) |2: @@ -988,6 +993,7 @@ static void build_subroutines(BuildCtx *ctx) |4: | mov CARG1, RB // Use metatable as default result. | movk CARG1, #(LJ_TTAB>>1)&0xffff, lsl #48 + | orr CARG1, CARG1, #LJ_SET47BIT | b ->fff_restv |5: | cmp TMP0, TISNIL @@ -1882,8 +1888,9 @@ static void build_subroutines(BuildCtx *ctx) | bl extern lj_ccallback_enter // (CTState *cts, void *cf) | // Returns lua_State *. | ldp BASE, RC, L:CRET1->base - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 + | movz TISNUM, #(LJ_TISNUM)&0xffff, lsl #48 + | asr TISNUM, TISNUM, #1 + | lsr TISNUMhi, TISNUM, #32 | movn TISNIL, #0 | mov L, CRET1 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] @@ -2660,6 +2667,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) } | ldr BASE, L->base | movk CRET1, #(LJ_TTAB>>1)&0xffff, lsl #48 + | orr CRET1, CRET1, #LJ_SET47BIT | str CRET1, [BASE, RA, lsl #3] | ins_next |