diff --git a/src/jit/nvm.c b/src/jit/nvm.c index 1dbaad25..58a4df31 100644 --- a/src/jit/nvm.c +++ b/src/jit/nvm.c @@ -3,6 +3,8 @@ #include "../ns.h" #include "../utils/file.h" #include "../utils/talloc.h" +#include "../utils/mut.h" +#include "nvm.h" #ifndef USE_PERF #define USE_PERF 0 // enable writing symbols to /tmp/perf-.map @@ -215,41 +217,81 @@ static void write_asm(u8* p, u64 sz) { // for debugging; view with objdump -b bi typedef struct SRef { B v; i32 p; } SRef; #define SREF(V,P) ((SRef){.v=V, .p=P}) -typedef struct OptRes { u32* bc; u32* offset; } OptRes; +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; 2: remove; 3: FN1_/FN2C; 4: FN2O + 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(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]] u32* bc = bc0; usz pos = 0; while (true) { u32* sbc = bc; #define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; }) bool ret = false; u8 cact = 0; + #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 FN1C: case FN1O: { SRef f = stk[TSSIZE(stk)-1]; + case FN1C: case FN1O: { S(f,0) if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; - actions[f.p] = 2; cact = 3; + RM(f.p); cact = 3; TSADD(data, (u64) c(Fun, f.v)->c1); goto defStk; break; } - case FN2C: { SRef f = stk[TSSIZE(stk)-2]; + case FN2C: { S(f,1) if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; - actions[f.p] = 2; cact = 3; + cact = 3; RM(f.p); TSADD(data, (u64) c(Fun, f.v)->c2); goto defStk; break; } - case FN2O: { SRef f = stk[TSSIZE(stk)-2]; + case FN2O: { S(f,1) if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; - actions[f.p] = 2; cact = 4; + cact = 4; RM(f.p); TSADD(data, (u64) c(Fun, f.v)->c1); TSADD(data, (u64) c(Fun, f.v)->c2); goto defStk; break; } + case OP1D: { S(f,0) S(m,1) + if (f.p==-1 | m.p==-1) goto defIns; + B d = m1_d(inc(m.v), inc(f.v)); + cact = 5; RM(f.p); RM(m.p); + TSADD(data, d.u); + TSSIZE(stk)--; + stk[TSSIZE(stk)-1] = SREF(d, pos); + break; + } + case OP2D: { S(f,0) S(m,1) S(g,2) + if (f.p==-1 | m.p==-1 | g.p==-1) goto defIns; + B d = m2_d(inc(m.v), inc(f.v), inc(g.v)); + cact = 5; RM(f.p); RM(m.p); RM(g.p); + TSADD(data, d.u); + TSSIZE(stk)-= 2; + stk[TSSIZE(stk)-1] = SREF(d, pos); + break; + } + case TR2D: { S(g,0) S(h,1) + if (g.p==-1 | h.p==-1) goto defIns; + B d = m_atop(inc(g.v), inc(h.v)); + cact = 5; RM(g.p); RM(h.p); + TSADD(data, d.u); + TSSIZE(stk)--; + stk[TSSIZE(stk)-1] = SREF(d, pos); + break; + } + case TR3D: case TR3O: { S(f,0) S(g,1) S(h,2) + if (f.p==-1 | g.p==-1 | h.p==-1) goto defIns; + if (isNothing(f.v)) thrM("JIT optimization: didn't expect constant ·"); + B d = m_fork(inc(f.v), inc(g.v), inc(h.v)); + cact = 5; RM(f.p); RM(g.p); RM(h.p); + TSADD(data, d.u); + TSSIZE(stk)-= 2; + stk[TSSIZE(stk)-1] = SREF(d, pos); + break; + } case RETN: case RETD: ret = true; cact = 1; @@ -260,8 +302,10 @@ static OptRes opt(u32* bc0) { i32 added = stackAdded(sbc); for (i32 i = 0; i < added; i++) TSADD(stk, SREF(bi_optOut, -1)) } + #undef S TSADD(actions, cact); #undef L64 + #undef RM if (ret) break; bc = nextBC(sbc); pos++; @@ -270,6 +314,7 @@ static OptRes opt(u32* bc0) { TSALLOC(u32, rbc, TSSIZE(actions)); TSALLOC(u32, roff, TSSIZE(actions)); + B refs = inc(bi_emptyHVec); bc = bc0; u64 tpos = 0, dpos = 0; while (true) { @@ -291,11 +336,20 @@ static OptRes opt(u32* bc0) { A64(data[dpos++]); A64(data[dpos++]); break; - - case 2: break; // remove - + case 5: + u64 on = data[dpos++]; B ob = b(on); + TSADD(rbc, isVal(ob)? ADDI : ADDU); + A64(on); + if (isVal(ob)) refs = vec_add(refs, ob); + break; + case 6: + dec(b(data[dpos++])); + break; + case 10: + case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19: + dpos+= ctype-10; + break; case 1: ret = true; goto def2; // return - case 0: def2:; // do nothing TSADDA(rbc, sbc, ebc-sbc); } @@ -306,10 +360,10 @@ static OptRes opt(u32* bc0) { bc = ebc; } bc = bc0; pos = 0; - TSFREE(data); TSFREE(actions); - return (OptRes){.bc = rbc, .offset = roff}; + if (a(refs)->ia==0) { dec(refs); refs=m_f64(0); } + return (OptRes){.bc = rbc, .offset = roff, .refs = refs}; } #undef SREF void freeOpt(OptRes o) { @@ -323,7 +377,7 @@ static u32 readBytes4(u8* d) { typedef B JITFn(B* cStack, Scope** pscs); static inline i32 maxi32(i32 a, i32 b) { return a>b?a:b; } -u8* m_nvm(Body* body) { +Nvm_res m_nvm(Body* body) { ALLOC_ASM(64); TSALLOC(u32, rel, 64); #define r_TMP 3 @@ -454,7 +508,7 @@ u8* m_nvm(Body* body) { // write_asm(binEx, sz); FREE_ASM(); TSFREE(rel); - return binEx; + return (Nvm_res){.p = binEx, .refs = optRes.refs}; } B evalJIT(Body* b, Scope* sc, u8* ptr) { // doesn't consume u32* bc = b->bc; diff --git a/src/jit/nvm.h b/src/jit/nvm.h index 2292b305..eceec0d7 100644 --- a/src/jit/nvm.h +++ b/src/jit/nvm.h @@ -2,5 +2,6 @@ #include "../vm.h" B evalJIT(Body* b, Scope* sc, u8* ptr); -u8* m_nvm(Body* b); +typedef struct Nvm_res { u8* p; B refs; } Nvm_res; +Nvm_res m_nvm(Body* b); void nvm_free(u8* ptr); diff --git a/src/vm.c b/src/vm.c index 7bf27b49..ab616733 100644 --- a/src/vm.c +++ b/src/vm.c @@ -228,6 +228,7 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B block body->comp = comp; ptr_inc(comp); body->bc = (u32*)nbc; body->nvm = NULL; + body->nvmRefs = m_f64(0); body->map = map; body->blocks = nBl; body->maxStack = hM; @@ -558,6 +559,7 @@ B evalBC(Body* b, Scope* sc) { // doesn't consume #undef P #undef ADD #undef POP + #undef POS_UPD #undef GS_UPD } @@ -582,7 +584,11 @@ B actualExec(Block* bl, Scope* psc, i32 ga, B* svar) { // consumes svar contents // jit = body->bc[2]==m_f64(123456).u>>32; // enable JIT just for blocks starting with `123456⋄` B r; if (jit) { - if (!body->nvm) body->nvm = m_nvm(body); + if (!body->nvm) { + Nvm_res r = m_nvm(body); + body->nvm = r.p; + body->nvmRefs = r.refs; + } r = evalJIT(body, sc, body->nvm); } else { r = evalBC(body, sc); @@ -650,9 +656,10 @@ void scope_free(Value* x) { } void body_free(Value* x) { Body* c = (Body*) x; - if(c->nsDesc) ptr_decR(c->nsDesc); - if(c->blocks) ptr_decR(c->blocks); - if(c->nvm ) nvm_free(c->nvm); + if(c->nsDesc ) ptr_decR(c->nsDesc); + if(c->blocks ) ptr_decR(c->blocks); + if(c->nvm ) nvm_free(c->nvm); + dec(c->nvmRefs); ptr_decR(c->comp); ptr_decR(RFLD(c->bc, I32Arr,a)); ptr_decR(RFLD(c->map,I32Arr,a)); @@ -678,6 +685,7 @@ void body_visit(Value* x) { Body* c = (Body*) x; if(c->nsDesc) mm_visitP(c->nsDesc); if(c->blocks) mm_visitP(c->blocks); + mm_visit(c->nvmRefs); mm_visitP(c->comp); mm_visitP(RFLD(c->bc, I32Arr,a)); mm_visitP(RFLD(c->map,I32Arr,a)); diff --git a/src/vm.h b/src/vm.h index a090636b..2e0b4570 100644 --- a/src/vm.h +++ b/src/vm.h @@ -81,6 +81,7 @@ struct Body { u16 maxPSC; u16 varAm; NSDesc* nsDesc; + B nvmRefs; i32 varIDs[]; };