move TAlloc/TStack around, immediate functions
This commit is contained in:
parent
d2a1d7c329
commit
1afe46b393
@ -1,6 +1,7 @@
|
||||
#include "../core.h"
|
||||
#include "../utils/hash.h"
|
||||
#include "../utils/mut.h"
|
||||
#include "../utils/talloc.h"
|
||||
#include "../nfns.h"
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "../core.h"
|
||||
#include "../utils/builtins.h"
|
||||
#include "../utils/talloc.h"
|
||||
|
||||
B md2BI_uc1(B t, B o, B f, B g, B x) { return c(BMd2,t)->uc1(t, o, f, g, x); }
|
||||
B md2BI_ucw(B t, B o, B f, B g, B w, B x) { return c(BMd2,t)->ucw(t, o, f, g, w, x); }
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "../utils/each.h"
|
||||
#include "../utils/mut.h"
|
||||
#include "../utils/builtins.h"
|
||||
#include "../utils/talloc.h"
|
||||
|
||||
|
||||
B shape_c1(B t, B x) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "../core.h"
|
||||
#include "../utils/talloc.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "../core.h"
|
||||
|
||||
u64 allocB; // currently allocated number of bytes
|
||||
|
||||
#if MM==0
|
||||
#include "../opt/mm_malloc.c"
|
||||
#elif MM==1
|
||||
|
||||
@ -1,17 +1,22 @@
|
||||
#include "../core.h"
|
||||
#include "../utils/mut.h"
|
||||
#include "../utils/utf.h"
|
||||
#include "../utils/talloc.h"
|
||||
|
||||
u64 allocB; // currently allocated number of bytes
|
||||
B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec;
|
||||
|
||||
NOINLINE TStack* tstack_ext(TStack* o, u32 elsz) {
|
||||
usz ncap = o->cap*2;
|
||||
TStack* n = (TStack*)mm_allocN(sizeof(TStack) + elsz*ncap, t_temp);
|
||||
memcpy(n->data, o->data, o->cap*elsz);
|
||||
n->cap = ncap;
|
||||
n->size = o->size;
|
||||
mm_free((Value*)o);
|
||||
NOINLINE TStack* ts_e(TStack* o, u32 elsz, u64 am) { u64 size = o->size;
|
||||
u64 alsz = mm_round(fsizeof(TStack, data, u8, (size+am)*elsz));
|
||||
TStack* n;
|
||||
if (alsz==mm_size((Value*)o)) {
|
||||
n = o;
|
||||
} else {
|
||||
n = (TStack*)mm_allocN(alsz, t_temp);
|
||||
memcpy(n->data, o->data, o->cap*elsz);
|
||||
mm_free((Value*)o);
|
||||
n->size = size;
|
||||
}
|
||||
n->cap = (mm_size((Value*)n)-offsetof(TStack,data))/elsz;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
@ -21,39 +21,6 @@ static B mm_alloc(usz sz, u8 type, u64 tag) {
|
||||
#define MAP_NORESERVE 0 // apparently needed for freebsd or something
|
||||
#endif
|
||||
|
||||
typedef struct TAlloc {
|
||||
struct Value;
|
||||
u8 data[];
|
||||
} TAlloc;
|
||||
#define TOFF offsetof(TAlloc, data)
|
||||
#define TALLOC(T,N,AM) T* N = (T*) ((TAlloc*)mm_allocN(TOFF + (AM)*sizeof(T) + 8, t_temp))->data; // +8 so mm is happy
|
||||
#define TOBJ(N) (void*)((u8*)(N) - TOFF)
|
||||
#define TFREE(N) mm_free((Value*)TOBJ(N));
|
||||
#define TREALLOC(N, AM) talloc_realloc(TOBJ(N), AM)
|
||||
#define TSIZE(N) (mm_size(TOBJ(N))-TOFF)
|
||||
static inline void* talloc_realloc(TAlloc* t, u64 am) { // TODO maybe shouldn't be inline?
|
||||
u64 stored = mm_size((Value*)t)-TOFF;
|
||||
if (stored > am) return t->data;
|
||||
TALLOC(u8,r,am);
|
||||
memcpy(r, t->data, stored);
|
||||
mm_free((Value*)t);
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef struct TStack {
|
||||
struct Value;
|
||||
usz size;
|
||||
usz cap;
|
||||
u8 data[];
|
||||
} TStack;
|
||||
#define TSALLOC(T,N,I) usz N##_dc=(I); u32 N##_e=sizeof(T); TStack* N##_o = (TStack*)mm_allocN(sizeof(TStack)+N##_e*N##_dc, t_temp); N##_o->size=0; N##_o->cap=N##_dc; T* N = (T*)N##_o->data;
|
||||
#define TSFREE(N) mm_free((Value*)N##_o);
|
||||
#define TSDBL(N) { N##_o = tstack_ext(N##_o, N##_e); N = (void*)N##_o->data; }
|
||||
#define TSADD(N,X) { if (N##_o->size==N##_o->cap) TSDBL(N); N[N##_o->size++] = X; }
|
||||
#define TSADDA(N,P,AM) { u64 n=AM; while(N##_o->size+n>N##_o->cap) TSDBL(N); memcpy(N+N##_o->size,P,n*N##_e); N##_o->size+= AM; }
|
||||
#define TSSIZE(N) (N##_o->size)
|
||||
TStack* tstack_ext(TStack* o, u32 elsz);
|
||||
|
||||
// shape mess
|
||||
|
||||
typedef struct ShArr {
|
||||
|
||||
4
src/h.h
4
src/h.h
@ -106,7 +106,7 @@
|
||||
#define AUTO __auto_type
|
||||
#define LIKELY(X) __builtin_expect(X,1)
|
||||
#define RARE(X) __builtin_expect(X,0)
|
||||
#define RFLD(X,T,F) ((T*)((char*)(X) - offsetof(T,F))) // reverse-read field: `T* x = …; E v = x->f; x == RFLD(v, T, f)`
|
||||
#define RFLD(X,T,F) ((T*)((char*)(X) - offsetof(T,F))) // value, result type, field name; reverse-read field: `T* x = …; E v = x->f; x == RFLD(v, T, f)`
|
||||
#define N64x "%"SCNx64
|
||||
#define N64d "%"SCNd64
|
||||
#define N64u "%"SCNu64
|
||||
@ -122,7 +122,7 @@ typedef u8 ur;
|
||||
CTR_FOR(F)
|
||||
#undef F
|
||||
|
||||
#define fsizeof(T,F,E,n) (offsetof(T, F) + sizeof(E)*(n)) // type, flexible array member name, flexible array member type, item amount
|
||||
#define fsizeof(T,F,E,N) (offsetof(T, F) + sizeof(E)*(N)) // type, flexible array member name, flexible array member type, item amount
|
||||
#define ftag(x) ((u64)(x) << 48)
|
||||
#define tag(v, t) b(((u64)(v)) | ftag(t))
|
||||
// .111111111110000000000000000000000000000000000000000000000000000 infinity
|
||||
|
||||
173
src/jit/nvm.c
173
src/jit/nvm.c
@ -2,6 +2,7 @@
|
||||
#include "../core/gstack.h"
|
||||
#include "../ns.h"
|
||||
#include "../utils/file.h"
|
||||
#include "../utils/talloc.h"
|
||||
|
||||
#ifndef USE_PERF
|
||||
#define USE_PERF 0 // enable writing symbols to /tmp/perf-<pid>.map
|
||||
@ -45,7 +46,7 @@ static void* mmX_allocN(usz sz, u8 type) { assert(sz>=16); return mmX_allocL(BSZ
|
||||
#endif
|
||||
#define P(N) B N=GSP;
|
||||
#if VM_POS
|
||||
#define POS_UPD (envCurr-1)->bcL = bc-1;
|
||||
#define POS_UPD (envCurr-1)->bcL = bc;
|
||||
#else
|
||||
#define POS_UPD
|
||||
#endif
|
||||
@ -61,28 +62,39 @@ INS B i_ADDI(u64 v) {
|
||||
INS B i_ADDU(u64 v) {
|
||||
return b(v);
|
||||
}
|
||||
INS B i_FN1C(B f, u32* bc GA1) { P(x) // TODO figure out a way to instead pass an offset in bc, so that shorter `mov`s can be used to pass it
|
||||
GS_UPD;POS_UPD;
|
||||
INS B i_FN1C(B f, u32* bc GA1) { P(x) GS_UPD;POS_UPD; // TODO figure out a way to instead pass an offset in bc, so that shorter `mov`s can be used to pass it
|
||||
B r = c1(f, x);
|
||||
dec(f); return r;
|
||||
}
|
||||
INS B i_FN1O(B f, u32* bc GA1) { P(x)
|
||||
GS_UPD;POS_UPD;
|
||||
INS B i_FN1O(B f, u32* bc GA1) { P(x) GS_UPD;POS_UPD;
|
||||
B r = isNothing(x)? x : c1(f, x);
|
||||
dec(f); return r;
|
||||
}
|
||||
INS B i_FN2C(B w, u32* bc GA1) { P(f)P(x)
|
||||
GS_UPD;POS_UPD;
|
||||
INS B i_FN2C(B w, u32* bc GA1) { P(f)P(x) GS_UPD;POS_UPD;
|
||||
B r = c2(f, w, x);
|
||||
dec(f); return r;
|
||||
}
|
||||
INS B i_FN2O(B w, u32* bc GA1) { P(f)P(x)
|
||||
GS_UPD;POS_UPD; B r;
|
||||
INS B i_FN2O(B w, u32* bc GA1) { P(f)P(x) GS_UPD;POS_UPD;
|
||||
B r;
|
||||
if (isNothing(x)) { dec(w); r = x; }
|
||||
else r = isNothing(w)? c1(f, x) : c2(f, w, x);
|
||||
dec(f);
|
||||
return r;
|
||||
}
|
||||
INS B i_FN1Ci(B x, BB2B fi, u32* bc GA1) { GS_UPD;POS_UPD;
|
||||
return fi(b((u64)0), x);
|
||||
}
|
||||
INS B i_FN2Ci(B w, BBB2B fi, u32* bc GA1) { P(x) GS_UPD;POS_UPD;
|
||||
return fi(b((u64)0), w, x);
|
||||
}
|
||||
INS B i_FN1Oi(B x, BB2B fm, u32* bc GA1) { GS_UPD;POS_UPD;
|
||||
B r = isNothing(x)? x : fm(b((u64)0), x);
|
||||
return r;
|
||||
}
|
||||
INS B i_FN2Oi(B w, BB2B fm, BBB2B fd, u32* bc GA1) { P(x) GS_UPD;POS_UPD;
|
||||
if (isNothing(x)) { dec(w); return x; }
|
||||
else return isNothing(w)? fm(b((u64)0), x) : fd(b((u64)0), w, x);
|
||||
}
|
||||
INS B i_ARR_0() { // TODO combine with ADDI
|
||||
return inc(bi_emptyHVec);
|
||||
}
|
||||
@ -151,12 +163,11 @@ INS B i_NSPM(B o, u32 l) {
|
||||
c(FldAlias,a)->p = l;
|
||||
return a;
|
||||
}
|
||||
INS B i_RETD(Scope** pscs GA1) {
|
||||
INS B i_RETD(Scope** pscs GA1) { GS_UPD;
|
||||
Scope* sc = pscs[0];
|
||||
Body* b = sc->body;
|
||||
ptr_inc(sc);
|
||||
ptr_inc(b->nsDesc);
|
||||
GS_UPD;
|
||||
return m_ns(sc, b->nsDesc);
|
||||
}
|
||||
|
||||
@ -171,8 +182,6 @@ INS B i_RETD(Scope** pscs GA1) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "x86_64.h"
|
||||
|
||||
#if USE_PERF
|
||||
@ -204,6 +213,110 @@ 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;
|
||||
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(u64, data, 64); // variable length; whatever things are needed for the specific action
|
||||
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;
|
||||
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];
|
||||
if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns;
|
||||
actions[f.p] = 2; cact = 3;
|
||||
TSADD(data, (u64) c(Fun, f.v)->c1);
|
||||
goto defStk;
|
||||
break;
|
||||
}
|
||||
case FN2C: { SRef f = stk[TSSIZE(stk)-2];
|
||||
if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns;
|
||||
actions[f.p] = 2; cact = 3;
|
||||
TSADD(data, (u64) c(Fun, f.v)->c2);
|
||||
goto defStk;
|
||||
break;
|
||||
}
|
||||
case FN2O: { SRef f = stk[TSSIZE(stk)-2];
|
||||
if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns;
|
||||
actions[f.p] = 2; cact = 4;
|
||||
TSADD(data, (u64) c(Fun, f.v)->c1);
|
||||
TSADD(data, (u64) c(Fun, f.v)->c2);
|
||||
goto defStk;
|
||||
break;
|
||||
}
|
||||
case RETN: case RETD:
|
||||
ret = true;
|
||||
cact = 1;
|
||||
goto defIns;
|
||||
default: defIns:;
|
||||
defStk:
|
||||
TSSIZE(stk)-= stackConsumed(sbc);
|
||||
i32 added = stackAdded(sbc);
|
||||
for (i32 i = 0; i < added; i++) TSADD(stk, SREF(bi_optOut, -1))
|
||||
}
|
||||
TSADD(actions, cact);
|
||||
#undef L64
|
||||
if (ret) break;
|
||||
bc = nextBC(sbc);
|
||||
pos++;
|
||||
}
|
||||
TSFREE(stk);
|
||||
|
||||
TSALLOC(u32, rbc, TSSIZE(actions));
|
||||
TSALLOC(u32, roff, TSSIZE(actions));
|
||||
bc = bc0;
|
||||
u64 tpos = 0, dpos = 0;
|
||||
while (true) {
|
||||
u32* sbc = bc;
|
||||
u32* ebc = nextBC(sbc);
|
||||
#define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; })
|
||||
u32 ctype = actions[tpos++];
|
||||
bool ret = false;
|
||||
u32 v = *bc++;
|
||||
u64 psz = TSSIZE(rbc);
|
||||
#define A64(X) { u64 a64=(X); TSADD(rbc, (u32)a64); TSADD(rbc, a64>>32); }
|
||||
switch (ctype) { default: UD;
|
||||
case 3: assert(v==FN1C|v==FN1O|v==FN2C);
|
||||
TSADD(rbc, v==FN1C? FN1Ci : v==FN1O? FN1Oi : FN2Ci);
|
||||
A64(data[dpos++]);
|
||||
break;
|
||||
case 4: assert(v==FN2O);
|
||||
TSADD(rbc, FN2Oi);
|
||||
A64(data[dpos++]);
|
||||
A64(data[dpos++]);
|
||||
break;
|
||||
|
||||
case 2: break; // remove
|
||||
|
||||
case 1: ret = true; goto def2; // return
|
||||
|
||||
case 0: def2:; // do nothing
|
||||
TSADDA(rbc, sbc, ebc-sbc);
|
||||
}
|
||||
u64 added = TSSIZE(rbc)-psz;
|
||||
for (i32 i = 0; i < added; i++) TSADD(roff, sbc-bc0);
|
||||
#undef A64
|
||||
if (ret) break;
|
||||
bc = ebc;
|
||||
}
|
||||
bc = bc0; pos = 0;
|
||||
|
||||
TSFREE(data);
|
||||
TSFREE(actions);
|
||||
return (OptRes){.bc = rbc, .offset = roff};
|
||||
}
|
||||
#undef SREF
|
||||
void freeOpt(OptRes o) {
|
||||
TSFREEP(o.bc);
|
||||
TSFREEP(o.offset);
|
||||
}
|
||||
|
||||
static u32 readBytes4(u8* d) {
|
||||
return d[0] | d[1]<<8 | d[2]<<16 | d[3]<<24;
|
||||
}
|
||||
@ -224,12 +337,15 @@ u8* m_nvm(Body* body) {
|
||||
if ((u64)i_SETN != (u32)(u64)i_SETN) thrM("JIT: Refusing to run with CBQN code outside of the 32-bit address range");
|
||||
// #define CCALL(F) { IMM(r_TMP, F); ASM(CALL, r_TMP, -); }
|
||||
#define CCALL(F) { TSADD(rel, ASM_SIZE); ASM(CALLI, (u32)(u64)F, -); }
|
||||
u32* bc = body->bc;
|
||||
u32* origBC = body->bc;
|
||||
OptRes optRes = opt(origBC);
|
||||
Block** blocks = body->blocks->a;
|
||||
i32 depth = 0;
|
||||
u32* bc = optRes.bc;
|
||||
while (true) {
|
||||
u32* s = bc;
|
||||
u32* n = nextBC(bc);
|
||||
u32* off = origBC + optRes.offset[s-optRes.bc];
|
||||
bool ret = false;
|
||||
#define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; })
|
||||
// #define LEA0(O,I,OFF) { ASM(MOV,O,I); ADDI(O,OFF); }
|
||||
@ -256,10 +372,14 @@ u8* m_nvm(Body* body) {
|
||||
IMM(REG_ARG0, L64); CCALL(i_ADDU);
|
||||
#endif
|
||||
break;
|
||||
case FN1C: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN1C); break; // (B, u32* bc, S)
|
||||
case FN2C: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN2C); break; // (B, u32* bc, S)
|
||||
case FN1O: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN1O); break; // (B, u32* bc, S)
|
||||
case FN2O: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN2O); break; // (B, u32* bc, S)
|
||||
case FN1C: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN1C); break; // (B, u32* bc, S)
|
||||
case FN2C: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN2C); break; // (B, u32* bc, S)
|
||||
case FN1O: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN1O); break; // (B, u32* bc, S)
|
||||
case FN2O: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN2O); break; // (B, u32* bc, S)
|
||||
case FN1Ci:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2,off); INV(3,0,i_FN1Ci); break; // (B, BB2B fm, u32* bc, S)
|
||||
case FN2Ci:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2,off); INV(3,0,i_FN2Ci); break; // (B, BBB2B fd, u32* bc, S)
|
||||
case FN1Oi:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2,off); INV(3,0,i_FN1Oi); break; // (B, BB2B fm, u32* bc, S)
|
||||
case FN2Oi:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2, L64); IMM(REG_ARG3,off); INV(4,0,i_FN2Oi); break; // (B, BB2B fm, BBB2B fd, u32* bc, S)
|
||||
case ARRM: case ARRO:;
|
||||
u32 sz = *bc++;
|
||||
if (sz) { TOPp; IMM(REG_ARG1, sz); INV(2,0,i_ARR_p); } // (B, i64 sz, S)
|
||||
@ -269,23 +389,23 @@ u8* m_nvm(Body* body) {
|
||||
Block* bl = blocks[*bc++];
|
||||
u64 fn = (u64)(bl->ty==0? i_DFND_0 : bl->ty==1? i_DFND_1 : bl->ty==2? i_DFND_2 : NULL);
|
||||
if (fn==0) thrM("JIT: Bad DFND argument");
|
||||
IMM(REG_ARG0,s); ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,bl); INV(3,1,fn);
|
||||
IMM(REG_ARG0,off); ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,bl); INV(3,1,fn);
|
||||
break;
|
||||
case OP1D: TOPp; IMM(REG_ARG1,s); INV(2,0,i_OP1D); break; // (B, u32* bc, S)
|
||||
case OP2D: TOPp; IMM(REG_ARG1,s); INV(2,0,i_OP2D); break; // (B, u32* bc, S)
|
||||
case OP1D: TOPp; IMM(REG_ARG1,off); INV(2,0,i_OP1D); break; // (B, u32* bc, S)
|
||||
case OP2D: TOPp; IMM(REG_ARG1,off); INV(2,0,i_OP2D); break; // (B, u32* bc, S)
|
||||
case OP2H: TOPp; INV(1,0,i_OP2H); break; // (B, S)
|
||||
case TR2D: TOPp; INV(1,0,i_TR2D); break; // (B, S)
|
||||
case TR3D: TOPp; INV(1,0,i_TR3D); break; // (B, S)
|
||||
case TR3O: TOPp; INV(1,0,i_TR3O); break; // (B, S)
|
||||
case LOCM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(REG_RES, tag((u64)d<<32 | (u32)p, VAR_TAG).u); } break;
|
||||
case EXTM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(REG_RES, tag((u64)d<<32 | (u32)p, EXT_TAG).u); } break;
|
||||
case LOCO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,s); INV(4,1,i_LOCO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S)
|
||||
case EXTO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,s); INV(4,1,i_EXTO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S)
|
||||
case LOCO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,off); INV(4,1,i_LOCO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S)
|
||||
case EXTO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,off); INV(4,1,i_EXTO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S)
|
||||
case LOCU: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); CCALL(i_LOCU); break; // (u32 d, u32 p, Scope** pscs, S)
|
||||
case EXTU: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); CCALL(i_EXTU); break; // (u32 d, u32 p, Scope** pscs, S)
|
||||
case SETN: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,s); INV(3,0,i_SETN); break; // (B, Scope** pscs, u32* bc, S)
|
||||
case SETU: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,s); INV(3,0,i_SETU); break; // (B, Scope** pscs, u32* bc, S)
|
||||
case SETM: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,s); INV(3,0,i_SETM); break; // (B, Scope** pscs, u32* bc, S)
|
||||
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 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
|
||||
@ -301,6 +421,7 @@ u8* m_nvm(Body* body) {
|
||||
depth+= stackDiff(s);
|
||||
if (ret) break;
|
||||
}
|
||||
freeOpt(optRes);
|
||||
ASM(POP, r_CS, -);
|
||||
ASM(POP, r_PSCS, -);
|
||||
ASM(POP, r_TMP, -);
|
||||
|
||||
@ -17,6 +17,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../core.h"
|
||||
#include "../utils/talloc.h"
|
||||
|
||||
// 16 integer registers:
|
||||
// 0 1 2 (0: not saved, 1: callee saves, 2: caller saves)
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "../core.h"
|
||||
#include "file.h"
|
||||
#include "mut.h"
|
||||
#include "talloc.h"
|
||||
|
||||
FILE* file_open(B path, char* desc, char* mode) { // doesn't consume
|
||||
u64 plen = utf8lenB(path);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "wyhash.h"
|
||||
#include "talloc.h"
|
||||
|
||||
extern u64 wy_secret[4];
|
||||
|
||||
|
||||
35
src/utils/talloc.h
Normal file
35
src/utils/talloc.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct TAlloc {
|
||||
struct Value;
|
||||
u8 data[];
|
||||
} TAlloc;
|
||||
#define TOFF offsetof(TAlloc, data)
|
||||
#define TALLOC(T,N,AM) T* N = (T*) ((TAlloc*)mm_allocN(TOFF + (AM)*sizeof(T) + 8, t_temp))->data; // +8 so mm is happy
|
||||
#define TOBJ(N) (void*)((u8*)(N) - TOFF)
|
||||
#define TFREE(N) mm_free((Value*)TOBJ(N));
|
||||
#define TREALLOC(N, AM) talloc_realloc(TOBJ(N), AM)
|
||||
#define TSIZE(N) (mm_size(TOBJ(N))-TOFF)
|
||||
static inline void* talloc_realloc(TAlloc* t, u64 am) { // TODO maybe shouldn't be inline?
|
||||
u64 stored = mm_size((Value*)t)-TOFF;
|
||||
if (stored > am) return t->data;
|
||||
TALLOC(u8,r,am);
|
||||
memcpy(r, t->data, stored);
|
||||
mm_free((Value*)t);
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef struct TStack {
|
||||
struct Value;
|
||||
usz size;
|
||||
usz cap;
|
||||
u8 data[];
|
||||
} TStack;
|
||||
#define TSALLOC(T,N,I) usz N##_dc=(I); u32 N##_e=sizeof(T); TStack* N##_o = (TStack*)mm_allocN(sizeof(TStack)+N##_e*N##_dc, t_temp); N##_o->size=0; N##_o->cap=N##_dc; T* N = (T*)N##_o->data;
|
||||
#define TSFREE(N) mm_free((Value*)N##_o);
|
||||
#define TSUPD(N,AM) { N##_o = ts_e(N##_o, N##_e, AM); N = (void*)N##_o->data; }
|
||||
#define TSADD(N,X) { if (N##_o->size==N##_o->cap) TSUPD(N, 1); N[N##_o->size++] = X; }
|
||||
#define TSADDA(N,P,AM) { u64 n=AM; if(N##_o->size+n>N##_o->cap) TSUPD(N, n); memcpy(N+N##_o->size,P,n*N##_e); N##_o->size+= n; }
|
||||
#define TSFREEP(N) mm_free((void*)RFLD(N, TStack, data));
|
||||
#define TSSIZE(N) (N##_o->size)
|
||||
TStack* ts_e(TStack* o, u32 elsz, u64 am);
|
||||
33
src/vm.c
33
src/vm.c
@ -4,6 +4,7 @@
|
||||
#include "jit/nvm.h"
|
||||
#include "ns.h"
|
||||
#include "utils/utf.h"
|
||||
#include "utils/talloc.h"
|
||||
|
||||
#ifndef USE_JIT
|
||||
#define USE_JIT 0 // enable the extremely basic x86-64 JIT that mostly just generates MOVs and CALLs
|
||||
@ -13,7 +14,7 @@
|
||||
#define FOR_BC(F) F(PUSH) F(VARO) F(VARM) F(ARRO) F(ARRM) F(FN1C) F(FN2C) F(OP1D) F(OP2D) F(TR2D) \
|
||||
F(TR3D) F(SETN) F(SETU) F(SETM) F(POPS) F(DFND) F(FN1O) F(FN2O) F(CHKV) F(TR3O) \
|
||||
F(OP2H) F(LOCO) F(LOCM) F(VFYM) F(SETH) F(RETN) F(FLDO) F(FLDM) F(NSPM) F(RETD) F(SYSV) F(LOCU) \
|
||||
F(EXTO) F(EXTM) F(EXTU)
|
||||
F(EXTO) F(EXTM) F(EXTU) F(ADDI) F(ADDU) F(FN1Ci)F(FN1Oi)F(FN2Ci)F(FN2Oi)
|
||||
|
||||
u32* nextBC(u32* p) {
|
||||
switch(*p) {
|
||||
@ -29,21 +30,36 @@ u32* nextBC(u32* p) {
|
||||
return p+2;
|
||||
case LOCO: case LOCM: case LOCU:
|
||||
case EXTO: case EXTM: case EXTU:
|
||||
case ADDI: case ADDU:
|
||||
case ADDI: case ADDU: case FN1Ci: case FN1Oi: case FN2Ci:
|
||||
return p+3;
|
||||
case FN2Oi:
|
||||
return p+5;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
i32 stackDiff(u32* p) {
|
||||
switch(*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 CHKV: case VFYM: case FLDO: case FLDM: case RETD: case NSPM: return 0;
|
||||
case FN1C: case OP1D: case TR2D: case SETN: case SETU: case POPS: case FN1O: case OP2H: case SETH: case RETN: return -1;
|
||||
case FN2C: case OP2D: case TR3D: case SETM: case FN2O: case TR3O: return -2;
|
||||
case ARRO: case ARRM: return 1-p[1];
|
||||
default: return 9999999;
|
||||
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 OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return -2;
|
||||
}
|
||||
}
|
||||
i32 stackConsumed(u32* p) {
|
||||
if (*p==ARRO|*p==ARRM) return p[1];
|
||||
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 OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return 3;
|
||||
}
|
||||
}
|
||||
i32 stackAdded(u32* p) {
|
||||
if (*p==ARRO|*p==ARRM) return 1;
|
||||
return stackDiff(p)+stackConsumed(p);
|
||||
}
|
||||
char* nameBC(u32* p) {
|
||||
switch(*p) { default: return "(unknown)";
|
||||
#define F(X) case X: return #X;
|
||||
@ -184,6 +200,7 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B block
|
||||
break;
|
||||
}
|
||||
}
|
||||
#undef A64
|
||||
usz nlen = TSSIZE(nBCT)-TSSIZE(mapT);
|
||||
for (usz i = 0; i < nlen; i++) TSADD(mapT, c-bc);
|
||||
h+= stackDiff(c);
|
||||
|
||||
6
src/vm.h
6
src/vm.h
@ -34,7 +34,8 @@ enum {
|
||||
SYSV = 30, // N; get system function N
|
||||
LOCU = 31, // N0,N1; like LOCO but overrides the slot with bi_optOut
|
||||
EXTO, EXTM, EXTU, // alternate versions of LOC_ for extended variables
|
||||
ADDI, ADDU, // separate PUSH for refcounting needed/not needed (stores the object inline, instead of reading from `objs`)
|
||||
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
|
||||
BC_SIZE
|
||||
};
|
||||
|
||||
@ -106,6 +107,9 @@ B evalBC(Body* b, Scope* sc); // doesn't consume; executes bytecode of the body
|
||||
|
||||
u32* nextBC(u32* p);
|
||||
i32 stackDiff(u32* p);
|
||||
i32 stackConsumed(u32* p);
|
||||
i32 stackAdded(u32* p);
|
||||
char* nameBC(u32* p);
|
||||
|
||||
|
||||
typedef struct FunBlock { struct Fun; Scope* sc; Block* bl; } FunBlock;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user