diff --git a/src/jit/nvm.c b/src/jit/nvm.c index 6b4f8fe7..e7d78730 100644 --- a/src/jit/nvm.c +++ b/src/jit/nvm.c @@ -156,6 +156,14 @@ INS B i_SETM(B s, Scope** pscs, u32* bc GA1) { P(f)P(x) GS_UPD; POS_UPD; v_set(pscs, s, r, true); dec(s); return r; } +INS B i_SETNi(B x, Scope** pscs, u32 d, u32 p, u32* bc GA1) { GS_UPD; POS_UPD; v_setI(pscs, d, p, inc(x), false); return x; } +INS B i_SETUi(B x, Scope** pscs, u32 d, u32 p, u32* bc GA1) { GS_UPD; POS_UPD; v_setI(pscs, d, p, inc(x), true ); return x; } +INS B i_SETMi(B f, Scope** pscs, u32 d, u32 p, u32* bc GA1) { P(x) GS_UPD; POS_UPD; + B w = v_getI(pscs, d, p); + B r = c2(f,w,x); dec(f); + v_setI(pscs, d, p, inc(r), true); + return r; +} INS B i_FLDO(B ns, u32 p, Scope** pscs GA1) { GS_UPD; if (!isNsp(ns)) thrM("Trying to read a field from non-namespace"); B r = inc(ns_getU(ns, pscs[0]->body->nsDesc->nameList, p)); @@ -218,7 +226,7 @@ void nvm_free(u8* ptr) { file_wChars(m_str32(U"asm_off"), o); dec(o); B s = inc(bi_emptyCVec); #define F(X) AFMT("s/%p$/%p == i_" #X "/;", i_##X, i_##X); - F(POPS) F(ADDI) F(ADDU) F(FN1C) F(FN1O) F(FN2C) F(FN2O) F(FN1Ci) F(FN2Ci) F(FN1Oi) F(FN2Oi) F(ARR_0) F(ARR_p) F(DFND_0) F(DFND_1) F(DFND_2) F(OP1D) F(OP2D) F(OP2H) F(TR2D) F(TR3D) F(TR3O) F(LOCO) F(LOCU) F(EXTO) F(EXTU) F(SETN) F(SETU) F(SETM) F(FLDO) F(NSPM) F(RETD) + F(POPS) F(ADDI) F(ADDU) F(FN1C) F(FN1O) F(FN2C) F(FN2O) F(FN1Ci) F(FN2Ci) F(FN1Oi) F(FN2Oi) F(ARR_0) F(ARR_p) F(DFND_0) F(DFND_1) F(DFND_2) F(OP1D) F(OP2D) F(OP2H) F(TR2D) F(TR3D) F(TR3O) F(LOCO) F(LOCU) F(EXTO) F(EXTU) F(SETN) F(SETU) F(SETM) F(FLDO) F(NSPM) F(RETD) F(SETNi) F(SETUi) F(SETMi) #undef F file_wChars(m_str32(U"asm_sed"), s); dec(s); } @@ -230,7 +238,7 @@ typedef struct SRef { B v; i32 p; } SRef; typedef struct OptRes { u32* bc; u32* offset; B refs; } OptRes; static OptRes opt(u32* bc0) { TSALLOC(SRef, stk, 8); - TSALLOC(u8, actions, 64); // 1 per instruction; 0: nothing; 1: indicates return; 3: FN1_/FN2C; 4: FN2O; 5: replace with PUSH; 6: decrement 1 data; 10+N: ignore N data + TSALLOC(u8, actions, 64); // 1 per instruction; 0: nothing; 1: indicates return; 2: immediate SET; 3: immediate FN1_/FN2C; 4: FN2O; 5: replace with PUSH; 6: decrement 1 data; 10+N: ignore N data TSALLOC(u64, data, 64); // variable length; whatever things are needed for the specific action u8 rm_map[] = {10,10,10,11,12,6,6,99,99,99,11,12,13,14,15,16,17,18,19}; #define RM(N) actions[N] = rm_map[actions[N]] @@ -243,6 +251,10 @@ static OptRes opt(u32* bc0) { #define S(N,I) SRef N = stk[TSSIZE(stk)-1-(I)]; switch (*bc++) { case FN1Ci: case FN1Oi: case FN2Ci: case FN2Oi: thrM("JIT optimization: didn't already expect immediate FN__"); case ADDU: case ADDI: cact = 0; TSADD(stk,SREF(b(L64), pos)); break; + case LOCM: { u32 d = *bc++; u32 p = *bc++; + TSADD(stk,SREF(tag((u64)d<<32 | (u32)p, VAR_TAG), pos)); + break; + } case FN1C: case FN1O: { S(f,0) if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; RM(f.p); cact = 3; @@ -299,6 +311,13 @@ static OptRes opt(u32* bc0) { stk[TSSIZE(stk)-1] = SREF(d, pos); break; } + case SETN: case SETU: case SETM: { S(s,0) + if (!isVar(s.v)) goto defIns; + cact = 2; RM(s.p); + TSADD(data, s.v.u); + TSSIZE(stk)-= SETM==*sbc? 2 : 1; + break; + } case RETN: case RETD: ret = true; cact = 1; @@ -333,6 +352,12 @@ static OptRes opt(u32* bc0) { u64 psz = TSSIZE(rbc); #define A64(X) { u64 a64=(X); TSADD(rbc, (u32)a64); TSADD(rbc, a64>>32); } switch (ctype) { default: UD; + case 2: assert(v==SETN|v==SETU|v==SETM); + TSADD(rbc, v==SETN? SETNi : v==SETU? SETUi : SETMi); + u64 d = data[dpos++]; + TSADD(rbc, (u16)(d>>32)); + TSADD(rbc, (u32)d); + break; case 3: assert(v==FN1C|v==FN1O|v==FN2C); TSADD(rbc, v==FN1C? FN1Ci : v==FN1O? FN1Oi : FN2Ci); A64(data[dpos++]); @@ -466,6 +491,9 @@ Nvm_res m_nvm(Body* body) { case SETN: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,off); INV(3,0,i_SETN); break; // (B, Scope** pscs, u32* bc, S) case SETU: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,off); INV(3,0,i_SETU); break; // (B, Scope** pscs, u32* bc, S) case SETM: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,off); INV(3,0,i_SETM); break; // (B, Scope** pscs, u32* bc, S) + case SETNi:TOPp; { u64 d=*bc++; u64 p=*bc++; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,d); IMM(REG_ARG3,p); IMM(REG_ARG4,off); INV(5,0,i_SETNi); break; } // (B, Scope** pscs. u32 d. u32 p, u32* bc, S) + case SETUi:TOPp; { u64 d=*bc++; u64 p=*bc++; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,d); IMM(REG_ARG3,p); IMM(REG_ARG4,off); INV(5,0,i_SETUi); break; } // (B, Scope** pscs. u32 d. u32 p, u32* bc, S) + case SETMi:TOPp; { u64 d=*bc++; u64 p=*bc++; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,d); IMM(REG_ARG3,p); IMM(REG_ARG4,off); INV(5,0,i_SETMi); break; } // (B, Scope** pscs. u32 d. u32 p, u32* bc, S) case FLDO: TOPp; IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); INV(3,0,i_FLDO); break; // (B, u32 p, Scope** pscs, S) case NSPM: TOPp; IMM(REG_ARG1,*bc++); CCALL(i_NSPM); break; // (B, u32 l, S) case RETD: ASM(MOV,REG_ARG0,r_PSCS); INV(1,1,i_RETD); ret=true; break; // (Scope** pscs, S); stack diff 0 is wrong, but updating it is useless diff --git a/src/vm.c b/src/vm.c index a4c37d8f..9031775c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -30,7 +30,8 @@ u32* nextBC(u32* p) { return p+2; case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: - case ADDI: case ADDU: case FN1Ci: case FN1Oi: case FN2Ci: + case ADDI: case ADDU: + case FN1Ci: case FN1Oi: case FN2Ci: case SETNi: case SETUi: case SETMi: return p+3; case FN2Oi: return p+5; @@ -41,8 +42,8 @@ i32 stackDiff(u32* p) { if (*p==ARRO|*p==ARRM) return 1-p[1]; switch(*p) { default: UD; // case ARRO: case ARRM: return 1-p[1]; case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 1; - case FN1Ci:case FN1Oi:case CHKV: case VFYM: case FLDO: case FLDM: case RETD: case NSPM: return 0; - case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case SETN: case SETU: case POPS: case OP2H: case SETH: case RETN: return -1; + case FN1Ci:case FN1Oi:case CHKV: case VFYM: case FLDO: case FLDM: case SETNi:case SETUi:case RETD: case NSPM: return 0; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case SETN: case SETU: case SETMi:case POPS: case OP2H: case SETH: case RETN: return -1; case OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return -2; } } @@ -51,8 +52,8 @@ i32 stackConsumed(u32* p) { switch(*p) { default: UD; // case ARRO: case ARRM: return -p[1]; case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 0; case CHKV: case VFYM: case RETD: return 0; - case FN1Ci:case FN1Oi:case FLDO: case FLDM: case NSPM: case RETN: case POPS: return 1; - case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case SETN: case SETU: case OP2H: case SETH: return 2; + case FN1Ci:case FN1Oi:case FLDO: case FLDM: case NSPM: case RETN: case POPS: case SETNi:case SETUi:return 1; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case SETMi:case OP1D: case TR2D: case SETN: case SETU: case OP2H: case SETH: return 2; case OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return 3; } } diff --git a/src/vm.h b/src/vm.h index 2e0b4570..e99b9804 100644 --- a/src/vm.h +++ b/src/vm.h @@ -36,6 +36,7 @@ enum { EXTO, EXTM, EXTU, // alternate versions of LOC_ for extended variables ADDI, ADDU, // separate PUSH for refcounting needed/not needed (stores the object inline as 2 u32s, instead of reading from `objs`) FN1Ci, FN1Oi, FN2Ci, FN2Oi, // FN__ alternatives that don't take the function from the stack, but instead as an 2×u32 immediate in the bytecode + SETNi, SETUi, SETMi, // SET_ alternatives that expect the set variable as a depth-position pair like LOC_ BC_SIZE }; @@ -155,23 +156,30 @@ typedef struct FldAlias { i32 p; } FldAlias; -NOINLINE B v_getR(Scope* pscs[], B s); -static B v_get(Scope* pscs[], B s) { // get value representing s, replacing with bi_optOut; doesn't consume - if (RARE(!isVar(s))) return v_getR(pscs, s); - Scope* sc = pscs[(u16)(s.u>>32)]; - B r = sc->vars[(u32)s.u]; - sc->vars[(u32)s.u] = bi_optOut; + +NOINLINE B v_getR(Scope* pscs[], B s); // doesn't consume +static inline B v_getI(Scope* pscs[], u32 d, u32 p) { + Scope* sc = pscs[d]; + B r = sc->vars[p]; + sc->vars[p] = bi_optOut; return r; } +static inline B v_get(Scope* pscs[], B s) { // get value representing s, replacing with bi_optOut; doesn't consume + if (RARE(!isVar(s))) return v_getR(pscs, s); + return v_getI(pscs, (u16)(s.u>>32), (u32)s.u); +} -NOINLINE void v_setR(Scope* pscs[], B s, B x, bool upd); -static void v_set(Scope* pscs[], B s, B x, bool upd) { // doesn't consume - if (RARE(!isVar(s))) return v_setR(pscs, s, x, upd);; - Scope* sc = pscs[(u16)(s.u>>32)]; - B prev = sc->vars[(u32)s.u]; +NOINLINE void v_setR(Scope* pscs[], B s, B x, bool upd); // doesn't consume +static inline void v_setI(Scope* pscs[], u32 d, u32 p, B x, bool upd) { // consumes x + Scope* sc = pscs[d]; + B prev = sc->vars[p]; if (upd) { if (prev.u==bi_noVar.u) thrM("↩: Updating undefined variable"); dec(prev); } - sc->vars[(u32)s.u] = inc(x); + sc->vars[p] = x; +} +static inline void v_set(Scope* pscs[], B s, B x, bool upd) { // doesn't consume + if (RARE(!isVar(s))) return v_setR(pscs, s, x, upd); + v_setI(pscs, (u16)(s.u>>32), (u32)s.u, inc(x), upd); }