move TAlloc/TStack around, immediate functions

This commit is contained in:
dzaima 2021-06-15 01:20:32 +03:00
parent d2a1d7c329
commit 1afe46b393
15 changed files with 236 additions and 78 deletions

View File

@ -1,6 +1,7 @@
#include "../core.h" #include "../core.h"
#include "../utils/hash.h" #include "../utils/hash.h"
#include "../utils/mut.h" #include "../utils/mut.h"
#include "../utils/talloc.h"
#include "../nfns.h" #include "../nfns.h"

View File

@ -1,5 +1,6 @@
#include "../core.h" #include "../core.h"
#include "../utils/builtins.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_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); } 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); }

View File

@ -2,6 +2,7 @@
#include "../utils/each.h" #include "../utils/each.h"
#include "../utils/mut.h" #include "../utils/mut.h"
#include "../utils/builtins.h" #include "../utils/builtins.h"
#include "../utils/talloc.h"
B shape_c1(B t, B x) { B shape_c1(B t, B x) {

View File

@ -1,4 +1,5 @@
#include "../core.h" #include "../core.h"
#include "../utils/talloc.h"

View File

@ -1,5 +1,7 @@
#include "../core.h" #include "../core.h"
u64 allocB; // currently allocated number of bytes
#if MM==0 #if MM==0
#include "../opt/mm_malloc.c" #include "../opt/mm_malloc.c"
#elif MM==1 #elif MM==1

View File

@ -1,17 +1,22 @@
#include "../core.h" #include "../core.h"
#include "../utils/mut.h" #include "../utils/mut.h"
#include "../utils/utf.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; B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec;
NOINLINE TStack* tstack_ext(TStack* o, u32 elsz) { NOINLINE TStack* ts_e(TStack* o, u32 elsz, u64 am) { u64 size = o->size;
usz ncap = o->cap*2; u64 alsz = mm_round(fsizeof(TStack, data, u8, (size+am)*elsz));
TStack* n = (TStack*)mm_allocN(sizeof(TStack) + elsz*ncap, t_temp); TStack* n;
memcpy(n->data, o->data, o->cap*elsz); if (alsz==mm_size((Value*)o)) {
n->cap = ncap; n = o;
n->size = o->size; } else {
mm_free((Value*)o); 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; return n;
} }

View File

@ -21,39 +21,6 @@ static B mm_alloc(usz sz, u8 type, u64 tag) {
#define MAP_NORESERVE 0 // apparently needed for freebsd or something #define MAP_NORESERVE 0 // apparently needed for freebsd or something
#endif #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 // shape mess
typedef struct ShArr { typedef struct ShArr {

View File

@ -106,7 +106,7 @@
#define AUTO __auto_type #define AUTO __auto_type
#define LIKELY(X) __builtin_expect(X,1) #define LIKELY(X) __builtin_expect(X,1)
#define RARE(X) __builtin_expect(X,0) #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 N64x "%"SCNx64
#define N64d "%"SCNd64 #define N64d "%"SCNd64
#define N64u "%"SCNu64 #define N64u "%"SCNu64
@ -122,7 +122,7 @@ typedef u8 ur;
CTR_FOR(F) CTR_FOR(F)
#undef 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 ftag(x) ((u64)(x) << 48)
#define tag(v, t) b(((u64)(v)) | ftag(t)) #define tag(v, t) b(((u64)(v)) | ftag(t))
// .111111111110000000000000000000000000000000000000000000000000000 infinity // .111111111110000000000000000000000000000000000000000000000000000 infinity

View File

@ -2,6 +2,7 @@
#include "../core/gstack.h" #include "../core/gstack.h"
#include "../ns.h" #include "../ns.h"
#include "../utils/file.h" #include "../utils/file.h"
#include "../utils/talloc.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
@ -45,7 +46,7 @@ static void* mmX_allocN(usz sz, u8 type) { assert(sz>=16); return mmX_allocL(BSZ
#endif #endif
#define P(N) B N=GSP; #define P(N) B N=GSP;
#if VM_POS #if VM_POS
#define POS_UPD (envCurr-1)->bcL = bc-1; #define POS_UPD (envCurr-1)->bcL = bc;
#else #else
#define POS_UPD #define POS_UPD
#endif #endif
@ -61,28 +62,39 @@ INS B i_ADDI(u64 v) {
INS B i_ADDU(u64 v) { INS B i_ADDU(u64 v) {
return b(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 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
GS_UPD;POS_UPD;
B r = c1(f, x); B r = c1(f, x);
dec(f); return r; dec(f); return r;
} }
INS B i_FN1O(B f, u32* bc GA1) { P(x) INS B i_FN1O(B f, u32* bc GA1) { P(x) GS_UPD;POS_UPD;
GS_UPD;POS_UPD;
B r = isNothing(x)? x : c1(f, x); B r = isNothing(x)? x : c1(f, x);
dec(f); return r; dec(f); return r;
} }
INS B i_FN2C(B w, u32* bc GA1) { P(f)P(x) INS B i_FN2C(B w, u32* bc GA1) { P(f)P(x) GS_UPD;POS_UPD;
GS_UPD;POS_UPD;
B r = c2(f, w, x); B r = c2(f, w, x);
dec(f); return r; dec(f); return r;
} }
INS B i_FN2O(B w, u32* bc GA1) { P(f)P(x) INS B i_FN2O(B w, u32* bc GA1) { P(f)P(x) GS_UPD;POS_UPD;
GS_UPD;POS_UPD; B r; B r;
if (isNothing(x)) { dec(w); r = x; } if (isNothing(x)) { dec(w); r = x; }
else r = isNothing(w)? c1(f, x) : c2(f, w, x); else r = isNothing(w)? c1(f, x) : c2(f, w, x);
dec(f); dec(f);
return r; 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 INS B i_ARR_0() { // TODO combine with ADDI
return inc(bi_emptyHVec); return inc(bi_emptyHVec);
} }
@ -151,12 +163,11 @@ INS B i_NSPM(B o, u32 l) {
c(FldAlias,a)->p = l; c(FldAlias,a)->p = l;
return a; return a;
} }
INS B i_RETD(Scope** pscs GA1) { INS B i_RETD(Scope** pscs GA1) { GS_UPD;
Scope* sc = pscs[0]; Scope* sc = pscs[0];
Body* b = sc->body; Body* b = sc->body;
ptr_inc(sc); ptr_inc(sc);
ptr_inc(b->nsDesc); ptr_inc(b->nsDesc);
GS_UPD;
return m_ns(sc, b->nsDesc); return m_ns(sc, b->nsDesc);
} }
@ -171,8 +182,6 @@ INS B i_RETD(Scope** pscs GA1) {
#include "x86_64.h" #include "x86_64.h"
#if USE_PERF #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) { static u32 readBytes4(u8* d) {
return d[0] | d[1]<<8 | d[2]<<16 | d[3]<<24; 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"); 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) { IMM(r_TMP, F); ASM(CALL, r_TMP, -); }
#define CCALL(F) { TSADD(rel, ASM_SIZE); ASM(CALLI, (u32)(u64)F, -); } #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; Block** blocks = body->blocks->a;
i32 depth = 0; i32 depth = 0;
u32* bc = optRes.bc;
while (true) { while (true) {
u32* s = bc; u32* s = bc;
u32* n = nextBC(bc); u32* n = nextBC(bc);
u32* off = origBC + optRes.offset[s-optRes.bc];
bool ret = false; bool ret = false;
#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; })
// #define LEA0(O,I,OFF) { ASM(MOV,O,I); ADDI(O,OFF); } // #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); IMM(REG_ARG0, L64); CCALL(i_ADDU);
#endif #endif
break; break;
case FN1C: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN1C); 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, s); INV(2,0,i_FN2C); 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, s); INV(2,0,i_FN1O); 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, s); INV(2,0,i_FN2O); 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:; case ARRM: case ARRO:;
u32 sz = *bc++; u32 sz = *bc++;
if (sz) { TOPp; IMM(REG_ARG1, sz); INV(2,0,i_ARR_p); } // (B, i64 sz, S) 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++]; 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); 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"); 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; break;
case OP1D: TOPp; IMM(REG_ARG1,s); INV(2,0,i_OP1D); 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,s); INV(2,0,i_OP2D); 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 OP2H: TOPp; INV(1,0,i_OP2H); break; // (B, S)
case TR2D: TOPp; INV(1,0,i_TR2D); 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 TR3D: TOPp; INV(1,0,i_TR3D); break; // (B, S)
case TR3O: TOPp; INV(1,0,i_TR3O); 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 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 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 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,s); INV(4,1,i_EXTO); 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 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 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 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,s); INV(3,0,i_SETU); 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,s); INV(3,0,i_SETM); 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 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 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 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); depth+= stackDiff(s);
if (ret) break; if (ret) break;
} }
freeOpt(optRes);
ASM(POP, r_CS, -); ASM(POP, r_CS, -);
ASM(POP, r_PSCS, -); ASM(POP, r_PSCS, -);
ASM(POP, r_TMP, -); ASM(POP, r_TMP, -);

View File

@ -17,6 +17,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#pragma once #pragma once
#include "../core.h" #include "../core.h"
#include "../utils/talloc.h"
// 16 integer registers: // 16 integer registers:
// 0 1 2 (0: not saved, 1: callee saves, 2: caller saves) // 0 1 2 (0: not saved, 1: callee saves, 2: caller saves)

View File

@ -2,6 +2,7 @@
#include "../core.h" #include "../core.h"
#include "file.h" #include "file.h"
#include "mut.h" #include "mut.h"
#include "talloc.h"
FILE* file_open(B path, char* desc, char* mode) { // doesn't consume FILE* file_open(B path, char* desc, char* mode) { // doesn't consume
u64 plen = utf8lenB(path); u64 plen = utf8lenB(path);

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "wyhash.h" #include "wyhash.h"
#include "talloc.h"
extern u64 wy_secret[4]; extern u64 wy_secret[4];

35
src/utils/talloc.h Normal file
View 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);

View File

@ -4,6 +4,7 @@
#include "jit/nvm.h" #include "jit/nvm.h"
#include "ns.h" #include "ns.h"
#include "utils/utf.h" #include "utils/utf.h"
#include "utils/talloc.h"
#ifndef USE_JIT #ifndef USE_JIT
#define USE_JIT 0 // enable the extremely basic x86-64 JIT that mostly just generates MOVs and CALLs #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) \ #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(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(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) { u32* nextBC(u32* p) {
switch(*p) { switch(*p) {
@ -29,21 +30,36 @@ u32* nextBC(u32* p) {
return p+2; return p+2;
case LOCO: case LOCM: case LOCU: case LOCO: case LOCM: case LOCU:
case EXTO: case EXTM: case EXTU: case EXTO: case EXTM: case EXTU:
case ADDI: case ADDU: case ADDI: case ADDU: case FN1Ci: case FN1Oi: case FN2Ci:
return p+3; return p+3;
case FN2Oi:
return p+5;
default: return 0; default: return 0;
} }
} }
i32 stackDiff(u32* p) { 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 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 FN1Ci:case FN1Oi: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 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 FN2C: case OP2D: case TR3D: case SETM: case FN2O: case TR3O: return -2; case OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return -2;
case ARRO: case ARRM: return 1-p[1];
default: return 9999999;
} }
} }
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) { char* nameBC(u32* p) {
switch(*p) { default: return "(unknown)"; switch(*p) { default: return "(unknown)";
#define F(X) case X: return #X; #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; break;
} }
} }
#undef A64
usz nlen = TSSIZE(nBCT)-TSSIZE(mapT); usz nlen = TSSIZE(nBCT)-TSSIZE(mapT);
for (usz i = 0; i < nlen; i++) TSADD(mapT, c-bc); for (usz i = 0; i < nlen; i++) TSADD(mapT, c-bc);
h+= stackDiff(c); h+= stackDiff(c);

View File

@ -34,7 +34,8 @@ enum {
SYSV = 30, // N; get system function N SYSV = 30, // N; get system function N
LOCU = 31, // N0,N1; like LOCO but overrides the slot with bi_optOut LOCU = 31, // N0,N1; like LOCO but overrides the slot with bi_optOut
EXTO, EXTM, EXTU, // alternate versions of LOC_ for extended variables 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 BC_SIZE
}; };
@ -106,6 +107,9 @@ B evalBC(Body* b, Scope* sc); // doesn't consume; executes bytecode of the body
u32* nextBC(u32* p); u32* nextBC(u32* p);
i32 stackDiff(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; typedef struct FunBlock { struct Fun; Scope* sc; Block* bl; } FunBlock;