From 21ba88751a59732b1da893562dee5efaaeae480d Mon Sep 17 00:00:00 2001 From: dzaima Date: Sun, 5 Sep 2021 16:06:13 +0300 Subject: [PATCH] working i8/i16-arrs --- src/README.md | 4 +- src/builtins/fns.c | 18 ++- src/core.h | 12 ++ src/core/fillarr.h | 4 +- src/core/stuff.c | 10 +- src/core/tyarr.c | 25 +++- src/core/tyarrTemplate.c | 2 +- src/h.h | 25 ++-- src/load.c | 3 +- src/opt/single.c | 2 +- src/utils/builtins.h | 2 +- src/utils/mut.c | 14 +++ src/utils/mut.h | 265 +++++++++++++-------------------------- 13 files changed, 183 insertions(+), 203 deletions(-) diff --git a/src/README.md b/src/README.md index e76c37c0..0ce13a81 100644 --- a/src/README.md +++ b/src/README.md @@ -80,9 +80,7 @@ Extra functions for converting types: o2cu(x) // B → c32, assumes is valid o2fu(x) // B → f64, assumes is valid o2b(x) // B → bool, throw if impossible - q_i32(x) // query if x is convertible to i32 - q_i64(x) // query if x is convertible to i64 - q_f64(x) // query if x is convertible to f64 (equivalent to isF64) + q_TYPE(x) // query if x is convertible to TYPE (see definitions in h.h) q_N(x) // query if x is · (≡ bi_N) noFill(x) // if x represents undefined fill (returned by getFill*; ≡ bi_noFill) tag(x,*_TAG) // pointer → B diff --git a/src/builtins/fns.c b/src/builtins/fns.c index 441624fa..53cef349 100644 --- a/src/builtins/fns.c +++ b/src/builtins/fns.c @@ -29,13 +29,23 @@ void ud_rec(B** p, usz d, usz r, i32* pos, usz* sh) { B ud_c1(B t, B x) { if (isAtm(x)) { usz xu = o2s(x); - if (RARE(xu>=I32_MAX)) { - f64* rp; B r = m_f64arrv(&rp, xu); + if (LIKELY(xu<=I8_MAX)) { + if (RARE(xu==0)) return emptyIVec(); + i8* rp; B r = m_i8arrv(&rp, xu); for (usz i = 0; i < xu; i++) rp[i] = i; return r; } - if (xu==0) return emptyIVec(); - i32* rp; B r = m_i32arrv(&rp, xu); + if (xu<=I16_MAX) { + i16* rp; B r = m_i16arrv(&rp, xu); + for (usz i = 0; i < xu; i++) rp[i] = i; + return r; + } + if (xu<=I32_MAX) { + i32* rp; B r = m_i32arrv(&rp, xu); + for (usz i = 0; i < xu; i++) rp[i] = i; + return r; + } + f64* rp; B r = m_f64arrv(&rp, xu); for (usz i = 0; i < xu; i++) rp[i] = i; return r; } diff --git a/src/core.h b/src/core.h index de1967c4..9fa683bc 100644 --- a/src/core.h +++ b/src/core.h @@ -26,9 +26,21 @@ #define TYARR_SZ(T,IA) fsizeof(T##Arr, a, T##Atom, IA) #define TYARR_SZ2(T,IA) TYARR_SZ(T,IA) +#define TU I8 +#define TP(W,X) W##i8##X +#include "core/tyarrTemplate.h" +#define TU I16 +#define TP(W,X) W##i16##X +#include "core/tyarrTemplate.h" #define TU I32 #define TP(W,X) W##i32##X #include "core/tyarrTemplate.h" +#define TU C8 +#define TP(W,X) W##c8##X +#include "core/tyarrTemplate.h" +#define TU C16 +#define TP(W,X) W##c16##X +#include "core/tyarrTemplate.h" #define TU C32 #define TP(W,X) W##c32##X #include "core/tyarrTemplate.h" diff --git a/src/core/fillarr.h b/src/core/fillarr.h index ecfd71d4..78c05154 100644 --- a/src/core/fillarr.h +++ b/src/core/fillarr.h @@ -29,8 +29,8 @@ static bool fillEqual(B w, B x) { static B getFillR(B x) { // doesn't consume; can return bi_noFill if (isArr(x)) { switch(TI(x,elType)) { default: UD; - case el_f64: case el_i32: return m_i32(0); - case el_c32: return m_c32(' '); + case el_i8: case el_i16: case el_i32: case el_f64: return m_i32(0); + case el_c8: case el_c16: case el_c32: return m_c32(' '); case el_B:; u8 t = v(x)->type; if (t==t_fillarr ) return inc(c(FillArr,x )->fill); diff --git a/src/core/stuff.c b/src/core/stuff.c index 863255e5..76d37fa8 100644 --- a/src/core/stuff.c +++ b/src/core/stuff.c @@ -355,7 +355,7 @@ NOINLINE bool equal(B w, B x) { // doesn't consume usz ia = a(x)->ia; u8 we = TI(w,elType); u8 xe = TI(x,elType); - if (we<=el_f64 && xe<=el_f64) { assert(we==el_i32|we==el_f64); assert(xe==el_i32|xe==el_f64); + if (((we==el_f64 | we==el_i32) && (xe==el_f64 | xe==el_i32))) { if (we==el_i32) { i32* wp = i32any_ptr(w); if(xe==el_i32) { i32* xp = i32any_ptr(x); for (usz i = 0; i < ia; i++) if(wp[i]!=xp[i]) return false; } else { f64* xp = f64any_ptr(x); for (usz i = 0; i < ia; i++) if(wp[i]!=xp[i]) return false; } @@ -439,8 +439,12 @@ char* format_type(u8 u) { case t_md2BI:return"builtin md2"; case t_md2_block:return"md2 block"; case t_fork:return"fork"; case t_atop:return"atop"; case t_md1D:return"md1D"; case t_md2D:return"md2D"; case t_md2H:return"md2H"; - case t_harr :return"harr" ; case t_i8arr :return"i8arr" ; case t_i32arr :return"i32arr" ; case t_fillarr :return"fillarr" ; case t_c32arr :return"c32arr" ; case t_f64arr :return"f64arr" ; - case t_hslice:return"hslice"; case t_i8slice:return"i8slice"; case t_i32slice:return"i32slice"; case t_fillslice:return"fillslice"; case t_c32slice:return"c32slice"; case t_f64slice:return"f64slice"; + case t_i8arr :return"i8arr" ; case t_i16arr :return"i16arr" ; case t_i32arr :return"i32arr" ; + case t_i8slice:return"i8slice"; case t_i16slice:return"i16slice"; case t_i32slice:return"i32slice"; + case t_c8arr :return"c8arr" ; case t_c16arr :return"c16arr" ; case t_c32arr :return"c32arr" ; + case t_c8slice:return"c8slice"; case t_c16slice:return"c16slice"; case t_c32slice:return"c32slice"; + case t_harr :return"harr" ; case t_fillarr :return"fillarr" ; case t_f64arr :return"f64arr" ; + case t_hslice:return"hslice"; case t_fillslice:return"fillslice"; case t_f64slice:return"f64slice"; case t_comp:return"comp"; case t_block:return"block"; case t_body:return"body"; case t_scope:return"scope"; case t_scopeExt:return"scope extension"; case t_blBlocks: return "block list"; case t_ns:return"ns"; case t_nsDesc:return"nsDesc"; case t_fldAlias:return"alias"; case t_hashmap:return"hashmap"; case t_temp:return"temporary"; case t_nfn:return"nfn"; case t_nfnDesc:return"nfnDesc"; case t_freed:return"(freed by GC)"; case t_harrPartial:return"partHarr"; diff --git a/src/core/tyarr.c b/src/core/tyarr.c index a62ea28a..5f9d1d28 100644 --- a/src/core/tyarr.c +++ b/src/core/tyarr.c @@ -1,13 +1,27 @@ #include "../core.h" -#define TU F64 -#define TP(W,X) W##f64##X +B m_i8(i8 x) { return m_i32(x); } B m_i16(i16 x) { return m_i32(x); } +B m_c8(i8 x) { return m_c32(x); } B m_c16(i16 x) { return m_c32(x); } +#define TU I8 +#define TP(W,X) W##i8##X +#include "tyarrTemplate.c" +#define TU I16 +#define TP(W,X) W##i16##X +#include "tyarrTemplate.c" +#define TU I32 +#define TP(W,X) W##i32##X +#include "tyarrTemplate.c" +#define TU C8 +#define TP(W,X) W##c8##X +#include "tyarrTemplate.c" +#define TU C16 +#define TP(W,X) W##c16##X #include "tyarrTemplate.c" #define TU C32 #define TP(W,X) W##c32##X #include "tyarrTemplate.c" -#define TU I32 -#define TP(W,X) W##i32##X +#define TU F64 +#define TP(W,X) W##f64##X #include "tyarrTemplate.c" NOINLINE B m_caf64(usz sz, f64* a) { f64* rp; B r = m_f64arrv(&rp, sz); for (usz i = 0; i < sz; i++) rp[i] = a[i]; return r; } @@ -22,6 +36,9 @@ NOINLINE B m_str32(u32* s) { } void tyarr_init() { + i8arr_init(); i16arr_init(); i32arr_init(); + c8arr_init(); c16arr_init(); c32arr_init(); f64arr_init(); + { i32* tmp; bi_emptyIVec = m_i32arrv(&tmp, 0); gc_add(bi_emptyIVec); } { u32* tmp; bi_emptyCVec = m_c32arrv(&tmp, 0); gc_add(bi_emptyCVec); } diff --git a/src/core/tyarrTemplate.c b/src/core/tyarrTemplate.c index 2f4f2b52..734f945a 100644 --- a/src/core/tyarrTemplate.c +++ b/src/core/tyarrTemplate.c @@ -17,7 +17,7 @@ static B TP(,arr_get) (B x, usz n) { VTY(x,T_ARR ); return TP(m_,) (c(TArr , static B TP(,slice_get) (B x, usz n) { VTY(x,T_SLICE); return TP(m_,) (c(TSlice,x)->a[n]); } static bool TP(,arr_canStore) (B x) { return TP(q_,) (x); } -void TP(,arr_init)() { +static void TP(,arr_init)() { TIi(T_ARR,get) = TP(,arr_get); TIi(T_SLICE,get) = TP(,slice_get); TIi(T_ARR,getU) = TP(,arr_get); TIi(T_SLICE,getU) = TP(,slice_get); TIi(T_ARR,slice) = TP(,arr_slice); TIi(T_SLICE,slice) = TP(,slice_slice); diff --git a/src/h.h b/src/h.h index cbc24f44..728e65fc 100644 --- a/src/h.h +++ b/src/h.h @@ -100,6 +100,10 @@ #define i64 int64_t #define u64 uint64_t #define f64 double +#define I8_MAX 127 +#define I16_MAX 65535 +#define I8_MIN (-128) +#define I16_MIN (-65536) #define I32_MAX ((i32)((1LL<<31)-1)) #define I32_MIN ((i32)(-(1LL<<31))) #define I64_MIN ((i64)(1ULL<<63)) @@ -174,8 +178,8 @@ enum Type { /* 8*/ t_fork, t_atop, /*10*/ t_md1D, t_md2D, t_md2H, - /*13*/ t_harr , t_i8arr , t_i32arr , t_fillarr , t_c32arr , t_f64arr , - /*19*/ t_hslice, t_i8slice, t_i32slice, t_fillslice, t_c32slice, t_f64slice, + /*13*/ t_i8arr , t_i16arr , t_i32arr , t_c8arr , t_c16arr , t_c32arr , t_f64arr , t_harr , t_fillarr , + /*19*/ t_i8slice, t_i16slice, t_i32slice, t_c8slice, t_c16slice, t_c32slice, t_f64slice, t_hslice, t_fillslice, /*25*/ t_comp, t_block, t_body, t_scope, t_scopeExt, t_blBlocks, /*31*/ t_ns, t_nsDesc, t_fldAlias, t_vfyObj, t_hashmap, t_temp, t_nfn, t_nfnDesc, @@ -187,11 +191,18 @@ enum Type { }; enum ElType { // a⌈b shall return the type that can store both, if possible; any x<=el_f64 is an integer type - el_i32=0, - el_f64=1, - el_c32=2, - el_B =3, - el_MAX=4 // also used for incomplete in mut.c + el_bit=0, // unused; just here for completeness of ElType + el_i8 =1, + el_i16=2, + el_i32=3, + el_f64=4, + + el_c8 =5, + el_c16=6, + el_c32=7, + + el_B =8, + el_MAX=9 // also used for incomplete in mut.c }; diff --git a/src/load.c b/src/load.c index 5ef0021b..940bed59 100644 --- a/src/load.c +++ b/src/load.c @@ -5,7 +5,7 @@ #include "utils/file.h" #include "utils/builtins.h" -#define FOR_INIT(F) F(base) F(harr) F(fillarr) F(i32arr) F(c32arr) F(f64arr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(load) F(sysfnPost) +#define FOR_INIT(F) F(base) F(harr) F(mutF) F(fillarr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(load) F(sysfnPost) #define F(X) void X##_init(void); FOR_INIT(F) #undef F @@ -227,7 +227,6 @@ void load_init() { // very last init function #ifndef NO_RT B provide[] = {bi_type,bi_fill,bi_log,bi_grLen,bi_grOrd,bi_asrt,bi_add,bi_sub,bi_mul,bi_div,bi_pow,bi_floor,bi_eq,bi_le,bi_fne,bi_shape,bi_pick,bi_ud,bi_tbl,bi_scan,bi_fillBy,bi_val,bi_catch}; - #ifndef ALL_R0 B runtime_0[] = {bi_floor,bi_ceil,bi_stile,bi_lt,bi_gt,bi_ne,bi_ge,bi_rtack,bi_ltack,bi_join,bi_take,bi_drop,bi_select,bi_const,bi_swap,bi_each,bi_fold,bi_atop,bi_over,bi_before,bi_after,bi_cond,bi_repeat}; #else diff --git a/src/opt/single.c b/src/opt/single.c index f1abfe82..baf53339 100644 --- a/src/opt/single.c +++ b/src/opt/single.c @@ -24,6 +24,6 @@ #include "../ns.c" #include "../nfns.c" #include "../rtwrap.c" +#include "../jit/nvm.c" #include "../load.c" #include "../main.c" -#include "../jit/nvm.c" diff --git a/src/utils/builtins.h b/src/utils/builtins.h index e978163b..9a9bcd45 100644 --- a/src/utils/builtins.h +++ b/src/utils/builtins.h @@ -7,7 +7,7 @@ /* sfns.c*/A(shape,"⥊") A(pick,"⊑") A(pair,"{𝕨‿𝕩}") A(select,"⊏") A(slash,"/") A(join,"∾") A(couple,"≍") A(shiftb,"»") A(shifta,"«") A(take,"↑") A(drop,"↓") A(group,"⊔") A(reverse,"⌽") \ /* sort.c*/A(gradeUp,"⍋") A(gradeDown,"⍒") \ /* everything before the definition of •Type is defined to be pure, and everything after is not */ \ -/* sysfn.c*/M(type,"•Type") M(decp,"•Decompose") M(primInd,"•PrimInd") M(glyph,"•Glyph") A(fill,"•FillFn") M(sys,"•getsys") A(grLen,"•GroupLen") D(grOrd,"•groupOrd") \ +/* sysfn.c*/M(type,"•Type") M(decp,"•Decompose") M(primInd,"•PrimInd") M(glyph,"•Glyph") A(fill,"•FillFn") M(sys,"•getsys") A(grLen,"•GroupLen") D(grOrd,"•GroupOrd") \ /* sysfn.c*/M(repr,"•Repr") M(fmt,"•Fmt") A(asrt,"!") A(casrt,"!") M(out,"•Out") M(show,"•Show") M(bqn,"•BQN") M(sh,"•SH") M(fromUtf8,"•FromUTF8") \ /* sysfn.c*/D(cmp,"•Cmp") A(hash,"•Hash") M(unixTime,"•UnixTime") M(monoTime,"•MonoTime") M(delay,"•Delay") M(makeRand,"•MakeRand") M(reBQN,"•ReBQN") M(exit,"•Exit") M(getLine,"•GetLine") \ /*internal.c*/M(itype,"•internal.Type") M(refc,"•internal.Refc") M(squeeze,"•internal.Squeeze") M(isPure,"•internal.IsPure") A(info,"•internal.Info") \ diff --git a/src/utils/mut.c b/src/utils/mut.c index 50bd0c24..546a1673 100644 --- a/src/utils/mut.c +++ b/src/utils/mut.c @@ -42,3 +42,17 @@ NOINLINE void mut_pfree(Mut* m, usz n) { // free the first n elements if (m->type==el_B) harr_pfree(taga(m->val), n); else mm_free((Value*) m->val); } + +u8 el_orArr[el_MAX*16 + el_MAX]; +void mutF_init() { + for (u8 i = 0; i <= el_MAX; i++) { + for (u8 j = 0; j <= el_MAX; j++) { + u8 el; + if (i==el_MAX|j==el_MAX) el = i>j?j:i; + else if (i<=el_f64 && j<=el_f64) el = i>j?i:j; + else if (i>=el_c8 && i<=el_c32 && j>=el_c8 && j<=el_c32) el = i>j?i:j; + else el = el_B; + el_orArr[i*16 + j] = el; + } + } +} diff --git a/src/utils/mut.h b/src/utils/mut.h index 9dfe0444..be54676c 100644 --- a/src/utils/mut.h +++ b/src/utils/mut.h @@ -18,9 +18,9 @@ typedef struct Mut { usz ia; Arr* val; union { - i32* ai32; + i8* ai8; i16* ai16; i32* ai32; + u8* ac8; u16* ac16; u32* ac32; f64* af64; - u32* ac32; B* aB; }; } Mut; @@ -33,9 +33,13 @@ static void mut_init(Mut* m, u8 n) { usz sz; // hack around inlining of the allocator too many times switch(n) { default: UD; + case el_i8: ty = t_i8arr ; sz = TYARR_SZ(I8, ia); break; + case el_i16: ty = t_i16arr; sz = TYARR_SZ(I16,ia); break; case el_i32: ty = t_i32arr; sz = TYARR_SZ(I32,ia); break; - case el_f64: ty = t_f64arr; sz = TYARR_SZ(F64,ia); break; + case el_c8: ty = t_c8arr ; sz = TYARR_SZ(C8, ia); break; + case el_c16: ty = t_c16arr; sz = TYARR_SZ(C16,ia); break; case el_c32: ty = t_c32arr; sz = TYARR_SZ(C32,ia); break; + case el_f64: ty = t_f64arr; sz = TYARR_SZ(F64,ia); break; case el_B:; HArr_p t = m_harrUp(ia); m->val = (Arr*)t.c; @@ -45,9 +49,9 @@ static void mut_init(Mut* m, u8 n) { Arr* a = m_arr(sz, ty, ia); m->val = a; switch(n) { default: UD; // gcc generates horrible code for this (which should just be two instructions), but that's what gcc does - case el_i32: m->ai32 = ((I32Arr*)a)->a; break; + case el_i8: m->ai8 = ((I8Arr*)a)->a; break; case el_i16: m->ai16 = ((I16Arr*)a)->a; break; case el_i32: m->ai32 = ((I32Arr*)a)->a; break; + case el_c8: m->ac8 = ((C8Arr*)a)->a; break; case el_c16: m->ac16 = ((C16Arr*)a)->a; break; case el_c32: m->ac32 = ((C32Arr*)a)->a; break; case el_f64: m->af64 = ((F64Arr*)a)->a; break; - case el_c32: m->ac32 = ((C32Arr*)a)->a; break; } } void mut_to(Mut* m, u8 n); @@ -73,16 +77,9 @@ static Arr* mut_fp(Mut* m) { assert(m->type!=el_MAX); return m->val; } +extern u8 el_orArr[]; static u8 el_or(u8 a, u8 b) { - #define M(X) if(b==X) return a>X?a:X; - switch (a) { default: UD; - case el_c32: M(el_c32); return el_B; - case el_i32: M(el_i32); M(el_f64); return el_B; - case el_f64: M(el_i32); M(el_f64); return el_B; - case el_B: return el_B; - case el_MAX: return b; - } - #undef M + return el_orArr[a*16 + b]; } void mut_pfree(Mut* m, usz n); @@ -151,70 +148,15 @@ static B mut_getU(Mut* m, usz ms) { } } -// doesn't consume; fills m[ms…ms+l] with x -static void mut_fill(Mut* m, usz ms, B x, usz l) { - again:; - u8 nty; - switch(m->type) { default: UD; - case el_MAX: - nty = isF64(x)? (q_i32(x)? el_i32 : el_f64) : (isC32(x)? el_c32 : el_B); - goto change; - - case el_i32: { - if (RARE(!q_i32(x))) { nty = isF64(x)? el_f64 : el_B; goto change; } - i32* p = m->ai32+ms; - i32 v = o2iu(x); - for (usz i = 0; i < l; i++) p[i] = v; - return; - } - case el_c32: { - if (RARE(!isC32(x))) { nty = el_B; goto change; } - u32* p = m->ac32+ms; - u32 v = o2cu(x); - for (usz i = 0; i < l; i++) p[i] = v; - return; - } - case el_f64: { - if (RARE(!isF64(x))) { nty = el_B; goto change; } - f64* p = m->af64+ms; - f64 v = o2fu(x); - for (usz i = 0; i < l; i++) p[i] = v; - return; - } - case el_B: { - B* p = m->aB+ms; - for (usz i = 0; i < l; i++) p[i] = x; - if (isVal(x)) for (usz i = 0; i < l; i++) inc(x); - return; - } - } - change: - mut_to(m, nty); - goto again; -} static void mut_fillG(Mut* m, usz ms, B x, usz l) { // doesn't consume x switch(m->type) { default: UD; - case el_i32: { - assert(q_i32(x)); - i32* p = m->ai32+ms; - i32 v = o2iu(x); - for (usz i = 0; i < l; i++) p[i] = v; - return; - } - case el_c32: { - assert(isC32(x)); - u32* p = m->ac32+ms; - u32 v = o2cu(x); - for (usz i = 0; i < l; i++) p[i] = v; - return; - } - case el_f64: { - assert(isF64(x)); - f64* p = m->af64+ms; - f64 v = o2fu(x); - for (usz i = 0; i < l; i++) p[i] = v; - return; - } + case el_i8: { assert(q_i8 (x)); i8* p = m->ai8 +ms; i8 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } + case el_i16: { assert(q_i16(x)); i16* p = m->ai16+ms; i16 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } + case el_i32: { assert(q_i32(x)); i32* p = m->ai32+ms; i32 v = o2iu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } + case el_c8: { assert(q_c8 (x)); u8* p = m->ac8 +ms; u8 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } + case el_c16: { assert(q_c16(x)); u16* p = m->ac16+ms; u16 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } + case el_c32: { assert(q_c32(x)); u32* p = m->ac32+ms; u32 v = o2cu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } + case el_f64: { assert(isF64(x)); f64* p = m->af64+ms; f64 v = o2fu(x); for (usz i = 0; i < l; i++) p[i] = v; return; } case el_B: { B* p = m->aB+ms; for (usz i = 0; i < l; i++) p[i] = x; @@ -224,110 +166,83 @@ static void mut_fillG(Mut* m, usz ms, B x, usz l) { // doesn't consume x } } +// doesn't consume; fills m[ms…ms+l] with x +static void mut_fill(Mut* m, usz ms, B x, usz l) { + u8 nmt = el_or(m->type, selfElType(x)); + if (nmt!=m->type) mut_to(m, nmt); + mut_fillG(m, ms, x, l); +} + +// mut_copy but x is guaranteed to be a subtype of m +static void mut_copyG(Mut* m, usz ms, B x, usz xs, usz l) { assert(isArr(x)); + // printf("mut_%d[%d…%d] ← %s[%d…%d]\n", m->type, ms, ms+l, format_type(xt), xs, xs+l); fflush(stdout); + u8 xt = v(x)->type; + switch(m->type) { default: UD; + case el_i8: { i8* rp = m->ai8+ms; i8* xp = i8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case el_i16: { i16* rp = m->ai16+ms; + switch (xt) { default: UD; + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } + } + case el_i32: { i32* rp = m->ai32+ms; + switch (xt) { default: UD; + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } + } + case el_c8: { u8* rp = m->ac8+ms; u8* xp = c8any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case el_c16: { u16* rp = m->ac16+ms; + switch (xt) { default: UD; + case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } + } + case el_c32: { u32* rp = m->ac32+ms; + switch (xt) { default: UD; + case t_c8arr: case t_c8slice: { u8* xp = c8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_c16arr: case t_c16slice: { u16* xp = c16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_c32arr: case t_c32slice: { u32* xp = c32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } + } + case el_f64: { + f64* rp = m->af64+ms; + switch (xt) { default: UD; + case t_i8arr: case t_i8slice: { i8* xp = i8any_ptr (x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i16arr: case t_i16slice: { i16* xp = i16any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_i32arr: case t_i32slice: { i32* xp = i32any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + case t_f64arr: case t_f64slice: { f64* xp = f64any_ptr(x); for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; return; } + } + } + case el_B: { + B* mpo = m->aB+ms; + B* xp; + if (xt==t_harr) xp = harr_ptr(x); + else if (xt==t_hslice) xp = c(HSlice,x)->a; + else if (xt==t_fillarr) xp = c(FillArr,x)->a; + else { + BS2B xget = TIi(xt,get); + for (usz i = 0; i < l; i++) mpo[i] = xget(x,i+xs); + return; + } + memcpy(mpo, xp+xs, l*sizeof(B*)); + for (usz i = 0; i < l; i++) inc(mpo[i]); + return; + } + } +} + // expects x to be an array, each position must be written to precisely once // doesn't consume x -static void mut_copy(Mut* m, usz ms, B x, usz xs, usz l) { // TODO try harder to not bump type - assert(isArr(x)); - u8 xt = v(x)->type; - u8 xe = TIi(xt,elType); - // printf("mut_%d[%d…%d] ← %s[%d…%d]\n", m->type, ms, ms+l, format_type(xt), xs, xs+l); fflush(stdout); - again: - switch(m->type) { default: UD; - case el_MAX: goto change; - - case el_i32: { - if (RARE(xt!=t_i32arr & xt!=t_i32slice)) goto change; - i32* xp = i32any_ptr(x); - memcpy(m->ai32+ms, xp+xs, l*4); - return; - } - case el_c32: { - if (RARE(xt!=t_c32arr & xt!=t_c32slice)) goto change; - u32* xp = c32any_ptr(x); - memcpy(m->ac32+ms, xp+xs, l*4); - return; - } - case el_f64: { - f64* xp; - if (xt==t_f64arr) xp = f64arr_ptr(x); - else if (xt==t_f64slice) xp = c(F64Slice,x)->a; - else if (LIKELY(xt==t_i32arr|xt==t_i32slice)) { - i32* xp = i32any_ptr(x); - f64* rp = m->af64+ms; - for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; - return; - } - else goto change; - memcpy(m->af64+ms, xp+xs, l*8); - return; - } - case el_B: { - B* mpo = m->aB+ms; - B* xp; - if (xt==t_harr) xp = harr_ptr(x); - else if (xt==t_hslice) xp = c(HSlice,x)->a; - else if (xt==t_fillarr) xp = c(FillArr,x)->a; - else { - BS2B xget = TIi(xt,get); - for (usz i = 0; i < l; i++) mpo[i] = xget(x,i+xs); - return; - } - memcpy(mpo, xp+xs, l*sizeof(B*)); - for (usz i = 0; i < l; i++) inc(mpo[i]); - return; - } - } - change: - mut_to(m, el_or(m->type, xe)); - goto again; -} -static void mut_copyG(Mut* m, usz ms, B x, usz xs, usz l) { // mut_copy but x is guaranteed to be a subtype of m - assert(isArr(x)); - u8 xt = v(x)->type; - switch(m->type) { default: UD; - case el_i32: { - i32* xp = i32any_ptr(x); - memcpy(m->ai32+ms, xp+xs, l*4); - return; - } - case el_c32: { - u32* xp = c32any_ptr(x); - memcpy(m->ac32+ms, xp+xs, l*4); - return; - } - case el_f64: { - f64* xp; - if (xt==t_f64arr) xp = f64arr_ptr(x); - else if (xt==t_f64slice) xp = c(F64Slice,x)->a; - else { - assert(TIi(xt,elType)==el_i32); - i32* xp = i32any_ptr(x); - f64* rp = m->af64+ms; - for (usz i = 0; i < l; i++) rp[i] = xp[i+xs]; - return; - } - memcpy(m->af64+ms, xp+xs, l*8); - return; - } - case el_B: { - B* mpo = m->aB+ms; - B* xp; - if (xt==t_harr) xp = harr_ptr(x); - else if (xt==t_hslice) xp = c(HSlice,x)->a; - else if (xt==t_fillarr) xp = c(FillArr,x)->a; - else { - BS2B xget = TIi(xt,get); - for (usz i = 0; i < l; i++) mpo[i] = xget(x,i+xs); - return; - } - memcpy(mpo, xp+xs, l*sizeof(B*)); - for (usz i = 0; i < l; i++) inc(mpo[i]); - return; - } - } +static void mut_copy(Mut* m, usz ms, B x, usz xs, usz l) { assert(isArr(x)); + u8 nmt = el_or(m->type, TI(x,elType)); + if (nmt!=m->type) mut_to(m, nmt); + mut_copyG(m, ms, x, xs, l); } + static B vec_join(B w, B x) { // consumes both usz wia = a(w)->ia; usz xia = a(x)->ia;