diff --git a/src/c32arr.c b/src/c32arr.c index af911f59..980d0c3e 100644 --- a/src/c32arr.c +++ b/src/c32arr.c @@ -38,7 +38,7 @@ B m_c32slice(B p, u32* ptr) { } -u32* c32arr_ptr(B x) { VT(x, t_c32arr); return c(C32Arr,x)->a; } +u32* c32arr_ptr(B x) { VTY(x, t_c32arr); return c(C32Arr,x)->a; } u32* c32any_ptr(B x) { assert(isArr(x)); u8 t=v(x)->type; if(t==t_c32arr) return c(C32Arr,x)->a; assert(t==t_c32slice); return c(C32Slice,x)->a; } B m_str8(usz sz, char* s) { @@ -84,8 +84,8 @@ bool eqStr(B w, u32* x) { B c32arr_slice (B x, usz s) {return m_c32slice(x , c(C32Arr ,x)->a+s); } B c32slice_slice(B x, usz s) { B r = m_c32slice(inc(c(Slice,x)->p), c(C32Slice,x)->a+s); dec(x); return r; } -B c32arr_get (B x, usz n) { VT(x,t_c32arr ); return m_c32(c(C32Arr ,x)->a[n]); } -B c32slice_get(B x, usz n) { VT(x,t_c32slice); return m_c32(c(C32Slice,x)->a[n]); } +B c32arr_get (B x, usz n) { VTY(x,t_c32arr ); return m_c32(c(C32Arr ,x)->a[n]); } +B c32slice_get(B x, usz n) { VTY(x,t_c32slice); return m_c32(c(C32Slice,x)->a[n]); } void c32arr_free(Value* x) { decSh(x); } bool c32arr_canStore(B x) { return isC32(x); } diff --git a/src/f64arr.c b/src/f64arr.c index 183dd04c..3cfe9906 100644 --- a/src/f64arr.c +++ b/src/f64arr.c @@ -38,7 +38,7 @@ B m_f64slice(B p, f64* ptr) { } -f64* f64arr_ptr(B x) { VT(x, t_f64arr); return c(F64Arr,x)->a; } +f64* f64arr_ptr(B x) { VTY(x, t_f64arr); return c(F64Arr,x)->a; } f64* f64any_ptr(B x) { assert(isArr(x)); u8 t=v(x)->type; if(t==t_f64arr) return c(F64Arr,x)->a; assert(t==t_f64slice); return c(F64Slice,x)->a; } NOINLINE B m_caf64(usz sz, f64* a) { @@ -61,8 +61,8 @@ F64Arr* toF64Arr(B x) { B f64arr_slice (B x, usz s) {return m_f64slice(x , c(F64Arr ,x)->a+s); } B f64slice_slice(B x, usz s) { B r = m_f64slice(inc(c(Slice,x)->p), c(F64Slice,x)->a+s); dec(x); return r; } -B f64arr_get (B x, usz n) { VT(x,t_f64arr ); return m_f64(c(F64Arr ,x)->a[n]); } -B f64slice_get(B x, usz n) { VT(x,t_f64slice); return m_f64(c(F64Slice,x)->a[n]); } +B f64arr_get (B x, usz n) { VTY(x,t_f64arr ); return m_f64(c(F64Arr ,x)->a[n]); } +B f64slice_get(B x, usz n) { VTY(x,t_f64slice); return m_f64(c(F64Slice,x)->a[n]); } void f64arr_free(Value* x) { decSh(x); } bool f64arr_canStore(B x) { return q_f64(x); } diff --git a/src/fillarr.c b/src/fillarr.c index 05a3552b..86a475b1 100644 --- a/src/fillarr.c +++ b/src/fillarr.c @@ -73,15 +73,15 @@ B m_fillslice(B p, B* ptr) { return tag(r, ARR_TAG); } -B* fillarr_ptr(B x) { VT(x,t_fillarr); return c(FillArr,x)->a; } +B* fillarr_ptr(B x) { VTY(x,t_fillarr); return c(FillArr,x)->a; } B fillarr_slice (B x, usz s) {return m_fillslice(x , c(FillArr ,x)->a+s); } B fillslice_slice(B x, usz s) { B r = m_fillslice(inc(c(Slice,x)->p), c(FillSlice,x)->a+s); dec(x); return r; } -B fillarr_get (B x, usz n) { VT(x,t_fillarr ); return inc(c(FillArr ,x)->a[n]); } -B fillslice_get (B x, usz n) { VT(x,t_fillslice); return inc(c(FillSlice,x)->a[n]); } -B fillarr_getU (B x, usz n) { VT(x,t_fillarr ); return c(FillArr ,x)->a[n] ; } -B fillslice_getU(B x, usz n) { VT(x,t_fillslice); return c(FillSlice,x)->a[n] ; } +B fillarr_get (B x, usz n) { VTY(x,t_fillarr ); return inc(c(FillArr ,x)->a[n]); } +B fillslice_get (B x, usz n) { VTY(x,t_fillslice); return inc(c(FillSlice,x)->a[n]); } +B fillarr_getU (B x, usz n) { VTY(x,t_fillarr ); return c(FillArr ,x)->a[n] ; } +B fillslice_getU(B x, usz n) { VTY(x,t_fillslice); return c(FillSlice,x)->a[n] ; } void fillarr_free(Value* x) { decSh(x); B* p = ((FillArr*)x)->a; diff --git a/src/fns.c b/src/fns.c index 98869dfb..abdd2793 100644 --- a/src/fns.c +++ b/src/fns.c @@ -174,29 +174,64 @@ B indexOf_c1(B t, B x) { if (isAtm(x)) thrM("⊐: 𝕩 cannot have rank 0"); usz xia = a(x)->ia; if (xia==0) { dec(x); return inc(bi_emptyIVec); } - if (rnk(x)==1 && TI(x).elType==el_i32) { - i32* xp = i32any_ptr(x); - i32 min=I32_MAX, max=I32_MIN; + // if (rnk(x)==1 && TI(x).elType==el_i32) { + // i32* xp = i32any_ptr(x); + // i32 min=I32_MAX, max=I32_MIN; + // for (usz i = 0; i < xia; i++) { + // i32 c = xp[i]; + // if (cmax) max = c; + // } + // i32 dst = 1 + max-(i64)min; + // if ((dstmax) max = c; - } - i32 dst = 1 + max-(i64)min; - if ((dstent[p].val; + else rp[i] = map->ent[p].val = ctr++; } + free_b2i(map); + dec(x); + // u64 e = nsTime(); q1+= e-s; + return r; } return c1(rt_indexOf, x); } diff --git a/src/h.h b/src/h.h index 625911fb..d7bed8ba 100644 --- a/src/h.h +++ b/src/h.h @@ -39,6 +39,7 @@ #define NOINLINE __attribute__ ((noinline)) #define NORETURN __attribute__ ((noreturn)) #define AUTO __auto_type +#define LIKELY(X) __builtin_expect(X,1) #define RARE(X) __builtin_expect(X,0) typedef u32 usz; @@ -86,10 +87,10 @@ enum Type { /*19*/ t_hslice, t_i8slice, t_i32slice, t_fillslice, t_c32slice, t_f64slice, /*25*/ t_comp, t_block, t_body, t_scope, - /*29*/ t_ns, t_nsDesc, t_fldAlias, - /*31*/ t_freed, t_harrPartial, + /*29*/ t_ns, t_nsDesc, t_fldAlias, t_hashmap, + /*33*/ t_freed, t_harrPartial, #ifdef RT_PERF - /*33*/ t_funPerf, t_md1Perf, t_md2Perf, + /*35*/ t_funPerf, t_md1Perf, t_md2Perf, #endif t_COUNT }; @@ -289,7 +290,7 @@ u64 envPrevHeight; // envStart+prevEnvHeight will give the original envCurr #define sprnk(X,R) (X->extra=(R)) #define rnk(X ) prnk(v(X)) #define srnk(X,R) sprnk(v(X),R) -#define VT(X,T) assert(isVal(X) && v(X)->type==(T)) +#define VTY(X,T) assert(isVal(X) && v(X)->type==(T)) void print_vmStack(); #ifdef DEBUG diff --git a/src/harr.c b/src/harr.c index eb5dbd36..c71fbdfd 100644 --- a/src/harr.c +++ b/src/harr.c @@ -23,27 +23,27 @@ HArr_p m_harrs(usz ia, usz* ctr) { // writes just ia gsAdd(r); return harr_parts(r); } -B harr_fv(HArr_p p) { VT(p.b, t_harrPartial); +B harr_fv(HArr_p p) { VTY(p.b, t_harrPartial); p.c->type = t_harr; p.c->sh = &p.c->ia; srnk(p.b, 1); gsPop(); return p.b; } -B harr_fc(HArr_p p, B x) { VT(p.b, t_harrPartial); +B harr_fc(HArr_p p, B x) { VTY(p.b, t_harrPartial); p.c->type = t_harr; arr_shCopy(p.b, x); gsPop(); return p.b; } -B harr_fcd(HArr_p p, B x) { VT(p.b, t_harrPartial); +B harr_fcd(HArr_p p, B x) { VTY(p.b, t_harrPartial); p.c->type = t_harr; arr_shCopy(p.b, x); dec(x); gsPop(); return p.b; } -usz* harr_fa(HArr_p p, ur r) { VT(p.b, t_harrPartial); +usz* harr_fa(HArr_p p, ur r) { VTY(p.b, t_harrPartial); p.c->type = t_harr; gsPop(); return arr_shAllocR(p.b, r); @@ -133,7 +133,7 @@ B toKCells(B x, ur k) { } -B* harr_ptr(B x) { VT(x,t_harr); return c(HArr,x)->a; } +B* harr_ptr(B x) { VTY(x,t_harr); return c(HArr,x)->a; } HArr* toHArr(B x) { if (v(x)->type==t_harr) return c(HArr,x); @@ -174,10 +174,10 @@ B harr_slice (B x, usz s) {return m_hslice(x , c(HArr ,x)->a+s B hslice_slice(B x, usz s) { B r = m_hslice(inc(c(Slice,x)->p), c(HSlice,x)->a+s); dec(x); return r; } -B harr_get (B x, usz n) { VT(x,t_harr ); return inc(c(HArr ,x)->a[n]); } -B hslice_get (B x, usz n) { VT(x,t_hslice); return inc(c(HSlice,x)->a[n]); } -B harr_getU (B x, usz n) { VT(x,t_harr ); return c(HArr ,x)->a[n] ; } -B hslice_getU(B x, usz n) { VT(x,t_hslice); return c(HSlice,x)->a[n] ; } +B harr_get (B x, usz n) { VTY(x,t_harr ); return inc(c(HArr ,x)->a[n]); } +B hslice_get (B x, usz n) { VTY(x,t_hslice); return inc(c(HSlice,x)->a[n]); } +B harr_getU (B x, usz n) { VTY(x,t_harr ); return c(HArr ,x)->a[n] ; } +B hslice_getU(B x, usz n) { VTY(x,t_hslice); return c(HSlice,x)->a[n] ; } void harr_free(Value* x) { decSh(x); B* p = ((HArr*)x)->a; // don't use harr_ptr so type isn't checked diff --git a/src/hash.c b/src/hash.c index b04073d1..b211d2b3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -34,18 +34,18 @@ B bqn_squeeze(B x) { } else return x; } -u64 bqn_hash(B x, const u64 secret[4]) { // consumes (because otherwise squeezing is hard as in-place cannot be done because slices) +u64 bqn_hash(B x, const u64 secret[4]) { // doesn't consume if (isAtm(x)) { if (q_f64(x)) return wyhash64(secret[0], x.u); if (isC32(x)) return wyhash64(secret[1], x.u); assert(isVal(x)); - dec(x); return wyhash64(secret[2], x.u); } + inc(x); x = bqn_squeeze(x); + u64 shHash = wyhash(a(x)->sh, rnk(x)*sizeof(usz), 0, secret); u8 xe = TI(x).elType; usz xia = a(x)->ia; - u64 shHash = wyhash(a(x)->sh, rnk(x)*sizeof(usz), 0, secret); u64 r; if (xe==el_i32) { r = wyhash(i32any_ptr(x), xia*4, shHash, secret); @@ -56,10 +56,42 @@ u64 bqn_hash(B x, const u64 secret[4]) { // consumes (because otherwise squeezin } else { assert(xe==el_B); u64 data[xia]; - BS2B xget = TI(x).get; - for (usz i = 0; i < xia; i++) data[i] = bqn_hash(xget(x, i), secret); + BS2B xgetU = TI(x).getU; + for (usz i = 0; i < xia; i++) data[i] = bqn_hash(xgetU(x, i), secret); r = wyhash(data, xia*8, shHash, secret); } dec(x); return r; } + +u64 wy_secret[4]; +u64 bqn_hashP(B x, const u64 secret[4]) { // bqn_hash but never zero + u64 r = bqn_hash(x, secret); + return LIKELY(r)?r:secret[3]; // bias towards secret[3], whatever +} + + + +#define N(X) X##_b2i +#define HT u64 +#define KT B +#define H1(K) bqn_hashP(K, wy_secret) +#define H2(K,h1) h1 +#define H1R(K,h2) h2 +#define EMPTY(S,K) ((S)==0) +#define HDEF 0 +#define KEYS +#define EQUAL(A,B) equal(A,B) +#define VALS +#define VT i32 +#include "hashmap.c" + + + +void hash_init() { + u64 bad1=0xa0761d6478bd642full; // values wyhash64 is afraid of + u64 bad2=0xe7037ed1a0b428dbull; + again: + make_secret(nsTime(), wy_secret); + for (u64 i = 0; i < 4; i++) if(wy_secret[i]==bad1 || wy_secret[i]==bad2) goto again; +} diff --git a/src/hashmap.c b/src/hashmap.c new file mode 100644 index 00000000..ed554bdf --- /dev/null +++ b/src/hashmap.c @@ -0,0 +1,147 @@ +// args: +// N(X) - X##_mapName +// HT - stored hash type (u32 or u64) +// KT - key type +// H1(K) - function to compute index in hashmap, returns u64; the expensive part +// H2(K,h1) - function to compute HT (returning just h1 (or K if applicable) is safe) +// H1R(K,h2) - calculate H1 from H2, preferrably fast +// EMPTY(S,K) - test whether value counts as unpopulated (ignore K if !KEYS) +// HDEF - if defined, the value to initialize HT to (otherwise it's undefined) +// KEYS - whether to separately store and check keys (otherwise only HT is compared) +// EQUAL(A,B) - compare two keys +// KDEF - if defined, the value to initialize keys to (otherwise it's undefined) +// VALS - whether to store values corresponding to keys (otherwise this is a hashset) +// VT - value type + +#define Map N(H) +#define Ent N(Ent) +#ifdef KEYS + #define IFKEY(...) __VA_ARGS__ +#else + #define IFKEY(...) +#endif +#ifdef VALS + #define IFVAL(...) __VA_ARGS__ +#else + #define IFVAL(...) +#endif + +typedef struct Ent { +#ifdef KEYS + KT key; +#endif + HT hash; +#ifdef VALS + VT val; +#endif +} Ent; + +typedef struct Map { + struct Value; + u64 pop; // count of defined entries + u64 mask; // sz-1 + u64 sz; // count of allocated entries, a power of 2 + Ent ent[]; +} Map; + +Map* N(m) (u64 sz) { + assert(sz && (sz & sz-1)==0); + Map* r = mm_allocN(fsizeof(Map,ent,Ent,sz), t_hashmap); + #ifdef HDEF + for (u64 i = 0; i < sz; i++) r->ent[i].hash = HDEF; + #endif + #ifdef KDEF + for (u64 i = 0; i < sz; i++) r->ent[i].key = KDEF; + #endif + r->sz = sz; + r->mask = sz-1; + r->pop = 0; + return r; +} +void N(free) (Map* m) { + mm_free((Value*) m); +} + + +static inline u64 N(find) (Map* m, KT k, u64 h1, u64 h2, bool* had) { + assert(m->sz > m->pop); + *had = true; + u64 mask = m->mask; + u64 p = h1 & mask; + while (true) { + Ent e = m->ent[p]; + if (e.hash==h2 IFKEY(&& LIKELY(EQUAL(e.key, k)))) return p; + if (EMPTY(e.hash, e.key)) { *had=false; return p; } + if (RARE(p++==mask)) p = 0; + } +} + + +static inline void N(qins) (Map* m, u64 h1, HT h2, KT k IFVAL(, VT v)) { // if guaranteed that k doesn't exist in the map yet and there's space for this + u64 mask = m->mask; + u64 p = h1 & mask; + while (true) { + u64 ch2 = m->ent[p].hash; + if (EMPTY(ch2, m->ent[p].key)) { + m->ent[p].hash = h2; + IFKEY(m->ent[p].key = k); + IFVAL(m->ent[p].val = v); + m->pop++; + return; + } + if (p++==mask) p = 0; + } +} +void N(dbl) (Map** m) { + Map* pm = *m; + u64 psz = pm->sz; + Map* nm = N(m)(psz*2); + for (u64 i = 0; i < psz; i++) { + Ent e = pm->ent[i]; + if(!EMPTY(e.hash, e.key)) N(qins)(nm, H1R(e.key, e.hash), e.hash, e.key IFVAL(, e.val)); + } + mm_free((Value*)pm); + *m = nm; +} + + +static inline u64 N(mk) (Map** mp, KT k, bool* had) { + Map* m = *mp; + if (m->pop*2 > m->sz) { N(dbl)(mp); m=*mp; } + u64 h1 = H1(k); u64 h2 = H2(k, h1); + u64 p = N(find)(m, k, h1, h2, had); + if (*had) return p; + m->ent[p].hash = h2; + IFKEY(m->ent[p].key = k); + m->pop++; + return p; +} +#ifdef VALS + static inline bool N(ins) (Map** mp, KT k, VT v) { // returns whether element was replaced + bool had; u64 p = N(mk)(mp, k, &had); + (*mp)->ent[p].val = v; + return had; + } +#endif + + +#undef IFKEY +#undef IFVAL +#undef Ent +#undef Map +#undef N +#undef HT +#undef KT +#undef H1 +#undef H2 +#undef EMPTY +#undef HDEF +#ifdef KEYS + #undef KEYS + #undef EQUAL + #undef KDEF +#endif +#ifdef VALS + #undef VALS + #undef VT +#endif \ No newline at end of file diff --git a/src/i32arr.c b/src/i32arr.c index d066cfea..80eefe1d 100644 --- a/src/i32arr.c +++ b/src/i32arr.c @@ -38,7 +38,7 @@ B m_i32slice(B p, i32* ptr) { } -i32* i32arr_ptr(B x) { VT(x, t_i32arr); return c(I32Arr,x)->a; } +i32* i32arr_ptr(B x) { VTY(x, t_i32arr); return c(I32Arr,x)->a; } i32* i32any_ptr(B x) { assert(isArr(x)); u8 t=v(x)->type; if(t==t_i32arr) return c(I32Arr,x)->a; assert(t==t_i32slice); return c(I32Slice,x)->a; } NOINLINE B m_cai32(usz ia, i32* a) { @@ -67,8 +67,8 @@ I32Arr* toI32Arr(B x) { // assumes it's possible B i32arr_slice (B x, usz s) {return m_i32slice(x , c(I32Arr ,x)->a+s); } B i32slice_slice(B x, usz s) { B r = m_i32slice(inc(c(Slice,x)->p), c(I32Slice,x)->a+s); dec(x); return r; } -B i32arr_get (B x, usz n) { VT(x,t_i32arr ); return m_i32(c(I32Arr ,x)->a[n]); } -B i32slice_get(B x, usz n) { VT(x,t_i32slice); return m_i32(c(I32Slice,x)->a[n]); } +B i32arr_get (B x, usz n) { VTY(x,t_i32arr ); return m_i32(c(I32Arr ,x)->a[n]); } +B i32slice_get(B x, usz n) { VTY(x,t_i32slice); return m_i32(c(I32Slice,x)->a[n]); } void i32arr_free(Value* x) { decSh(x); } bool i32arr_canStore(B x) { return q_i32(x); } diff --git a/src/main.c b/src/main.c index 84635822..59dbe455 100644 --- a/src/main.c +++ b/src/main.c @@ -76,6 +76,7 @@ int main(int argc, char* argv[]) { gc_add(srcB); for (i32 i = 0; i < 100; i++) { dec(bqn_exec(inc(srcB), bi_N, bi_N)); gc_maybeGC(); } rtPerf_print(); + CTR_FOR(CTR_PRINT) exit(0); #endif bqn_setComp(bqn_exec(srcB, bi_N, bi_N)); diff --git a/src/stuff.c b/src/stuff.c index ebfcd175..4820baa8 100644 --- a/src/stuff.c +++ b/src/stuff.c @@ -518,7 +518,7 @@ void printAllocStats() { _Thread_local B comp_currPath; _Thread_local B comp_currArgs; -#define FOR_INIT(F) F(hdr) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) F(fns) F(sfns) F(arith) F(grade) F(md1) F(md2) F(sysfn) F(derv) F(comp) F(rtPerf) F(ns) F(load) +#define FOR_INIT(F) F(hdr) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) F(hash) F(fns) F(sfns) F(arith) F(grade) F(md1) F(md2) F(sysfn) F(derv) F(comp) F(rtPerf) F(ns) F(load) #define F(X) static inline void X##_init(); FOR_INIT(F) #undef F diff --git a/src/sysfn.c b/src/sysfn.c index 82e6df52..a5f4650d 100644 --- a/src/sysfn.c +++ b/src/sysfn.c @@ -164,13 +164,15 @@ B cmp_c2(B t, B w, B x) { B hash_c2(B t, B w, B x) { u64 secret[4]; make_secret(o2i64(w), secret); u64 rv = bqn_hash(x, secret); + dec(x); i32* rp; B r = m_i32arrv(&rp, 4); rp[0] = (u16)(rv>>48); rp[1] = (u16)(rv>>32); rp[2] = (u16)(rv>>16); rp[3] = (u16)(rv ); return r; } B hash_c1(B t, B x) { - u64 rv = bqn_hash(x, _wyp); + u64 rv = bqn_hash(x, wy_secret); + dec(x); i32* rp; B r = m_i32arrv(&rp, 4); rp[0] = (u16)(rv>>48); rp[1] = (u16)(rv>>32); rp[2] = (u16)(rv>>16); rp[3] = (u16)(rv ); diff --git a/src/vm.c b/src/vm.c index fd4851b1..e6b1c65b 100644 --- a/src/vm.c +++ b/src/vm.c @@ -211,7 +211,7 @@ void v_set(Scope* pscs[], B s, B x, bool upd) { // doesn't consume } sc->vars[(u32)s.u] = inc(x); } else { - VT(s, t_harr); + VTY(s, t_harr); B* sp = harr_ptr(s); usz ia = a(s)->ia; if (isAtm(x) || !eqShape(s, x)) { @@ -244,7 +244,7 @@ B v_get(Scope* pscs[], B s) { // get value representing s, replacing with bi_opt sc->vars[(u32)s.u] = bi_optOut; return r; } else { - VT(s, t_harr); + VTY(s, t_harr); usz ia = a(s)->ia; B* sp = harr_ptr(s); HArr_p r = m_harrUv(ia);