basic constant folding

This commit is contained in:
dzaima 2021-06-16 03:03:31 +03:00
parent 1afe46b393
commit 4322fb8232
4 changed files with 85 additions and 21 deletions

View File

@ -3,6 +3,8 @@
#include "../ns.h" #include "../ns.h"
#include "../utils/file.h" #include "../utils/file.h"
#include "../utils/talloc.h" #include "../utils/talloc.h"
#include "../utils/mut.h"
#include "nvm.h"
#ifndef USE_PERF #ifndef USE_PERF
#define USE_PERF 0 // enable writing symbols to /tmp/perf-<pid>.map #define USE_PERF 0 // enable writing symbols to /tmp/perf-<pid>.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; typedef struct SRef { B v; i32 p; } SRef;
#define SREF(V,P) ((SRef){.v=V, .p=P}) #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) { static OptRes opt(u32* bc0) {
TSALLOC(SRef, stk, 8); 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 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; u32* bc = bc0; usz pos = 0;
while (true) { while (true) {
u32* sbc = bc; u32* sbc = bc;
#define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; }) #define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; })
bool ret = false; bool ret = false;
u8 cact = 0; 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__"); 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 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; 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); TSADD(data, (u64) c(Fun, f.v)->c1);
goto defStk; goto defStk;
break; 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; 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); TSADD(data, (u64) c(Fun, f.v)->c2);
goto defStk; goto defStk;
break; 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; 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)->c1);
TSADD(data, (u64) c(Fun, f.v)->c2); TSADD(data, (u64) c(Fun, f.v)->c2);
goto defStk; goto defStk;
break; 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: case RETN: case RETD:
ret = true; ret = true;
cact = 1; cact = 1;
@ -260,8 +302,10 @@ static OptRes opt(u32* bc0) {
i32 added = stackAdded(sbc); i32 added = stackAdded(sbc);
for (i32 i = 0; i < added; i++) TSADD(stk, SREF(bi_optOut, -1)) for (i32 i = 0; i < added; i++) TSADD(stk, SREF(bi_optOut, -1))
} }
#undef S
TSADD(actions, cact); TSADD(actions, cact);
#undef L64 #undef L64
#undef RM
if (ret) break; if (ret) break;
bc = nextBC(sbc); bc = nextBC(sbc);
pos++; pos++;
@ -270,6 +314,7 @@ static OptRes opt(u32* bc0) {
TSALLOC(u32, rbc, TSSIZE(actions)); TSALLOC(u32, rbc, TSSIZE(actions));
TSALLOC(u32, roff, TSSIZE(actions)); TSALLOC(u32, roff, TSSIZE(actions));
B refs = inc(bi_emptyHVec);
bc = bc0; bc = bc0;
u64 tpos = 0, dpos = 0; u64 tpos = 0, dpos = 0;
while (true) { while (true) {
@ -291,11 +336,20 @@ static OptRes opt(u32* bc0) {
A64(data[dpos++]); A64(data[dpos++]);
A64(data[dpos++]); A64(data[dpos++]);
break; break;
case 5:
case 2: break; // remove 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 1: ret = true; goto def2; // return
case 0: def2:; // do nothing case 0: def2:; // do nothing
TSADDA(rbc, sbc, ebc-sbc); TSADDA(rbc, sbc, ebc-sbc);
} }
@ -306,10 +360,10 @@ static OptRes opt(u32* bc0) {
bc = ebc; bc = ebc;
} }
bc = bc0; pos = 0; bc = bc0; pos = 0;
TSFREE(data); TSFREE(data);
TSFREE(actions); 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 #undef SREF
void freeOpt(OptRes o) { void freeOpt(OptRes o) {
@ -323,7 +377,7 @@ static u32 readBytes4(u8* d) {
typedef B JITFn(B* cStack, Scope** pscs); typedef B JITFn(B* cStack, Scope** pscs);
static inline i32 maxi32(i32 a, i32 b) { return a>b?a:b; } 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); ALLOC_ASM(64);
TSALLOC(u32, rel, 64); TSALLOC(u32, rel, 64);
#define r_TMP 3 #define r_TMP 3
@ -454,7 +508,7 @@ u8* m_nvm(Body* body) {
// write_asm(binEx, sz); // write_asm(binEx, sz);
FREE_ASM(); FREE_ASM();
TSFREE(rel); TSFREE(rel);
return binEx; return (Nvm_res){.p = binEx, .refs = optRes.refs};
} }
B evalJIT(Body* b, Scope* sc, u8* ptr) { // doesn't consume B evalJIT(Body* b, Scope* sc, u8* ptr) { // doesn't consume
u32* bc = b->bc; u32* bc = b->bc;

View File

@ -2,5 +2,6 @@
#include "../vm.h" #include "../vm.h"
B evalJIT(Body* b, Scope* sc, u8* ptr); 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); void nvm_free(u8* ptr);

View File

@ -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->comp = comp; ptr_inc(comp);
body->bc = (u32*)nbc; body->bc = (u32*)nbc;
body->nvm = NULL; body->nvm = NULL;
body->nvmRefs = m_f64(0);
body->map = map; body->map = map;
body->blocks = nBl; body->blocks = nBl;
body->maxStack = hM; body->maxStack = hM;
@ -558,6 +559,7 @@ B evalBC(Body* b, Scope* sc) { // doesn't consume
#undef P #undef P
#undef ADD #undef ADD
#undef POP #undef POP
#undef POS_UPD
#undef GS_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⋄` // jit = body->bc[2]==m_f64(123456).u>>32; // enable JIT just for blocks starting with `123456⋄`
B r; B r;
if (jit) { 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); r = evalJIT(body, sc, body->nvm);
} else { } else {
r = evalBC(body, sc); r = evalBC(body, sc);
@ -650,9 +656,10 @@ void scope_free(Value* x) {
} }
void body_free(Value* x) { void body_free(Value* x) {
Body* c = (Body*) x; Body* c = (Body*) x;
if(c->nsDesc) ptr_decR(c->nsDesc); if(c->nsDesc ) ptr_decR(c->nsDesc);
if(c->blocks) ptr_decR(c->blocks); if(c->blocks ) ptr_decR(c->blocks);
if(c->nvm ) nvm_free(c->nvm); if(c->nvm ) nvm_free(c->nvm);
dec(c->nvmRefs);
ptr_decR(c->comp); ptr_decR(c->comp);
ptr_decR(RFLD(c->bc, I32Arr,a)); ptr_decR(RFLD(c->bc, I32Arr,a));
ptr_decR(RFLD(c->map,I32Arr,a)); ptr_decR(RFLD(c->map,I32Arr,a));
@ -678,6 +685,7 @@ void body_visit(Value* x) {
Body* c = (Body*) x; Body* c = (Body*) x;
if(c->nsDesc) mm_visitP(c->nsDesc); if(c->nsDesc) mm_visitP(c->nsDesc);
if(c->blocks) mm_visitP(c->blocks); if(c->blocks) mm_visitP(c->blocks);
mm_visit(c->nvmRefs);
mm_visitP(c->comp); mm_visitP(c->comp);
mm_visitP(RFLD(c->bc, I32Arr,a)); mm_visitP(RFLD(c->bc, I32Arr,a));
mm_visitP(RFLD(c->map,I32Arr,a)); mm_visitP(RFLD(c->map,I32Arr,a));

View File

@ -81,6 +81,7 @@ struct Body {
u16 maxPSC; u16 maxPSC;
u16 varAm; u16 varAm;
NSDesc* nsDesc; NSDesc* nsDesc;
B nvmRefs;
i32 varIDs[]; i32 varIDs[];
}; };