From 5e0bda6a280e8171271238c36e67e5bf5119d7fe Mon Sep 17 00:00:00 2001 From: dzaima Date: Tue, 14 Jun 2022 02:09:41 +0300 Subject: [PATCH] ARMO & ARMM --- src/h.h | 2 +- src/jit/nvm_x86_64.c | 26 ++++++++++-- src/vm.c | 97 ++++++++++++++++++++++++++++++++++---------- src/vm.h | 11 +++-- 4 files changed, 106 insertions(+), 30 deletions(-) diff --git a/src/h.h b/src/h.h index 20d4688d..72ac9c37 100644 --- a/src/h.h +++ b/src/h.h @@ -223,7 +223,7 @@ typedef union B { /*31*/ F(bitarr) \ \ /*32*/ F(comp) F(block) F(body) F(scope) F(scopeExt) F(blBlocks) F(arbObj) F(ffiType) \ - /*40*/ F(ns) F(nsDesc) F(fldAlias) F(vfyObj) F(hashmap) F(temp) F(nfn) F(nfnDesc) \ + /*40*/ F(ns) F(nsDesc) F(fldAlias) F(arrMerge) F(vfyObj) F(hashmap) F(temp) F(nfn) F(nfnDesc) \ /*48*/ F(freed) F(harrPartial) F(customObj) F(mmapH) \ \ /*51*/ IF_WRAP(F(funWrap) F(md1Wrap) F(md2Wrap)) diff --git a/src/jit/nvm_x86_64.c b/src/jit/nvm_x86_64.c index 8a62b1a0..c39cb4aa 100644 --- a/src/jit/nvm_x86_64.c +++ b/src/jit/nvm_x86_64.c @@ -121,6 +121,22 @@ INS B i_ARR_p(B el0, i64 sz, B* cStack) { assert(sz>0); if (allNum) return num_squeeze(r.b); return r.b; } +INS B i_ARMO(B el0, i64 sz, B* cStack) { assert(sz>0); + HArr_p r = m_harrUv(sz); + r.a[sz-1] = el0; + for (i64 i = 1; i < sz; i++) r.a[sz-i-1] = GSP; + GS_UPD; + return bqn_merge(r.b); +} +INS B i_ARMM(B el0, i64 sz, B* cStack) { assert(sz>0); + HArr_p r = m_harrUv(sz); // can't use harrs as gStack isn't updated + r.a[sz-1] = el0; + for (i64 i = 1; i < sz; i++) r.a[sz-i-1] = GSP; + GS_UPD; + WrappedObj* a = mm_alloc(sizeof(WrappedObj), t_arrMerge); + a->obj = r.b; + return tag(a,OBJ_TAG); +} INS B i_DFND_0(u32* bc, Scope* sc, Block* bl) { POS_UPD; return evalFunBlock(bl, sc); } INS B i_DFND_1(u32* bc, Scope* sc, Block* bl) { POS_UPD; return m_md1Block(bl, sc); } // TODO these only fail on oom, so no need to update pos INS B i_DFND_2(u32* bc, Scope* sc, Block* bl) { POS_UPD; return m_md2Block(bl, sc); } @@ -200,7 +216,7 @@ INS B i_FLDO(B ns, u32 p, Scope* sc) { return r; } INS B i_VFYM(B o) { // TODO this and ALIM allocate and thus can error on OOM - VfyObj* a = mm_alloc(sizeof(VfyObj), t_vfyObj); + WrappedObj* a = mm_alloc(sizeof(WrappedObj), t_vfyObj); a->obj = o; return tag(a,OBJ_TAG); } @@ -597,13 +613,15 @@ Nvm_res m_nvm(Body* body) { case FN2Ci: { u64 fn = L64; POS_UPD(R_A0,R_A3); MOV(R_A1, R_RES); GET(R_A2,1,1); CCALL(fn); } break; case FN1Oi:TOPp; GET(R_A1,0,2); IMM(R_A1,L64); IMM(R_A2,off); CCALL(i_FN1Oi); break; // ( B x, BB2B fm, u32* bc) case FN2Oi:TOPp; GET(R_A1,1,1); IMM(R_A2,L64); IMM(R_A3, L64); IMM(R_A4,off); CCALL(i_FN2Oi); break; // (B w, B x, BB2B fm, BBB2B fd, u32* bc) - case ARRM: case ARRO:; bool o = *(bc-1) == ARRO; + case ARRM: case ARRO:; { bool o = *(bc-1) == ARRO; u32 sz = *bc++; if (sz==0 ) { TOPs; CCALL(i_ARR_0); } // unused with optimizations else if (sz==1 && o) { TOPp; GET(R_A3,0,2); CCALL(m_vec1); } // (B a) else if (sz==2 && o) { TOPpR(R_A1); GET(R_A0,1,1); CCALL(m_vec2); } // (B a, B b) else { TOPp; IMM(R_A1, sz); lGPos=SPOSq(1-sz); INV(2,0,i_ARR_p); } // (B a, i64 sz, S) - break; + } break; + case ARMO: { u32 sz = *bc++; TOPp; IMM(R_A1, sz); lGPos=SPOSq(1-sz); INV(2,0,i_ARMO); break; } + case ARMM: { u32 sz = *bc++; TOPp; IMM(R_A1, sz); lGPos=SPOSq(1-sz); INV(2,0,i_ARMM); break; } case DFND0: case DFND1: case DFND2: TOPs; // (u32* bc, Scope* sc, Block* bl) Block* bl = (Block*)L64; u64 fn = (u64)(bl->ty==0? i_DFND_0 : bl->ty==1? i_DFND_1 : bl->ty==2? i_DFND_2 : NULL); @@ -654,7 +672,7 @@ Nvm_res m_nvm(Body* body) { case RETD: if (lGPos!=0) GS_SET(r_CS); MOV(R_A0,r_SC); CCALL(i_RETD); ret=true; break; // (Scope* sc) case RETN: if (lGPos!=0) GS_SET(r_CS); ret=true; break; case FAIL: TOPs; IMM(R_A0,off); MOV(R_A1,r_SC); INV(2,0,i_FAIL); ret=true; break; - default: print_fmt("JIT: Unsupported bytecode %i/%S", *s, bc_repr(*s)); err(""); + default: print_fmt("JIT: Unsupported bytecode %i/%S\n", *s, bc_repr(*s)); err(""); } #undef GET #undef GS_SET diff --git a/src/vm.c b/src/vm.c index 0526e53b..aa1099cd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -11,7 +11,7 @@ #define UNWIND_COMPILER 1 #endif -#define FOR_BC(F) F(PUSH) F(DYNO) F(DYNM) F(ARRO) F(ARRM) F(FN1C) F(FN2C) F(MD1C) F(MD2C) F(TR2D) \ +#define FOR_BC(F) F(PUSH) F(DYNO) F(DYNM) F(ARRO) F(ARRM) F(ARMO) F(ARMM) F(FN1C) F(FN2C) F(MD1C) F(MD2C) F(TR2D) \ F(TR3D) F(SETN) F(SETU) F(SETM) F(SETC) F(POPS) F(DFND) F(FN1O) F(FN2O) F(CHKV) F(TR3O) \ F(MD2R) F(MD2L) F(VARO) F(VARM) F(VFYM) F(SETH) F(RETN) F(FLDO) F(FLDM) F(ALIM) F(NOTM) F(RETD) F(SYSV) F(VARU) F(PRED) \ F(EXTO) F(EXTM) F(EXTU) F(ADDI) F(ADDU) F(FN1Ci)F(FN1Oi)F(FN2Ci)F(FN2Oi) \ @@ -473,6 +473,38 @@ NOINLINE Block* compile(B bcq, B objs, B allBlocks, B allBodies, B indices, B to +FORCE_INLINE bool v_merge(Scope* pscs[], B s, B x, bool upd, bool hdr) { + B o = c(WrappedObj,s)->obj; + if (!isArr(x) || rnk(x)==0) thrF("[…]%S𝕩: 𝕩 cannot have rank 0", upd? "↩" : "←"); + + B* op = harr_ptr(o); + usz oia = a(o)->ia; + + if (a(x)->sh[0] != oia) { + if (hdr) return false; + else thrF("[…]%S𝕩: Target length & leading axis of 𝕩 didn't match", upd? "↩" : "←"); + } + + if (rnk(x)==1) { + SGet(x) + for (usz i = 0; i < oia; i++) { + B cx = m_unit(Get(x,i)); + if (!hdr) v_set (pscs, op[i], cx, upd, true); + else if (!v_seth(pscs, op[i], cx)) { dec(cx); return false; } + dec(cx); + } + return true; + } else { + B cells = toCells(inc(x)); + B* xp = harr_ptr(cells); + for (usz i = 0; i < oia; i++) { + if (!hdr) v_set (pscs, op[i], xp[i], upd, true); + else if (!v_seth(pscs, op[i], xp[i])) { dec(cells); return false; } + } + dec(cells); + return true; + } +} NOINLINE void v_setF(Scope* pscs[], B s, B x, bool upd) { if (isArr(s)) { VTY(s, t_harr); @@ -500,6 +532,8 @@ NOINLINE void v_setF(Scope* pscs[], B s, B x, bool upd) { for (u64 i = 0; i < ia; i++) v_set(pscs, sp[i], GetU(x,i), upd, true); } else if (s.u == bi_N.u) { return; + } else if (isObj(s)) { + v_merge(pscs, s, x, upd, false); } else { assert(isExt(s)); Scope* sc = pscs[(u16)(s.u>>32)]; B prev = sc->ext->vars[(u32)s.u]; @@ -511,7 +545,8 @@ NOINLINE void v_setF(Scope* pscs[], B s, B x, bool upd) { } } NOINLINE bool v_sethF(Scope* pscs[], B s, B x) { - if (v(s)->type==t_vfyObj) return equal(c(VfyObj,s)->obj,x); + if (v(s)->type==t_vfyObj) return equal(c(WrappedObj,s)->obj,x); + if (v(s)->type==t_arrMerge) return v_merge(pscs, s, x, false, true); VTY(s, t_harr); B* sp = harr_ptr(s); usz ia = a(s)->ia; @@ -813,12 +848,30 @@ B evalBC(Body* b, Scope* sc, Block* bl) { // doesn't consume break; } case VFYM: { P(o) GS_UPD; - VfyObj* a = mm_alloc(sizeof(VfyObj), t_vfyObj); + WrappedObj* a = mm_alloc(sizeof(WrappedObj), t_vfyObj); a->obj = o; ADD(tag(a,OBJ_TAG)); break; } case FAIL: thrM(q_N(sc->vars[2])? "This block cannot be called monadically" : "This block cannot be called dyadically"); + case ARMO: { + u32 sz = *bc++; + assert(sz>0); + HArr_p r = m_harrUv(sz); + for (i64 i = 0; i < sz; i++) r.a[sz-i-1] = POP; + ADD(bqn_merge(r.b)); + break; + } + case ARMM: { + u32 sz = *bc++; + assert(sz>0); + HArr_p r = m_harrUv(sz); + for (i64 i = 0; i < sz; i++) r.a[sz-i-1] = POP; + WrappedObj* a = mm_alloc(sizeof(WrappedObj), t_arrMerge); + a->obj = r.b; + ADD(tag(a,OBJ_TAG)); + break; + } case RETD: { GS_UPD; ADD(m_ns(ptr_inc(sc), ptr_inc(b->nsDesc))); @@ -979,8 +1032,8 @@ DEF_FREE(comp) { Comp* c = (Comp *)x; if (c->objs!=NULL) ptr_decR(c->obj DEF_FREE(funBl) { FunBlock* c = (FunBlock*)x; ptr_dec(c->sc); ptr_decR(c->bl); } DEF_FREE(md1Bl) { Md1Block* c = (Md1Block*)x; ptr_dec(c->sc); ptr_decR(c->bl); } DEF_FREE(md2Bl) { Md2Block* c = (Md2Block*)x; ptr_dec(c->sc); ptr_decR(c->bl); } -DEF_FREE(alias) { dec(((FldAlias*)x)->obj); } -DEF_FREE(vfymO) { dec(((VfyObj* )x)->obj); } +DEF_FREE(alias) { dec(((FldAlias* )x)->obj); } +DEF_FREE(wrobj) { dec(((WrappedObj*)x)->obj); } DEF_FREE(bBlks) { BlBlocks* c = (BlBlocks*)x; u16 am = c->am; for (i32 i = 0; i < am; i++) ptr_dec(c->a[i]); } DEF_FREE(scExt) { ScopeExt* c = (ScopeExt*)x; u16 am = c->varAm*2; for (i32 i = 0; i < am; i++) dec(c->vars[i]); } @@ -1013,8 +1066,8 @@ void comp_visit(Value* x) { Comp* c = (Comp *)x; mm_visitP(c->objs); mm_ void funBl_visit(Value* x) { FunBlock* c = (FunBlock*)x; mm_visitP(c->sc); mm_visitP(c->bl); } void md1Bl_visit(Value* x) { Md1Block* c = (Md1Block*)x; mm_visitP(c->sc); mm_visitP(c->bl); } void md2Bl_visit(Value* x) { Md2Block* c = (Md2Block*)x; mm_visitP(c->sc); mm_visitP(c->bl); } -void alias_visit(Value* x) { mm_visit(((FldAlias*)x)->obj); } -void vfymO_visit(Value* x) { mm_visit(((VfyObj* )x)->obj); } +void alias_visit(Value* x) { mm_visit(((FldAlias* )x)->obj); } +void wrobj_visit(Value* x) { mm_visit(((WrappedObj*)x)->obj); } void bBlks_visit(Value* x) { BlBlocks* c = (BlBlocks*)x; u16 am = c->am; for (i32 i = 0; i < am; i++) mm_visitP(c->a[i]); } void scExt_visit(Value* x) { ScopeExt* c = (ScopeExt*)x; u16 am = c->varAm*2; for (i32 i = 0; i < am; i++) mm_visit(c->vars[i]); } @@ -1024,6 +1077,7 @@ void block_print(FILE* f, B x) { fprintf(f,"(%p: block)",v(x)); } void scope_print(FILE* f, B x) { fprintf(f,"(%p: scope; vars:",v(x));Scope*sc=c(Scope,x);for(u64 i=0;ivarAm;i++){fprintf(f," ");fprint(f,sc->vars[i]);}fprintf(f,")"); } void alias_print(FILE* f, B x) { fprintf(f,"(alias %d of ", c(FldAlias,x)->p); fprint(f,c(FldAlias,x)->obj); fprintf(f,")"); } void vfymO_print(FILE* f, B x) { fprint(f,c(FldAlias,x)->obj); } +void marrO_print(FILE* f, B x) { fprintf(f,"["); fprint(f,c(FldAlias,x)->obj); fprintf(f,"]"); } void bBlks_print(FILE* f, B x) { fprintf(f,"(block list)"); } void scExt_print(FILE* f, B x) { fprintf(f,"(scope extension with %d vars)", c(ScopeExt,x)->varAm); } @@ -1071,17 +1125,18 @@ void print_vmStack() { B oomMessage; void comp_init() { - TIi(t_comp ,freeO) = comp_freeO; TIi(t_comp ,freeF) = comp_freeF; TIi(t_comp ,visit) = comp_visit; TIi(t_comp ,print) = comp_print; - TIi(t_body ,freeO) = body_freeO; TIi(t_body ,freeF) = body_freeF; TIi(t_body ,visit) = body_visit; TIi(t_body ,print) = body_print; - TIi(t_block ,freeO) = block_freeO; TIi(t_block ,freeF) = block_freeF; TIi(t_block ,visit) = block_visit; TIi(t_block ,print) = block_print; - TIi(t_scope ,freeO) = scope_freeO; TIi(t_scope ,freeF) = scope_freeF; TIi(t_scope ,visit) = scope_visit; TIi(t_scope ,print) = scope_print; - TIi(t_scopeExt ,freeO) = scExt_freeO; TIi(t_scopeExt,freeF) = scExt_freeF; TIi(t_scopeExt,visit) = scExt_visit; TIi(t_scopeExt,print) = scExt_print; - TIi(t_blBlocks ,freeO) = bBlks_freeO; TIi(t_blBlocks,freeF) = bBlks_freeF; TIi(t_blBlocks,visit) = bBlks_visit; TIi(t_blBlocks,print) = bBlks_print; - TIi(t_fldAlias ,freeO) = alias_freeO; TIi(t_fldAlias,freeF) = alias_freeF; TIi(t_fldAlias,visit) = alias_visit; TIi(t_fldAlias,print) = alias_print; - TIi(t_vfyObj ,freeO) = vfymO_freeO; TIi(t_vfyObj ,freeF) = vfymO_freeF; TIi(t_vfyObj ,visit) = vfymO_visit; TIi(t_vfyObj ,print) = vfymO_print; - TIi(t_funBl ,freeO) = funBl_freeO; TIi(t_funBl ,freeF) = funBl_freeF; TIi(t_funBl ,visit) = funBl_visit; TIi(t_funBl ,print) = funBl_print; TIi(t_funBl,decompose) = block_decompose; - TIi(t_md1Bl ,freeO) = md1Bl_freeO; TIi(t_md1Bl ,freeF) = md1Bl_freeF; TIi(t_md1Bl ,visit) = md1Bl_visit; TIi(t_md1Bl ,print) = md1Bl_print; TIi(t_md1Bl,decompose) = block_decompose; TIi(t_md1Bl,m1_d)=md1Bl_d; - TIi(t_md2Bl ,freeO) = md2Bl_freeO; TIi(t_md2Bl ,freeF) = md2Bl_freeF; TIi(t_md2Bl ,visit) = md2Bl_visit; TIi(t_md2Bl ,print) = md2Bl_print; TIi(t_md2Bl,decompose) = block_decompose; TIi(t_md2Bl,m2_d)=md2Bl_d; + TIi(t_comp ,freeO) = comp_freeO; TIi(t_comp ,freeF) = comp_freeF; TIi(t_comp ,visit) = comp_visit; TIi(t_comp ,print) = comp_print; + TIi(t_body ,freeO) = body_freeO; TIi(t_body ,freeF) = body_freeF; TIi(t_body ,visit) = body_visit; TIi(t_body ,print) = body_print; + TIi(t_block ,freeO) = block_freeO; TIi(t_block ,freeF) = block_freeF; TIi(t_block ,visit) = block_visit; TIi(t_block ,print) = block_print; + TIi(t_scope ,freeO) = scope_freeO; TIi(t_scope ,freeF) = scope_freeF; TIi(t_scope ,visit) = scope_visit; TIi(t_scope ,print) = scope_print; + TIi(t_scopeExt,freeO) = scExt_freeO; TIi(t_scopeExt,freeF) = scExt_freeF; TIi(t_scopeExt,visit) = scExt_visit; TIi(t_scopeExt,print) = scExt_print; + TIi(t_blBlocks,freeO) = bBlks_freeO; TIi(t_blBlocks,freeF) = bBlks_freeF; TIi(t_blBlocks,visit) = bBlks_visit; TIi(t_blBlocks,print) = bBlks_print; + TIi(t_fldAlias,freeO) = alias_freeO; TIi(t_fldAlias,freeF) = alias_freeF; TIi(t_fldAlias,visit) = alias_visit; TIi(t_fldAlias,print) = alias_print; + TIi(t_vfyObj ,freeO) = wrobj_freeO; TIi(t_vfyObj ,freeF) = wrobj_freeF; TIi(t_vfyObj ,visit) = wrobj_visit; TIi(t_vfyObj ,print) = vfymO_print; + TIi(t_arrMerge,freeO) = wrobj_freeO; TIi(t_arrMerge,freeF) = wrobj_freeF; TIi(t_arrMerge,visit) = wrobj_visit; TIi(t_arrMerge,print) = marrO_print; + TIi(t_funBl ,freeO) = funBl_freeO; TIi(t_funBl ,freeF) = funBl_freeF; TIi(t_funBl ,visit) = funBl_visit; TIi(t_funBl ,print) = funBl_print; TIi(t_funBl,decompose) = block_decompose; + TIi(t_md1Bl ,freeO) = md1Bl_freeO; TIi(t_md1Bl ,freeF) = md1Bl_freeF; TIi(t_md1Bl ,visit) = md1Bl_visit; TIi(t_md1Bl ,print) = md1Bl_print; TIi(t_md1Bl,decompose) = block_decompose; TIi(t_md1Bl,m1_d)=md1Bl_d; + TIi(t_md2Bl ,freeO) = md2Bl_freeO; TIi(t_md2Bl ,freeF) = md2Bl_freeF; TIi(t_md2Bl ,visit) = md2Bl_visit; TIi(t_md2Bl ,print) = md2Bl_print; TIi(t_md2Bl,decompose) = block_decompose; TIi(t_md2Bl,m2_d)=md2Bl_d; TIi(t_funBl,fn_im) = funBl_im; TIi(t_md1Bl,m1_im) = md1Bl_im; TIi(t_md2Bl,m2_im) = md2Bl_im; TIi(t_funBl,fn_iw) = funBl_iw; TIi(t_md1Bl,m1_iw) = md1Bl_iw; TIi(t_md2Bl,m2_iw) = md2Bl_iw; @@ -1105,7 +1160,7 @@ void comp_init() { bL_m[POPS]=1; bL_m[CHKV]=1; bL_m[VFYM]=1; bL_m[NOTM]=1; bL_m[RETN]=1; bL_m[RETD]=1; bL_m[FAIL]=1; bL_m[PRED]=1; - bL_m[PUSH]=2; bL_m[DFND]=2; bL_m[ARRO]=2; bL_m[ARRM]=2; + bL_m[PUSH]=2; bL_m[DFND]=2; bL_m[ARRO]=2; bL_m[ARRM]=2; bL_m[ARMO]=2; bL_m[ARMM]=2; bL_m[DYNO]=2; bL_m[DYNM]=2; bL_m[FLDO]=2; bL_m[FLDM]=2; bL_m[SYSV]=2; bL_m[ALIM]=2; @@ -1150,8 +1205,8 @@ void comp_init() { // stack added map for (i32 i = 0; i < BC_SIZE; i++) sA_m[i] = sD_m[i] + sC_m[i]; - sA_m[ARRO]=1; - sA_m[ARRM]=1; + sA_m[ARRO]=1; sA_m[ARMO]=1; + sA_m[ARRM]=1; sA_m[ARMM]=1; } diff --git a/src/vm.h b/src/vm.h index e060ba0e..16e09d79 100644 --- a/src/vm.h +++ b/src/vm.h @@ -25,6 +25,8 @@ enum { RETD = 0x08, // return a namespace of exported items ARRO = 0x0B, // N; create a vector of top N items ARRM = 0x0C, // N; create a mutable vector of top N items + ARMO = 0x0D, // push `>ToS` + ARMM = 0x0E, // push a mutable version of `>ToS` that unpacks cells of what its assigned to FN1C = 0x10, // monadic function call ⟨…,x,f ⟩ → F x FN2C = 0x11, // dyadic function call ⟨…,x,f,w⟩ → w F x @@ -57,6 +59,7 @@ enum { FLDO = 0x40, // N; get field nameList[N] from ToS FLDM = 0x41, // N; get mutable field nameList[N] from ToS ALIM = 0x42, // N; replace ToS with one with a namespace field alias N + EXTO, EXTM, EXTU, // alternate versions of VAR_ 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 @@ -190,8 +193,8 @@ extern i32 sC_m[BC_SIZE]; extern i32 sA_m[BC_SIZE]; static u32* nextBC (u32* p) { return p + bL_m[*p]; } static i32 stackAdded (u32* p) { return sA_m[*p]; } -static i32 stackDiff (u32* p) { if (*p==ARRO|*p==ARRM) return 1-p[1]; return sD_m[*p]; } -static i32 stackConsumed(u32* p) { if (*p==ARRO|*p==ARRM) return p[1]; return sC_m[*p]; } +static i32 stackDiff (u32* p) { if (*p==ARRO|*p==ARRM|*p==ARMO|*p==ARMM) return 1-p[1]; return sD_m[*p]; } +static i32 stackConsumed(u32* p) { if (*p==ARRO|*p==ARRM|*p==ARMO|*p==ARMM) return p[1]; return sC_m[*p]; } char* bc_repr(u32 p); @@ -281,10 +284,10 @@ typedef struct FldAlias { B obj; i32 p; } FldAlias; -typedef struct VfyObj { +typedef struct WrappedObj { struct Value; B obj; -} VfyObj; +} WrappedObj; NOINLINE B v_getF(Scope* pscs[], B s); // doesn't consume