From ab868a55f3f721afc6f7525d05d01110118f163f Mon Sep 17 00:00:00 2001 From: dzaima Date: Mon, 25 Apr 2022 02:59:40 +0300 Subject: [PATCH] singeli copy --- makefile | 4 +- src/core.h | 7 ++ src/core/harr.c | 21 ----- src/core/stuff.c | 2 +- src/core/tyarr.c | 81 ----------------- src/singeli/src/avx.singeli | 13 +-- src/singeli/src/avx2.singeli | 33 +++++-- src/singeli/src/base.singeli | 10 ++- src/singeli/src/cbqnDefs.singeli | 12 +++ src/singeli/src/copy.singeli | 136 ++++++++++++++++++++++++++++ src/singeli/src/equal.singeli | 3 +- src/singeli/src/expand.singeli | 38 -------- src/singeli/src/mask.singeli | 24 +++-- src/singeli/src/select.singeli | 2 - src/singeli/src/slash.singeli | 2 +- src/singeli/src/sse3.singeli | 3 +- src/utils/mut.c | 148 +++++++++++++++++++++++++++++++ test/README.md | 1 + test/copy.bqn | 49 ++++++++++ 19 files changed, 419 insertions(+), 170 deletions(-) create mode 100644 src/singeli/src/copy.singeli delete mode 100644 src/singeli/src/expand.singeli create mode 100644 test/copy.bqn diff --git a/makefile b/makefile index 6d91f47c..2051f949 100644 --- a/makefile +++ b/makefile @@ -137,10 +137,10 @@ preSingeliBin: git submodule update --init; \ fi @echo "pre-singeli build:" - @${MAKE} singeli=0 postmsg="singeli sources:" t=presingeli f='-O1' OUTPUT=obj/presingeli/BQN c + @${MAKE} singeli=0 postmsg="singeli sources:" t=presingeli f='-O1 -DPRE_SINGELI' OUTPUT=obj/presingeli/BQN c -gen-singeli: ${addprefix src/singeli/gen/, cmp.c dyarith.c slash.c equal.c scan.c expand.c} +gen-singeli: ${addprefix src/singeli/gen/, cmp.c dyarith.c copy.c equal.c scan.c slash.c} @echo $(postmsg) src/singeli/gen/%.c: src/singeli/src/%.singeli preSingeliBin @echo $< | cut -c 17- | sed 's/^/ /' diff --git a/src/core.h b/src/core.h index 3489d219..8e14da3c 100644 --- a/src/core.h +++ b/src/core.h @@ -33,6 +33,13 @@ static B* arr_bptr(B x) { assert(isArr(x)); if (v(x)->type==t_fillslice) return c(FillSlice,x)->a; return NULL; } +static B* arrV_bptr(Arr* x) { + if (x->type==t_harr) return ((HArr*)x)->a; + if (x->type==t_fillarr) return fillarr_ptr(x); + if (x->type==t_hslice) return ((HSlice*)x)->a; + if (x->type==t_fillslice) return ((FillSlice*)x)->a; + return NULL; +} static void* tyany_ptr(B x) { u8 t = v(x)->type; return IS_SLICE(t)? c(TySlice,x)->a : c(TyArr,x)->a; diff --git a/src/core/harr.c b/src/core/harr.c index bd0dda78..150ed7d9 100644 --- a/src/core/harr.c +++ b/src/core/harr.c @@ -59,27 +59,6 @@ B toKCells(B x, ur k) { return HARR_O(r).b; } -HArr* cpyHArr(B x) { - usz ia = a(x)->ia; - HArr_p r = m_harrUc(x); - u8 xe = TI(x,elType); - if (xe==el_bit) { u64* xp = bitarr_ptr(x); for(usz i=0; iia; \ - E* rp; Arr* r = m_##E##arrp(&rp, ia); \ - arr_shCopy(r, x); \ - u8 xe = TI(x,elType); \ - if (xe==el_bit) { u64* xp = bitarr_ptr(x); BIT_ICPY(E) } \ - else if (xe==el_i8 ) { i8* xp = i8any_ptr (x); for(usz i=0; iia; \ - T##Atom* rp; Arr* r = m_##E##arrp(&rp, ia); \ - arr_shCopy(r, x); \ - u8 xe = TI(x,elType); \ - if (xe==el_c8 ) { u8* xp = c8any_ptr (x); for(usz i=0; iia; - u64* rp; Arr* r = m_bitarrp(&rp, ia); - arr_shCopy(r, x); - u8 xe = TI(x,elType); - if (xe==el_bit) { u64* xp = bitarr_ptr(x); for(usz i=0; i>1<<2) | (iota{32}&1)}}} +def ucvt{T, x:X & w256u{X,64} & T== u8} = to_el{T, sel{[16]i8, ucvt{u32,x}, make{[32]i8, 4*iota{32}}}} + +def ucvt{T, x:X & w256{X} & width{T}==width{eltype{X}}} = to_el{T, x} # TODO check for not being f64/i64 diff --git a/src/singeli/src/base.singeli b/src/singeli/src/base.singeli index e1eebb1a..fcc4d400 100644 --- a/src/singeli/src/base.singeli +++ b/src/singeli/src/base.singeli @@ -16,8 +16,14 @@ def tail{n,x} = x - (x>>n << n) # get the n least significant bits def bit {k,x} = tail{1,x>>k} << k # get the k-th bit def rare{x:u1} = emit{u1, '__builtin_expect', x, 0} +def assert{x & x==0} = assert{'failed assertion'} +def assert{x & x==1} = 1 def assert{x:u1} = emit{void, 'si_assert', x} +def min{a, b & knum{a} & knum{b}} = tern{ab, a, b} + + # various checks def knum{x} = match{kind{x},'number'} @@ -101,7 +107,7 @@ def broadcast{n, v & knum{n}} = @collect(n) v # debug stuff +def printfType{T} = tern{isfloat{T}, '%.17g', merge{'%', tern{width{T}==64, 'l', ''}, tern{issigned{T}, 'd', 'u'}}} def print{x & match{kind{x},'symbol'}} = { emit{void, 'printf', '"%s"', merge{'"', x, '"'}}; x } -def print{x & anyNum{x}} = { emit{void, 'printf', tern{issigned{x}, '"%d"', '"%u"'}, x}; x } -def print{x:T & anyNum{x} & width{T}==64} = { emit{void, 'printf', tern{issigned{x}, '"%ld"', '"%lu"'}, x}; x } +def print{x:T & anyNum{x}} = { emit{void, 'printf', merge{'"', printfType{T}, '"'}, x}; x } def println{x} = { print{x}; print{'\n'}; x } \ No newline at end of file diff --git a/src/singeli/src/cbqnDefs.singeli b/src/singeli/src/cbqnDefs.singeli index 1d604b16..d8cdb842 100644 --- a/src/singeli/src/cbqnDefs.singeli +++ b/src/singeli/src/cbqnDefs.singeli @@ -9,6 +9,18 @@ def q_chr{T,x & T==u8 } = bcall{u1, 'q_c8', x} def q_chr{T,x & T==u16} = bcall{u1, 'q_c16', x} def q_chr{T,x & T==u32} = bcall{u1, 'q_c32', x} +def cbqn_c32Tag{} = emit{u64, '', 'C32_TAG'} +def cbqn_tagTag{} = emit{u64, '', 'TAG_TAG'} +def cbqn_varTag{} = emit{u64, '', 'VAR_TAG'} +def cbqn_extTag{} = emit{u64, '', 'EXT_TAG'} +def cbqn_rawTag{} = emit{u64, '', 'RAW_TAG'} +def cbqn_md1Tag{} = emit{u64, '', 'MD1_TAG'} +def cbqn_md2Tag{} = emit{u64, '', 'MD2_TAG'} +def cbqn_funTag{} = emit{u64, '', 'FUN_TAG'} +def cbqn_nspTag{} = emit{u64, '', 'NSP_TAG'} +def cbqn_objTag{} = emit{u64, '', 'OBJ_TAG'} +def cbqn_arrTag{} = emit{u64, '', 'ARR_TAG'} + def cbqn_elType{T & T==u1 } = 0 def cbqn_elType{T & T==i8 } = 1 def cbqn_elType{T & T==i16} = 2 diff --git a/src/singeli/src/copy.singeli b/src/singeli/src/copy.singeli new file mode 100644 index 00000000..e3f89818 --- /dev/null +++ b/src/singeli/src/copy.singeli @@ -0,0 +1,136 @@ +include './base' +include './sse3' +include './avx' +include './avx2' +include './mask' +include './cbqnDefs' +include './bitops' + + +def spreadBits{T==[32]u8, a:u32} = { + def idxs = iota{32} + b:= broadcast{[8]u32, a} + c:= [32]u8~~b + d:= sel{[16]u8, c, make{[32]i8, idxs>>3 + bit{4, idxs}}} + e:= make{[32]u8, 1< { + x:= b_getBatch{bulk, xp, i} # TODO unroll f64 by two to make b_getBatch not sad + y:= spreadBits{TU, x} + r:= y & TU~~broadcast{T, 1} + storeBatch{rp, i, T~~r, M} + }} +} + + +copy{vw, X, R}(x: *u8, r: *u8, l:u64, xRaw: *u8) : void = { + assert{l!=0} + + def bulk = vw/max{width{X}, width{R}} + xp:= *tern{X==u1, u64, X} ~~ x + rp:= *tern{R==u1, u64, R} ~~ r + def XV = [bulk]X + def RV = [bulk]R + + if (R==u64) { + # show{'R==u64', X, R} + assert{((X==u8) | (X==u16)) | (X==u32)} + maskedLoop{bulk, l, {i, M} => { # TODO could maybe read 256 bits and use unpack to write >256 + v:= loadBatch{xp, i, RV} + v|= broadcast{RV, cbqn_c32Tag{} << 48} + storeBatch{rp, i, v, M} + }} + } else if (X==u1 and R==u1) { + # show{'u1u1', X, R} + def V64 = [vw/64]u64 + maskedLoop{vcount{V64}, cdiv{l, 64}, {i, M} => { + v:= loadBatch{xp, i, V64} + storeBatch{rp, i, v, M} + }} + } else if (X==u1) { + # show{'X==u1', X, R} + copyFromBits{[bulk]R, *u64~~x, *R~~r, l} + } else if (R==u1) { + # show{'R==u1', X, R} + def XU = ty_u{XV} + maskedLoop{bulk, l, {i, M} => { + v:= loadBatch{xp, i, XV} + r:= getmask{(XU~~v) == XU~~broadcast{XV,1}} + b_setBatch{vcount{XV}, rp, i, r} # TODO something more special for f64 + }} + } else if (width{X}<=width{R}) { + # show{'w{X}<=w{R}', X, R} + maskedLoop{bulk, l, {i, M} => { + v:= loadBatch{xp, i, RV} + storeBatch{rp, i, v, M} + }} + } else { + # show{'w{X}>w{R}', X, R} + maskedLoop{bulk, l, {i, M} => { + v:= loadBatch{xp, i, XV} + storeBatch{rp, i, v, M} + }} + } +} + +# avx2_copy_src_dst +# x→int & equal-width copies +'avx2_copy_1_1' = copy{256, u1, u1} +'avx2_copy_1_i8' = copy{256, u1, i8} +'avx2_copy_1_i16' = copy{256, u1, i16} +'avx2_copy_1_i32' = copy{256, u1, i32} + +'avx2_copy_i8_1' = copy{256, i8, u1} +'avx2_copy_i8_i8', 'avx2_copy_c8_c8' = copy{256, i8, i8} +'avx2_copy_i8_i16' = copy{256, i8, i16} +'avx2_copy_i8_i32' = copy{256, i8, i32} + +'avx2_copy_i16_1' = copy{256, i16, u1} +'avx2_copy_i16_i8' = copy{256, i16, i8} +'avx2_copy_i16_i16', 'avx2_copy_c16_c16' = copy{256, i16, i16} +'avx2_copy_i16_i32' = copy{256, i16, i32} + +'avx2_copy_i32_1' = copy{256, i32, u1} +'avx2_copy_i32_i8' = copy{256, i32, i8} +'avx2_copy_i32_i16' = copy{256, i32, i16} +'avx2_copy_i32_i32', 'avx2_copy_c32_c32'= copy{256, i32, i32} + +'avx2_copy_f64_1' = copy{256, f64, u1} +'avx2_copy_f64_i8' = copy{256, f64, i8} +'avx2_copy_f64_i16' = copy{256, f64, i16} +'avx2_copy_f64_i32' = copy{256, f64, i32} + +# x→f64, x→B (no avx2_copy_B_B because that may possibly need refcounting) +'avx2_copy_1_f64', 'avx2_copy_1_B' = copy{256, u1, f64} +'avx2_copy_i8_f64', 'avx2_copy_i8_B' = copy{256, i8, f64} +'avx2_copy_i16_f64', 'avx2_copy_i16_B' = copy{256, i16, f64} +'avx2_copy_i32_f64', 'avx2_copy_i32_B' = copy{256, i32, f64} +'avx2_copy_f64_f64', 'avx2_copy_f64_B' = copy{256, f64, f64} + +# chr→x +'avx2_copy_c8_c16' = copy{256, u8, u16} +'avx2_copy_c8_c32' = copy{256, u8, u32} +'avx2_copy_c8_B' = copy{256, u8, u64} + +'avx2_copy_c16_c8' = copy{256, u16, u8} +'avx2_copy_c16_c32' = copy{256, u16, u32} +'avx2_copy_c16_B' = copy{256, u16, u64} + +'avx2_copy_c32_c8' = copy{256, u32, u8} +'avx2_copy_c32_c16' = copy{256, u32, u16} +'avx2_copy_c32_B' = copy{256, u32, u64} + +# B→chr +'avx2_copy_B_c8' = copy{256, u64, u8} +'avx2_copy_B_c16' = copy{256, u64, u16} +'avx2_copy_B_c32' = copy{256, u64, u32} diff --git a/src/singeli/src/equal.singeli b/src/singeli/src/equal.singeli index 2b3ebf83..3b5ca617 100644 --- a/src/singeli/src/equal.singeli +++ b/src/singeli/src/equal.singeli @@ -55,7 +55,8 @@ equal{W, X}(w:*u8, x:*u8, l:u64, d:u64) : u1 = { def fac = width{X}/width{W} maskedLoop{bulk, l, {i, M} => { - cw:= load{*ww{tern{fac==1, 256, 128}, u8} ~~ (w + i*32/fac)} + # TODO update this to modern mask stuff + cw:= load{*ww{tern{fac==1, 256, 128}, W} ~~ (w + i*32/fac)} cx:= load{*ww{256, X} ~~ x, i} cwc:= cvt{W, ww{256, X}, cw} if (anyne{cwc,cx,M}) return{0} diff --git a/src/singeli/src/expand.singeli b/src/singeli/src/expand.singeli deleted file mode 100644 index 7a5f0ad5..00000000 --- a/src/singeli/src/expand.singeli +++ /dev/null @@ -1,38 +0,0 @@ -include './base' -include './sse3' -include './avx' -include './avx2' -include './mask' -include './bitops' - - -def bitspread{T==[32]u8, a:u32} = { - def idxs = iota{32} - b:= broadcast{[8]u32, a} - c:= [32]u8~~b - d:= sel{[16]u8, c, make{[32]i8, idxs>>3 + bit{4, idxs}}} - e:= make{[32]u8, 1< { - x:= b_getBatch{bulk, xp, i} # TODO unroll f64 by two to make b_getBatch not sad - y:= bitspread{TU, x} - r:= y & TU~~broadcast{T, 1} - storeBatch{rp, i, T~~r, M} - }} -} - -'avx2_expand_1_i8' = bitexpand{[32]i8} -'avx2_expand_1_i16' = bitexpand{[16]i16} -'avx2_expand_1_i32' = bitexpand{[ 8]i32} -'avx2_expand_1_f64' = bitexpand{[ 4]f64} \ No newline at end of file diff --git a/src/singeli/src/mask.singeli b/src/singeli/src/mask.singeli index d206ca46..cd3cdb09 100644 --- a/src/singeli/src/mask.singeli +++ b/src/singeli/src/mask.singeli @@ -47,9 +47,22 @@ def maskAfter{n} = { -# store low packed elements of x to P; TODO the w parameter isn't doing much? -def storeLow{ptr:P, w, x:T & width{eltype{P}} == width{eltype{T}}} = store{*T~~ptr, 0, x} -def storeLow{ptr:P, w, x:T & w256{T} & w==64} = store{*u64~~ptr, 0, extract{[4]u64~~x, 0}} +# store low packed elements of x to P +def storeLow{ptr:P, w, x:T & width{T}==w} = store{*T~~ptr, 0, x} +def storeLow{ptr:P, w, x:T & w256{T} & w==128} = store{*[128/width{eltype{T}}](eltype{T})~~ptr, 0, half{x, 0}} +def storeLow{ptr:P, w, x:T & w256{T} & w==64} = emit{void, '_mm_storeu_si64', ptr, v2i{half{x, 0}}} +def storeLow{ptr:P, w, x:T & w256{T} & w==32} = emit{void, '_mm_storeu_si32', ptr, v2i{half{x, 0}}} +def storeLow{ptr:P, w, x:T & w256{T} & w==16} = emit{void, '_mm_storeu_si16', ptr, v2i{half{x, 0}}} + +def loadLow{ptr:P, w & w128{eltype{P}} & w==128} = eltype{P} ~~ load{*[16]u8 ~~ ptr} +def loadLow{ptr:P, w & w128{eltype{P}} & w== 64} = eltype{P} ~~ emit{[16]u8, '_mm_loadu_si64', ptr} +def loadLow{ptr:P, w & w128{eltype{P}} & w== 32} = eltype{P} ~~ emit{[16]u8, '_mm_loadu_si32', ptr} +def loadLow{ptr:P, w & w128{eltype{P}} & w== 16} = eltype{P} ~~ emit{[16]u8, '_mm_loadu_si16', ptr} + +def loadLow{ptr:P, w & w256{eltype{P}} & w<256} = undefPromote{eltype{P}, loadLow{*[16]u8 ~~ ptr, w}} +def loadLow{ptr:P, w & width{eltype{P}} == w} = load{*eltype{P} ~~ ptr} + +def loadLowBatch{T, ptr:P, w, n & eltype{P}==eltype{T}} = loadLow{*T ~~ (ptr + n*(w/width{eltype{P}})), w} # store vcount{T} items into the n'th batch of ptr elements, compressing the items if needed; masked by M def storeBatch{ptr:P, n, x:T, M} = { @@ -66,11 +79,10 @@ def loadBatch{ptr:P, n, T} = { def rpos = ptr + n*vcount{T} def E0 = eltype{P} - if (width{eltype{T}} == width{E0}) load{*T ~~ rpos} - else cvt{E0, T, load{*[16]u8 ~~ rpos}} + cvt{E0, T, loadLow{*to_el{E0, T} ~~ rpos, vcount{T}*width{E0}}} } -def maskedLoop{bulk, l, step} = { +def maskedLoop{bulk, l, step} = { # TODO version assuming l!=0 m:u64 = l/bulk @for (i to m) step{i, maskNone} diff --git a/src/singeli/src/select.singeli b/src/singeli/src/select.singeli index 5197e2c8..5378aff0 100644 --- a/src/singeli/src/select.singeli +++ b/src/singeli/src/select.singeli @@ -5,8 +5,6 @@ include './avx' include './avx2' include './mask' -def min{a, b & knum{a} & knum{b}} = tern{a=width{B}} = w/width{A} diff --git a/src/singeli/src/slash.singeli b/src/singeli/src/slash.singeli index 5de2d2a4..b76ae22c 100644 --- a/src/singeli/src/slash.singeli +++ b/src/singeli/src/slash.singeli @@ -22,7 +22,7 @@ def comp16{w:*u64, X, r:*i16, l:u64} = { @for(w in reinterpret{*u8,w} over i to cdiv{l,8}) { def step{w} = { pc:= popc{w} - store{reinterpret{*u64,r}, 0, pext{promote{u64,X{}}, load{c16lut, w}}} + store{reinterpret{*u64,r}, 0, pext{promote{u64,X{}}, load{c16lut, w}}} # TODO don't use unaligned store to make valgrind/ubsan happy r+= pc } step{w&15} diff --git a/src/singeli/src/sse3.singeli b/src/singeli/src/sse3.singeli index 47ea5811..e8727a62 100644 --- a/src/singeli/src/sse3.singeli +++ b/src/singeli/src/sse3.singeli @@ -85,7 +85,7 @@ def extract{x:T, i & w128i{T,16} & knum{i}} = emit{eltype{T}, '_mm_extract_epi16 # debug stuff def printGen{x, s, n} = apply{emit, merge{tup{void, 'printf', merge{'"', apply{merge,each{{c}=>{if(c>0) merge{',',s}; else s}, iota{n}}}, '"'}}, each{{c}=>extract{x,c}, iota{n}}}} -def print{x:T & isvec{T}} = printGen{x, merge{'%', tern{width{eltype{T}}==64, 'l', ''}, tern{issigned{x}, 'd', 'u'}}, vcount{T}} +def print{x:T & isvec{T}} = printGen{x, printfType{eltype{T}}, vcount{T}} @@ -97,6 +97,7 @@ def extract{x:T, i & w128i{T,32} & knum{i}} = emit{eltype{T}, '_mm_extract_epi32 def extract{x:T, i & w128i{T,64} & knum{i}} = emit{eltype{T}, '_mm_extract_epi64', x, i} # conversion +def cvt{F, T, a:A & eltype{T}==F} = T~~a def cvt{F==i8, T==[8]i16, a:A & w128i{A}} = emit{T, '_mm_cvtepi8_epi16', a} def cvt{F==i8, T==[4]i32, a:A & w128i{A}} = emit{T, '_mm_cvtepi8_epi32', a} def cvt{F==i16, T==[4]i32, a:A & w128i{A}} = emit{T, '_mm_cvtepi16_epi32', a} diff --git a/src/utils/mut.c b/src/utils/mut.c index 4d204435..4c2bf850 100644 --- a/src/utils/mut.c +++ b/src/utils/mut.c @@ -179,6 +179,154 @@ DEF_G(void, copy, B, (Mut* m, usz ms, B x, usz xs, usz l)) { } } +#if SINGELI + #include + #if __GNUC__ && !__clang__ // yay gcc + __m128i _mm_loadu_si32(void* p) { + return (__m128i) _mm_load_ss(p); + } + void _mm_storeu_si32(void* p, __m128i x) { + _mm_store_ss(p, _mm_castsi128_ps(x)); + } + #endif + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-variable" + #include "../singeli/gen/copy.c" + #pragma GCC diagnostic pop + typedef void (*copy_fn)(u8*, u8*, u64, u8*); + + static void badCopy(u8* xp, u8* rp, u64 len, u8* xRaw) { + err("Copying wrong array type"); + } + + #define COPY_FN(X,R) avx2_copy_##X##_##R + #define MAKE_CPY(MAKE, GET, WR, XRP, H2T, T, ...) \ + static copy_fn copy##T##Fns[10]; \ + static void cpy##T##Arr_B(u8* xp, u8* rp, u64 ia, u8* xRaw) { \ + Arr* xa = (Arr*)xRaw; B* bxp = arrV_bptr(xa); \ + if (bxp!=NULL && sizeof(B)==sizeof(f64)) { \ + H2T; \ + } else { AS2B fn = TIv(xa,GET); \ + for (usz i=0; iia; \ + MAKE; arr_shCopy(r, x); \ + if (ia>0) { \ + copy##T##Fns[TI(x,elType)](tyany_ptr(x), (u8*)(XRP), ia, (u8*)a(x)); \ + } \ + decG(x); \ + return (T##Arr*)r; \ + } + #define BIT_PUT(V) bitp_set((u64*)rp, i, o2bu(V)) + #define H2T_COPY(T) copy##T##Fns[el_MAX]((u8*)bxp, rp, ia, xRaw) + #define MAKE_TYCPY(T, E, F, ...) MAKE_CPY(T##Atom* rp; Arr* r = m_##E##arrp(&rp, ia), getU, ((T##Atom*)rp)[i] = F, rp, H2T_COPY(T), T, __VA_ARGS__) + #define MAKE_CCPY(T,E) MAKE_TYCPY(T, E, o2cu, {badCopy, badCopy, badCopy, badCopy, badCopy, COPY_FN(c8,E),COPY_FN(c16,E),COPY_FN(c32,E),cpy##T##Arr_B,COPY_FN(B,E)}) + #define MAKE_ICPY(T,E) MAKE_TYCPY(T, E, o2fu, {COPY_FN(1,E),COPY_FN(i8,E),COPY_FN(i16,E),COPY_FN(i32,E),COPY_FN(f64,E),badCopy, badCopy, badCopy, cpy##T##Arr_B,COPY_FN(f64,E)}) + MAKE_CPY(HArr_p p = m_harrUp(ia); Arr* r = (Arr*)p.c, get, ((B*)rp)[i] =, p.a, for (usz i=0; iia; \ + E* rp; Arr* r = m_##E##arrp(&rp, ia); \ + arr_shCopy(r, x); \ + u8 xe = TI(x,elType); \ + if (xe==el_bit) { u64* xp = bitarr_ptr(x); for(usz i=0; iia; \ + T##Atom* rp; Arr* r = m_##E##arrp(&rp, ia); \ + arr_shCopy(r, x); \ + u8 xe = TI(x,elType); \ + if (xe==el_c8 ) { u8* xp = c8any_ptr (x); for(usz i=0; iia; + HArr_p r = m_harrUc(x); + u8 xe = TI(x,elType); + if (xe==el_bit) { u64* xp = bitarr_ptr(x); for(usz i=0; iia; + u64* rp; Arr* r = m_bitarrp(&rp, ia); + arr_shCopy(r, x); + u8 xe = TI(x,elType); + if (xe==el_bit) { u64* xp = bitarr_ptr(x); for(usz i=0; iabit, ms)); } static B m_getU_i8 (Mut* m, usz ms) { return m_i32(m->ai8 [ms]); } diff --git a/test/README.md b/test/README.md index 1c48dcc7..adae28b4 100644 --- a/test/README.md +++ b/test/README.md @@ -8,6 +8,7 @@ test/x86Cfgs.sh path/to/mlochbaum/BQN // run the test suite for x86-64-specific test/moreCfgs.sh path/to/mlochbaum/BQN // run "2+2" in a bunch of configurations ./BQN test/cmp.bqn // fuzz-test scalar comparison functions =≠<≤>≥ ./BQN test/equal.bqn // fuzz-test 𝕨≡𝕩 +./BQN test/copy.bqn // fuzz-test creating new arrays with elements copied from another ./BQN test/bitcpy.bqn // fuzz-test bit_cpy; requires a CBQN build with -DTEST_BITCPY ./BQN test/squeeze.bqn // fuzz-test squeezing; requires a CBQN build with -DEEQUAL_NEGZERO ``` \ No newline at end of file diff --git a/test/copy.bqn b/test/copy.bqn new file mode 100644 index 00000000..8e312b5b --- /dev/null +++ b/test/copy.bqn @@ -0,0 +1,49 @@ +⟨Variation, ListVariations, ClearRefs⟩ ⇐ •internal +u ← ⌊100×(•UnixTime+1|100וMonoTime)@ +R ← (•MakeRand •Show u).Range + +vn ← "Ab"‿"Ai8"‿"Ai16"‿"Ai32"‿"Af64"‿"Ac8"‿"Ac16"‿"Ac32"‿"Ah"‿"Af" +vi ←⟨0, 0, 0, 0, 1, 2, 2, 2, 1, 1⟩ + +vf ← ∾⟨ + ↓⟜(5↑ vn)¨ ↕5 + ↓⟜(3↑5↓vn)¨ ↕3 + ⟨⟩‿⟨⟩ +⟩ +vf ↩ ∾⟜(8↓vn)¨ vf +vf ↩ (↕10) {𝕩 ∾ 'S'∾¨ 1↓¨ (𝕨=0)↓𝕩}¨ vf +vf ↩ {𝕩 ∾ ∾⟜"Inc"¨ 𝕩}¨ vf + +•Show¨ vf + +count ← 10000 +eqlen ← 0 + +{𝕊: + n ← R 2⋆6+R 9 + v ← R ≠vn + l ← ⊢◶⟨ + {𝕊: (v⊑0∾2⋆6‿14‿30) -˜ n R 2⋆v⊑1‿7‿15‿31} + {𝕊: ÷n R 0} + {𝕊: @+n R (v-5)⊑256‿65536‿1114112} + ⟩ v⊑vi + + vs ← v⊑vf + vsLV ← ListVariations l + + { 𝕊 v0: + a0 ← v0 Variation l + ! a0 ≡ l + { 𝕊: + a1 ← 𝕩 Variation a0 + a0 ≡ a1?1; + •Out "fail:" + •Show v0‿"→"‿𝕩 + •Exit 1 + }¨ vs + }¨ vs + ClearRefs@ + eqlen+↩ (≠vs) ≡ +´⥊vs≡⌜vsLV +}¨ ↕count + +•Out "Fraction of matching variation count to ListVariations: "∾(•Repr eqlen÷count)∾" (expected: ~0.999)" \ No newline at end of file