From 9abe7506ab8ea64cbcf33a56a0e7f2a78ad3d39a Mon Sep 17 00:00:00 2001 From: dzaima Date: Thu, 26 Jan 2023 00:45:39 +0200 Subject: [PATCH] native minimal compiler --- build/src/build.bqn | 2 +- src/builtins/internal.c | 20 +- src/load.c | 100 ++++++---- src/main.c | 9 + src/ns.c | 9 +- src/opt/comp.c | 392 ++++++++++++++++++++++++++++++++++++++++ src/vm.c | 6 +- 7 files changed, 498 insertions(+), 40 deletions(-) create mode 100644 src/opt/comp.c diff --git a/build/src/build.bqn b/build/src/build.bqn index 0f7474a0..bbea6ef6 100755 --- a/build/src/build.bqn +++ b/build/src/build.bqn @@ -492,7 +492,7 @@ AddRule ← { π•Š cacheβ€ΏcacheKeyβ€Ώdstβ€ΏGetCMDβ€Ώdispβ€Ώdeps: cacheKey ⇐ cacheKey found0 ⇐ 0 SetFound ↩ {found0↩𝕩} - DepHash ⇐ {π•Š: Hash {𝕩.found1≑@? 𝕩.found0; 𝕩.found1}Β¨ ruleDeps} + DepHash ⇐ {π•Š: Hash {𝕩.found1≑@? 𝕩.found0; 𝕩.found1}Β¨ ruleDeps} # todo instead of conditionally choosing found1 or found2, decide statically; and properly cache found1 ⇐ @ SetVal ⇐ {found1 ↩ π•©β‹ˆDepHash@} disp ⇐ disp diff --git a/src/builtins/internal.c b/src/builtins/internal.c index ab2e4121..0d521348 100644 --- a/src/builtins/internal.c +++ b/src/builtins/internal.c @@ -279,7 +279,18 @@ B eequal_c2(B t, B w, B x) { #ifdef TEST_BITCPY #include "../utils/mut.h" #endif +#if NATIVE_COMPILER + extern B native_comp; + void switchComp(void); +#endif B internalTemp_c1(B t, B x) { + + #if NATIVE_COMPILER + switchComp(); + B r = bqn_exec(x, bi_N, bi_N); + switchComp(); + return r; + #endif #ifdef TEST_BITCPY SGetU(x) bit_cpy(bitarr_ptr(GetU(x,0)), o2s(GetU(x,1)), bitarr_ptr(GetU(x,2)), o2s(GetU(x,3)), o2s(GetU(x,4))); @@ -291,10 +302,13 @@ B internalTemp_c1(B t, B x) { #include "../utils/calls.h" #endif B internalTemp_c2(B t, B w, B x) { + #if NATIVE_COMPILER + return c2(native_comp, w, x); + #endif #ifdef TEST_MUT - SGetU(x) - FILL_TO(tyarr_ptr(w), o2s(GetU(x,0)), o2s(GetU(x,1)), GetU(x,2), o2s(GetU(x,3))); - dec(w); + SGetU(x) + FILL_TO(tyarr_ptr(w), o2s(GetU(x,0)), o2s(GetU(x,1)), GetU(x,2), o2s(GetU(x,3))); + dec(w); #endif return x; } diff --git a/src/load.c b/src/load.c index ecbb382e..50ee4521 100644 --- a/src/load.c +++ b/src/load.c @@ -118,7 +118,10 @@ Block* load_compObj(B x, B src, B path, Scope* sc) { // consumes x,src return r; } +#if !(ONLY_NATIVE_COMP && !FORMATTER && NO_RT && NO_EXPLAIN) #include PRECOMPILED_FILE(src) +#endif + #if RT_SRC Block* load_compImport(char* name, B bc, B objs, B blocks, B bodies, B inds, B src) { // consumes all return compile(bc, objs, blocks, bodies, inds, bi_N, src, m_c8vec_0(name), NULL); @@ -136,6 +139,15 @@ B load_compArg; B load_glyphs; B load_explain; + +#if NATIVE_COMPILER +#include "opt/comp.c" +B load_rtComp; +void switchComp() { + load_comp = load_comp.u==load_rtComp.u? native_comp : load_rtComp; +} +#endif + #if FORMATTER B load_fmt, load_repr; B bqn_fmt(B x) { // consumes @@ -414,15 +426,15 @@ void load_init() { // very last init function HArr_p runtimeH = m_harrUc(rtObjRaw); SGet(rtObjRaw) - rt_undo = Get(rtObjRaw, n_undo ); gc_add(rt_undo); - rt_select = Get(rtObjRaw, n_select ); gc_add(rt_select); - rt_slash = Get(rtObjRaw, n_slash ); gc_add(rt_slash); - rt_group = Get(rtObjRaw, n_group ); gc_add(rt_group); - rt_under = Get(rtObjRaw, n_under ); gc_add(rt_under); - rt_find = Get(rtObjRaw, n_find ); gc_add(rt_find); - rt_transp = Get(rtObjRaw, n_transp ); gc_add(rt_transp); - rt_depth = Get(rtObjRaw, n_depth ); gc_add(rt_depth); - rt_insert = Get(rtObjRaw, n_insert ); gc_add(rt_insert); + rt_undo = Get(rtObjRaw, n_undo ); + rt_select = Get(rtObjRaw, n_select ); + rt_slash = Get(rtObjRaw, n_slash ); + rt_group = Get(rtObjRaw, n_group ); + rt_under = Get(rtObjRaw, n_under ); + rt_find = Get(rtObjRaw, n_find ); + rt_transp = Get(rtObjRaw, n_transp ); + rt_depth = Get(rtObjRaw, n_depth ); + rt_insert = Get(rtObjRaw, n_insert ); for (usz i = 0; i < rtLen; i++) { #ifdef RT_WRAP @@ -461,14 +473,22 @@ void load_init() { // very last init function if (isVal(r)) v(r)->flags|= i+1; } load_rtObj = frtObj; - load_compArg = m_hVec2(load_rtObj, incG(bi_sys)); gc_add(frtObj); - rt_select=rt_slash=rt_group=rt_find=rt_transp=rt_invFnReg=rt_invFnSwap = bi_invalidFn; - rt_undo=rt_insert = bi_invalidMd1; - rt_under=rt_depth = bi_invalidMd2; + load_compArg = m_hVec2(load_rtObj, incG(bi_sys)); + rt_select=rt_slash=rt_group=rt_find=rt_transp=rt_invFnReg=rt_invFnSwap = incByG(bi_invalidFn, 7); + rt_undo=rt_insert = incByG(bi_invalidMd1, 2); + rt_under=rt_depth = incByG(bi_invalidMd2, 2); rt_invFnRegFn=rt_invFnSwapFn = invalidFn_c1; #endif gc_add(load_compArg); - + gc_add(rt_undo); + gc_add(rt_select); + gc_add(rt_slash); + gc_add(rt_group); + gc_add(rt_under); + gc_add(rt_find); + gc_add(rt_transp); + gc_add(rt_depth); + gc_add(rt_insert); @@ -489,29 +509,35 @@ void load_init() { // very last init function print_allocStats(); exit(0); #else // use compiler - B prevAsrt = runtime[n_asrt]; - runtime[n_asrt] = bi_casrt; // horrible but GC is off so it's fiiiiiine - Block* comp_b = load_compImport("(compiler)", - #include PRECOMPILED_FILE(compiles) - ); - runtime[n_asrt] = prevAsrt; - load_glyphs = m_hVec3(m_c32vec_0(U"+-Γ—Γ·β‹†βˆšβŒŠβŒˆ|¬∧∨<>β‰ =≀β‰₯β‰‘β‰’βŠ£βŠ’β₯ŠβˆΎβ‰β‹ˆβ†‘β†“β†•Β«Β»βŒ½β‰/β‹β’βŠβŠ‘βŠβŠ’βˆŠβ·βŠ”!"), m_c32vec_0(U"Λ™ΛœΛ˜Β¨βŒœβΌΒ΄Λ`"), m_c32vec_0(U"βˆ˜β—‹βŠΈβŸœβŒΎβŠ˜β—ΆβŽ‰βš‡βŸβŽŠ")); - load_compgen = evalFunBlock(comp_b, 0); ptr_dec(comp_b); - load_comp = c1(load_compgen, inc(load_glyphs)); - gc_add(load_compgen); gc_add(load_comp); gc_add(load_glyphs); + load_glyphs = m_hVec3(m_c32vec_0(U"+-Γ—Γ·β‹†βˆšβŒŠβŒˆ|¬∧∨<>β‰ =≀β‰₯β‰‘β‰’βŠ£βŠ’β₯ŠβˆΎβ‰β‹ˆβ†‘β†“β†•Β«Β»βŒ½β‰/β‹β’βŠβŠ‘βŠβŠ’βˆŠβ·βŠ”!"), m_c32vec_0(U"Λ™ΛœΛ˜Β¨βŒœβΌΒ΄Λ`"), m_c32vec_0(U"βˆ˜β—‹βŠΈβŸœβŒΎβŠ˜β—ΆβŽ‰βš‡βŸβŽŠ")); gc_add(load_glyphs); + + #if !ONLY_NATIVE_COMP + B prevAsrt = runtime[n_asrt]; + runtime[n_asrt] = bi_casrt; // horrible but GC is off so it's fiiiiiine + Block* comp_b = load_compImport("(compiler)", + #include PRECOMPILED_FILE(compiles) + ); + runtime[n_asrt] = prevAsrt; + load_compgen = evalFunBlock(comp_b, 0); ptr_dec(comp_b); + load_comp = c1(load_compgen, inc(load_glyphs)); + #if NATIVE_COMPILER + load_rtComp = load_comp; + #endif + gc_add(load_compgen); gc_add(load_comp); + #endif #if FORMATTER - Block* fmt_b = load_compImport("(formatter)", - #include PRECOMPILED_FILE(formatter) - ); - B fmtM = evalFunBlock(fmt_b, 0); ptr_dec(fmt_b); - B fmtR = c1(fmtM, m_caB(4, (B[]){incG(bi_type), incG(bi_decp), incG(bi_glyph), incG(bi_repr)})); - decG(fmtM); - SGet(fmtR) - load_fmt = Get(fmtR, 0); gc_add(load_fmt); - load_repr = Get(fmtR, 1); gc_add(load_repr); - decG(fmtR); + Block* fmt_b = load_compImport("(formatter)", + #include PRECOMPILED_FILE(formatter) + ); + B fmtM = evalFunBlock(fmt_b, 0); ptr_dec(fmt_b); + B fmtR = c1(fmtM, m_caB(4, (B[]){incG(bi_type), incG(bi_decp), incG(bi_glyph), incG(bi_repr)})); + decG(fmtM); + SGet(fmtR) + load_fmt = Get(fmtR, 0); gc_add(load_fmt); + load_repr = Get(fmtR, 1); gc_add(load_repr); + decG(fmtR); #endif gc_enable(); @@ -754,6 +780,12 @@ void typesFinished_init() { for (u64 i = 0; i < t_COUNT; i++) { if (TIi(i,freeT) == def_fallbackTriv) TIi(i,freeT) = TIi(i,freeF); } + #if NATIVE_COMPILER + nativeCompiler_init(); + #if ONLY_NATIVE_COMP + load_comp = native_comp; + #endif + #endif } bool cbqn_initialized; diff --git a/src/main.c b/src/main.c index aadf3dfc..1d9ac80d 100644 --- a/src/main.c +++ b/src/main.c @@ -489,6 +489,10 @@ void profiler_free(void); void profiler_displayResults(void); void clearImportCache(void); +#if NATIVE_COMPILER && !ONLY_NATIVE_COMP +void switchComp(void); +#endif + static B escape_parser; static B simple_unescape(B x) { if (RARE(escape_parser.u==0)) { @@ -654,6 +658,11 @@ void cbqn_runLine0(char* ln, i64 read) { } else if (isCmd(cmdS, &cmdE, "internalPrint ")) { code = utf8Decode0(cmdE); output = 2; +#if NATIVE_COMPILER && !ONLY_NATIVE_COMP + } else if (isCmd(cmdS, &cmdE, "switchCompiler")) { + switchComp(); + return; +#endif } else if (isCmd(cmdS, &cmdE, "e ") || isCmd(cmdS, &cmdE, "explain ")) { B expl = bqn_explain(utf8Decode0(cmdE), replPath); HArr* expla = toHArr(expl); diff --git a/src/ns.c b/src/ns.c index 6194af3a..accfe781 100644 --- a/src/ns.c +++ b/src/ns.c @@ -140,7 +140,14 @@ Body* m_nnsDescF(i32 n, char** names) { B m_nnsF(Body* desc, i32 n, B* vals) { assert(n == desc->varAm); - Scope* sc = m_scope(desc, NULL, n, n, vals); + i32 varAm = n; + #if ONLY_NATIVE_COMP + varAm+= 100; + #endif + Scope* sc = m_scope(desc, NULL, varAm, n, vals); + #if ONLY_NATIVE_COMP + for (usz i = 0; i < 100; i++) sc->vars[i+n] = bi_N; + #endif return m_ns(sc, ptr_inc(desc->nsDesc)); } diff --git a/src/opt/comp.c b/src/opt/comp.c new file mode 100644 index 00000000..a9ff7f06 --- /dev/null +++ b/src/opt/comp.c @@ -0,0 +1,392 @@ +#include "../nfns.h" +#include "../vm.h" +#include "../utils/mut.h" + +B native_comp; + + + +NOINLINE B nc_emptyI32Vec() { + i32* rp; + return m_i32arrv(&rp, 0); +} +B nc_ivec1(i32 a ) { i32* rp; B r = m_i32arrv(&rp, 1); rp[0]=a; return r; } +B nc_ivec2(i32 a, i32 b ) { i32* rp; B r = m_i32arrv(&rp, 2); rp[0]=a; rp[1]=b; return r; } +B nc_ivec3(i32 a, i32 b, i32 c) { i32* rp; B r = m_i32arrv(&rp, 3); rp[0]=a; rp[1]=b; rp[2]=c; return r; } +NOINLINE void nc_iadd(B* w, i32 x) { // consumes x + *w = vec_add(*w, m_f64(x)); +} +NOINLINE void nc_ijoin(B* w, B x) { // doesn't consume x + SGetU(x) + usz ia = IA(x); + for (usz i = 0; i < ia; i++) nc_iadd(w, o2i(GetU(x, i))); +} + + + +#define nc_equal equal +NOINLINE void nc_add(B* w, B x) { // consumes x + *w = vec_add(*w, x); +} +NOINLINE B nc_pop(B* wp) { + B w = *wp; + assert(isArr(w) && v(w)->refc==1 && IA(w)>0); + B r = IGetU(w, a(w)->ia-1); + a(w)->ia--; + return r; +} + + + +NOINLINE B nc_literal(B val) { + HArr_p r = m_harr0p(1); + r.a[0] = val; + arr_shAtm((Arr*)r.c); + return r.b; +} +static bool nc_up(u32 c) { return (c>='A' & c<='Z'); } +static bool nc_al(u32 c) { return (c>='a' & c<='z') | nc_up(c); } +static bool nc_num(u32 c) { return (c>='0' & c<='9'); } +B sys_c1(B, B); +NOINLINE B nc_tokenize(B prims, B sysvs, u32* chars, usz len, bool* hasBlock) { + B r = emptyHVec(); + usz i = 0; + usz pi = USZ_MAX; + while (i < len) { + u32 c = chars[i++]; + if (i==pi) thrF("Native compiler: Tokenizer stuck on \\u%xi / %i", c, c); + B val; + if (c==U'∞') val = nc_literal(m_f64(1.0/0)); + else if (c==U'Ο€') val = nc_literal(m_f64(3.141592653589793)); + else if (c=='@') val = nc_literal(m_c32(0)); + else if (c==' ') continue; + else if (c=='{' | c=='}') continue; // ignoring braces for now + else if (nc_num(c) | (c==U'Β―')) { + bool neg = c==U'Β―'; + if (!neg) i--; + f64 num = 0; + while (nc_num(chars[i])) num = num*10 + (chars[i++]-'0'); + if (neg) num = -num; + val = nc_literal(m_f64(num)); + } else if (c=='"') { + usz i0 = i; + while ('"'!=chars[i]) { i++; if (i>=len) thrM("Native compiler: Unclosed string literal"); } + usz ia = i-i0; + u32* vp; val = nc_literal(m_c32arrv(&vp, ia)); + memcpy(vp, chars+i0, ia*sizeof(u32)); + i++; + } else if (c=='#') { // comments + while (iβ‰ =≀β‰₯β‰‘β‰’βŠ£βŠ’β₯ŠβˆΎβ‰β‹ˆβ†‘β†“β†•Β«Β»βŒ½β‰/β‹β’βŠβŠ‘βŠβŠ’βˆŠβ·βŠ”!Λ™ΛœΛ˜Β¨βŒœβΌΒ΄Λ`βˆ˜β—‹βŠΈβŸœβŒΎβŠ˜β—ΆβŽ‰βš‡βŸβŽŠ"; + usz j = 0; + while(primRepr[j]) { + if (primRepr[j]==c) { val = nc_literal(IGet(prims, j)); goto add; } + j++; + } + // syntax + u32* basicChars = U"()βŸ¨βŸ©β†β†©"; + while (*basicChars) { + if (c==*basicChars) { val = m_c32(c); goto add; } + basicChars++; + } + thrF("Native compiler: Can't tokenize \\u%xi / %i", c, c); + } + add: + nc_add(&r, val); + } + return r; +} + +usz addObj(B* objs, B val) { // consumes val + nc_add(objs, val); + return IA(*objs)-1; +} + +i32 nc_ty(B x) { + assert(o2iG(IGetU(x, 0))<10); + return o2iG(IGetU(x, 0)); } + +B nc_generate(B p1) { // consumes + // printf("p1: "); printI(p1); putchar('\n'); + + usz p1ia = IA(p1); + B listFinal; + if (p1ia == 1) { // simple case of 1 element + listFinal = p1; + toFinal:; + B elFinal = IGet(listFinal, 0); + if(nc_ty(elFinal)>3) thrM("Native compiler: Unexpected assignment"); + decG(listFinal); + return elFinal; + } + + // merge 1-modifiers + SGetU(p1) + B p2 = emptyHVec(); + { + usz i = 0; + while (i < p1ia) { + B e = incG(GetU(p1, i)); + u8 e0t = nc_ty(e); + usz j = i+1; + if (e0t==4 || e0t==5) goto add; + if (!(e0t==0 || e0t==3)) thrM("Native compiler: Unexpected type in expression"); + while (j0) { + B en1 = GetU(p2, i-1); + u8 en1t = nc_ty(en1); + // printf("e @ %d: ", i); printI(e); putchar('\n'); + + if (en1t==4 || en1t==5) { // assignment + B bc = nc_emptyI32Vec(); + nc_ijoin(&bc, IGetU(e, 1)); + nc_ijoin(&bc, IGetU(en1, 1)); + nc_iadd(&bc, en1t==4? SETN : SETU); + decG(e); + e = m_hVec2(m_f64(explicit? 3 : 0), bc); + i-= 1; + continue; + } + if (en1t!=0) thrM("Native compiler: Expected but didn't get function"); + + if (i>=2) { // dyadic call, fork + B en2 = GetU(p2, i-2); + if (nc_ty(en2)==3 || (!explicit && nc_ty(en2)==0)) { + B bc = nc_emptyI32Vec(); + nc_ijoin(&bc, IGetU(e, 1)); + nc_ijoin(&bc, IGetU(en1, 1)); + nc_ijoin(&bc, IGetU(en2, 1)); + nc_iadd(&bc, explicit? FN2O : TR3O); + decG(e); + e = m_hVec2(m_f64(explicit? 3 : 0), bc); + i-= 2; + continue; + } + } + + // monadic call, atop + B bc = nc_emptyI32Vec(); + nc_ijoin(&bc, IGetU(e, 1)); + nc_ijoin(&bc, IGetU(en1, 1)); + nc_iadd(&bc, explicit? FN1O : TR2D); + decG(e); + e = m_hVec2(m_f64(explicit? 3 : 0), bc); + i-= 1; + } + // printf("e: "); printI(e); putchar('\n'); + decG(p2); + return e; +} + +u32 nc_var(B* vars, B name) { // doesn't consume + B o = *vars; + usz ia = IA(o); + SGetU(o) + for (usz i = 0; i < ia; i++) if (nc_equal(GetU(o, i), name)) return i; + nc_add(vars, incG(name)); + return ia; +} + +B nc_parseStatements(B tokens, usz i0, usz* i1, u32 close, B* objs, B* vars) { + SGetU(tokens) + usz tia = IA(tokens); + usz i = i0; + + B statements = emptyHVec(); + B parts = emptyHVec(); // list of lists; first element indicates class: 0:fn; 1:md1; 2:md2; 3:arr; 4:v←; 5:v↩ + + while (true) { + B ct; + if (i==tia) ct = m_c32(0); + else ct = GetU(tokens, i++); + // printf("next token: "); printI(ct); putchar('\n'); + + if (isC32(ct)) { + u32 ctc = o2cG(ct); + if (ctc=='\0' || ctc==close || ctc==',') { + if (IA(parts)>0) { + nc_add(&statements, nc_generate(parts)); + parts = emptyHVec(); + } + if (ctc==close) { + decG(parts); + break; + } + + if (ctc=='\0') thrM("Native compiler: Unclosed"); + if (close==U')') thrM("Native compiler: Multiple statements in parens"); + } else if (ctc=='(' || ctc==U'⟨') { + usz iM; + B res = nc_parseStatements(tokens, i, &iM, ctc=='('? ')' : U'⟩', objs, vars); + i = iM; + nc_add(&parts, res); + } else thrF("Native compiler: Unexpected character token: %B", ct); + } else if (isArr(ct)) { + if (RNK(ct)==0) { // literal + B val = IGetU(ct, 0); + usz i = addObj(objs, inc(val)); + i32 type = isFun(val)? 0 : isMd1(val)? 1 : isMd2(val)? 2 : 3; + nc_add(&parts, m_hVec2(m_f64(type), nc_ivec2(PUSH, i))); + } else { // name + u8 ty = nc_ty(ct); + assert(ty<=3); + if (ibody; if (b==NULL) return bi_N; @@ -259,6 +262,7 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl while (*c!=RETN & *c!=RETD) { if (*c==PRED) { remapArgs = true; break; } c = nextBC(c); + if (c-bc-1 >= bcIA) thrM("VM compiler: No RETN/RETD found before end of bytecode"); } if (remapArgs) { if (sc && depth==0) thrM("Predicates cannot be used directly in a REPL"); @@ -267,6 +271,7 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl while (*c!=RETN & *c!=RETD) { if (*c==VARO | *c==VARM | *c==VARU) if (c[1]==0 && c[2]= bcIA) thrM("VM compiler: No RETN/RETD found before end of bytecode"); } for (i32 i = 0; i < 6; i++) if (argUsed[i]) { TSADDA(newBC, ((u32[]){ VARO,0,i, VARM,0,vam+i, SETN, POPS }), 8); @@ -277,7 +282,6 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl c = bc+idx; while (true) { u32* n = nextBC(c); - if (n-bc-1 >= bcIA) thrM("VM compiler: No RETN/RETD found before end of bytecode"); bool ret = false; #define A64(X) { u64 a64=(X); TSADD(newBC, (u32)a64); TSADD(newBC, a64>>32); } switch (*c) {