From 9e47ce066ae219136a3c9c79fe1970748f32a747 Mon Sep 17 00:00:00 2001 From: dzaima Date: Mon, 26 May 2025 23:01:00 +0300 Subject: [PATCH] more proper eltype copying helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes c¨⌾(m⊸/)genericlist arr_bptr==NULL path copying input during noAlloc --- src/builtins/slash.c | 34 ++++++---------------- src/utils/mut.c | 67 +++++++++++++++++++++++++++++++++++--------- src/utils/mut.h | 25 +++++++++++++---- 3 files changed, 82 insertions(+), 44 deletions(-) diff --git a/src/builtins/slash.c b/src/builtins/slash.c index c392ef58..6d369960 100644 --- a/src/builtins/slash.c +++ b/src/builtins/slash.c @@ -1084,7 +1084,7 @@ B slash_ucw(B t, B o, B w, B x) { // (c ; C˙)¨⌾(w⊸/) x #if SINGELI_SIMD - if (isFun(o) && TY(o)==t_md1D) { + if (MAY_F(isFun(o) && TY(o)==t_md1D)) { u8 xe = TI(x,elType); Md1D* od = c(Md1D,o); @@ -1109,28 +1109,12 @@ B slash_ucw(B t, B o, B w, B x) { else incByG(c, sum-1); } - DirectArr r; - void* xp; - if (re != xe) { - assert(xe != el_B); - r = toEltypeArr(x, re); - x = incG(r.obj); - xp = r.data; - } else { - if (xe==el_B) { - r = potentiallyReuse(x); - if (r.obj.u == x.u) { - xp = r.data; - decByMask(bitany_ptr(w), xp, ia, 0); - } else { - TO_BPTR(x); - xp = arr_bptrG(x); - incByMask(bitany_ptr(w), xp, ia, 1); - } - } else { - r = potentiallyReuse(x); - xp = tyany_ptr(x); - } + ConvArr r = toEltypeArrX(x, re); + assert((xe==el_B) == (r.refState!=0)); + if (r.refState != 0) { + assert(re == el_B); + if (r.refState == 1) decByMask(bitany_ptr(w), r.xp, ia, 0); + else incByMask(bitany_ptr(w), r.xp, ia, 1); } u64 cv; @@ -1141,10 +1125,10 @@ B slash_ucw(B t, B o, B w, B x) { cv = re==el_f64? r_f64u(o2fG(c)) : r_Bu(c); } - blendArrScalarFns[elwBitLog(re)](r.data, xp, cv, bitany_ptr(w), ia); + blendArrScalarFns[elwBitLog(re)](r.rp, r.xp, cv, bitany_ptr(w), ia); NOGC_E; decG(w); decG(x); - return r.obj; + return r.res; } #endif goto notConstEach; notConstEach:; diff --git a/src/utils/mut.c b/src/utils/mut.c index 062edbd7..41b908d2 100644 --- a/src/utils/mut.c +++ b/src/utils/mut.c @@ -799,12 +799,14 @@ static NOINLINE DirectArr toFillArr(B x, B fill) { static void* reusableArr_ptr(Arr* t, u8 el) { return el==el_B? (void*)(PTY(t)==t_fillarr? fillarrv_ptr(t) : harrv_ptr(t)) : tyarrv_ptr((TyArr*)t); } -DirectArr toEltypeArr(B x, u8 re) { +static DirectArr doReuse(B x, u8 xe) { // consumes (i.e. transfers x to result) + assert(TI(x,elType)==xe); + x = REUSE(x); + return (DirectArr){x, reusableArr_ptr(a(x), xe)}; +} +DirectArr toEltypeArr(B x, u8 re) { // consumes assert(isArr(x)); - if (reusable(x) && re==reuseElType[TY(x)]) { - x = REUSE(x); - return (DirectArr){x, reusableArr_ptr(a(x), re)}; - } + if (reusable(x) && re==reuseElType[TY(x)]) return doReuse(x, re); Arr* tyarr; switch (re) { default: UD; @@ -827,18 +829,15 @@ DirectArr toEltypeArr(B x, u8 re) { tyarr: return (DirectArr){taga(tyarr), tyarrv_ptr((TyArr*) tyarr)}; } -static NOINLINE DirectArr m_fillarrAs(B x, B fill) { + + + +static NOINLINE DirectArr m_fillarrAs(B x, B fill) { // doesn't consume Arr* r = arr_shCopy(m_fillarrp(IA(x)), x); fillarr_setFill(r, fill); return (DirectArr){taga(r), fillarrv_ptr(r)}; } -DirectArr potentiallyReuse(B x) { - assert(isArr(x)); - u8 xe = TI(x,elType); - if (reusable(x) && xe == reuseElType[TY(x)]) { - x = REUSE(x); - return (DirectArr){incG(x), reusableArr_ptr(a(x), xe)}; - } +static DirectArr m_directarrAs(B x, u8 xe) { // doesn't consume if (xe==el_B) { B fill = getFillR(x); if (!noFill(fill)) return m_fillarrAs(x, fill); @@ -850,6 +849,48 @@ DirectArr potentiallyReuse(B x) { void* rp = m_tyarrlbc(&r, elwBitLog(xe), x, el2t(xe)); return (DirectArr) {r, rp}; } +static bool canReuse(B x, u8 xe) { + return reusable(x) && xe == reuseElType[TY(x)]; +} +DirectArr potentiallyReuse(B x) { // doesn't consume + assert(isArr(x)); + u8 xe = TI(x,elType); + return canReuse(x, xe)? doReuse(incG(x), xe) : m_directarrAs(x, xe); +} + +ConvArr toEltypeArrX(B x, u8 re) { // doesn't consume + debug_assert(isArr(x) && el_or(re,TI(x,elType))==re); + u8 xe = TI(x,elType); + u8 refState = 0; + DirectArr dr; + if (re == xe) { + if (canReuse(x, xe)) { + refState = xe==el_B? 1 : 0; + dr = doReuse(incG(x), xe); + goto ret_dr; + } else { + void* xp; + if (xe == el_B) { + xp = arr_bptr(x); + if (xp == NULL) { + refState = 1; + goto toEltype; + } + refState = 2; + } else { + xp = tyany_ptr(x); + } + DirectArr r = m_directarrAs(x, re); + return (ConvArr){r.obj, r.data, xp, refState}; + } + } else { + assert(xe != el_B); + toEltype:; + dr = toEltypeArr(incG(x), re); + ret_dr: + return (ConvArr){dr.obj, dr.data, dr.data, refState}; + } +} B directGetU_bit(void* data, ux i) { return m_f64(bitp_get(data,i));} void directSet_bit(void* data, ux i, B v) { bitp_set(data, i, o2bG(v)); } B directGetU_i8 (void* data, ux i) { return m_f64((( i8*)data)[i]); } void directSet_i8 (void* data, ux i, B v) { (( i8*)data)[i] = o2iG(v); } diff --git a/src/utils/mut.h b/src/utils/mut.h index f9443898..affaec01 100644 --- a/src/utils/mut.h +++ b/src/utils/mut.h @@ -288,15 +288,28 @@ extern INIT_GLOBAL DirectGet directGetU[el_MAX]; extern INIT_GLOBAL DirectSet directSet[el_MAX]; extern INIT_GLOBAL DirectSetRange directSetRange[el_MAX]; -// consumes x; returns an array with eltype==re, with same shape/elements/fill as x, and its data pointer -DirectArr toEltypeArr(B x, u8 re); +// returns an array with eltype==re, with same shape/elements/fill as x, and its data pointer +DirectArr toEltypeArr(B x, u8 re); // consumes -// doesn't consume; returns array with same shape & fill as x, returning x itself if possible (iif so, x.u==obj.u). +// returns array with same shape & fill as x, returning x itself if possible (iif so, x.u==obj.u). // If reused, the object is untouched besides having its refcount incremented and flags cleared. // As such, if an el_B array is reused, all elements effectively have 1 more refcount than they should as x's elements never get freed -// Otherwise, functionality is the same as if a regular new array was made -// May start NOGC -DirectArr potentiallyReuse(B x); +// Otherwise, functionality is the same as if a regular new array was made (i.e. uninitialized elements, may start NOGC) +DirectArr potentiallyReuse(B x); // doesn't consume + +typedef struct { + B res; + void* rp; + void* xp; + u8 refState; +} ConvArr; + +// gives TI(res,elType)==re to write in via rp, and a pointer to x's data in eltype==re representation, from either x, or rp +// TI(x,elType)==el_B needs special handling based on result.refState: +// 0: elements aren't reference-counted (is so iif TI(x,elType)!=el_B) +// 1: xp==rp, elements not desired to be copied from x must be decremented +// 2: result is a fresh array, so elements desired to be copied from x must be incremented +ConvArr toEltypeArrX(B x, u8 re); // doesn't consume; x must stay alive for xp to remain valid #define DIRECTARR_COPY(R, RE, X) \ u8 R##_elt = RE; \