From 801472d6d49bc8c1d316507a182f6fcc653ce16b Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Wed, 9 Nov 2022 16:37:33 -0500 Subject: [PATCH 1/9] Implement bit_cpy versions of the Group methods that use memcpy --- src/builtins/group.c | 59 ++++++++++++++++++++++++++++---------------- src/builtins/slash.c | 2 -- src/utils/mut.h | 2 ++ 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index a18f8b3a..2fb1b223 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -2,6 +2,7 @@ #include "../utils/talloc.h" #include "../utils/calls.h" #include "../builtins.h" +#include "../utils/mut.h" extern B ud_c1(B, B); extern B ne_c2(B, B, B); @@ -9,8 +10,6 @@ extern B slash_c1(B, B); extern B slash_c2(B, B, B); extern B select_c2(B, B, B); extern B take_c2(B, B, B); -extern B drop_c2(B, B, B); -extern B join_c2(B, B, B); static Arr* arr_shChangeLen(Arr* a, ur r, usz* xsh, usz len) { assert(r > 1); @@ -27,6 +26,11 @@ static void allocGroups(B* rp, usz ria, B z, u8 xt, ur xr, usz* xsh, i32* len, u if (xr==1) for (usz j = 0; j < ria; j++) { usz l=len[j]; if (!l) rp[j] = inc(z); else m_tyarrv(rp+j, width, l, xt); } else for (usz j = 0; j < ria; j++) { usz l=len[j]; rp[j] = !l ? inc(z) : m_shChangeLen(xt, xr, xsh, l, width, csz); } } +static Arr* m_bitarr_nop(usz ia) { return m_arr(BITARR_SZ(ia), t_bitarr, ia); } +static void allocBitGroups(B* rp, usz ria, B z, ur xr, usz* xsh, i32* len, usz width) { + if (xr==1) for (usz j = 0; j < ria; j++) { usz l=len[j]; rp[j] = !l ? inc(z) : taga(arr_shVec(m_bitarr_nop(l))); } + else for (usz j = 0; j < ria; j++) { usz l=len[j]; rp[j] = !l ? inc(z) : taga(arr_shChangeLen(m_bitarr_nop(l*width), xr, xsh, l)); } +} extern B rt_group; B group_c2(B t, B w, B x) { @@ -93,7 +97,7 @@ B group_c2(B t, B w, B x) { if (bits && xl>=3) { bits=0; width>>=3; } if ((csz & (csz-1)) || xl>7) xl = 7; } - if (xia>64 && notB && !bits && change<(xia*width)/32) { + if (xia>64 && notB && change<(xia*width)/32) { #define C1(F,X ) F##_c1(m_f64(0),X ) #define C2(F,X,W) F##_c2(m_f64(0),X,W) @@ -121,14 +125,22 @@ B group_c2(B t, B w, B x) { void* xp = tyany_ptr(x); - allocGroups(rp, ria, z, xt, xr, xsh, len, width, csz); - for (u64 i=0, k=i0*width; i32 && neg>xia/4+xia/8) { @@ -144,20 +156,25 @@ B group_c2(B t, B w, B x) { for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check u8 xk = xl - 3; - if (notB && !bits && sort) { + if (notB && sort) { void* xp = tyany_ptr(x); u64 i=neg*width; - #define GROUP_SORT(ALLOC) \ - for (usz j=0; j #define mut_copyG(N, ms, x, xs, l) N##_mutfns.m_copyG(N##_mutarr, ms, x, xs, l) +// Companion to bit_cpy when uniform syntax is wanted +#define MEM_CPY(R,RI,X,XI,L) memcpy((u8*)(R)+(RI), (u8*)(X)+(XI), (L)) static void bit_cpy(u64* r, usz rs, u64* x, usz xs, usz l) { u64 re = rs+(u64)l; From 6eb504118eecc94492316180ba6854ceecdc6f25 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Wed, 9 Nov 2022 17:51:25 -0500 Subject: [PATCH 2/9] Split out optimized Group cases and add comments --- src/builtins/group.c | 380 +++++++++++++++++++++++-------------------- 1 file changed, 205 insertions(+), 175 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index 2fb1b223..7c951cb0 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -1,3 +1,22 @@ +// Group and Group Indices (βŠ”) + +// Group Indices: calls π•©βŠ”β†•π•© for rank-1 flat 𝕩, otherwise self-hosted + +// Group: native code for rank-1 𝕨 only, optimizations for integers +// SHOULD squeeze 𝕨 +// SHOULD handle boolean 𝕨 with replicate +// COULD handle small-range 𝕨 with equals-replicate +// All statistics computed in the initial pass that finds βŒˆΒ΄π•¨ +// If +Β΄Β»βŠΈβ‰ π•¨ is small, process in chunks as a separate case +// If +´𝕨<Β―1 is large, filter out Β―1s. +// COULD recompute statistics, may have enabled chunked or sorted code +// If ∧´1β†“Β»βŠΈ<𝕨, that is, βˆ§βŠΈβ‰‘π•¨, each result array is a slice of 𝕩 +// COULD use slice types; seems dangerous--when will they be freed? +// Remaining cases copy cells from 𝕩 individually +// CPU-sized cells handled quickly +// SHOULD use bit ops for 1-bit cells +// SHOULD use memcpy and bit_cpy for other sizes + #include "../core.h" #include "../utils/talloc.h" #include "../utils/calls.h" @@ -32,6 +51,191 @@ static void allocBitGroups(B* rp, usz ria, B z, ur xr, usz* xsh, i32* len, usz w else for (usz j = 0; j < ria; j++) { usz l=len[j]; rp[j] = !l ? inc(z) : taga(arr_shChangeLen(m_bitarr_nop(l*width), xr, xsh, l)); } } +// Integer list w +static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { + if (we==el_bit) w = taga(cpyI8Arr(w)); + i64 ria = 0; + bool bad = false, sort = true; + usz neg = 0, change = 0; + void *wp0 = tyany_ptr(w); + #define CASE(T) case el_##T: { \ + T max = -1, prev = -1; \ + for (usz i = 0; i < xia; i++) { \ + T n = ((T*)wp0)[i]; \ + if (n>max) max = n; \ + bad |= n < -1; \ + neg += n == -1; \ + sort &= prev <= n; \ + change += prev != n; \ + prev = n; \ + } \ + if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \ + i64 m=(i64)max+1; if (m>ria) ria=m; \ + break; } + switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) } + #undef CASE + if (bad) thrM("βŠ”: 𝕨 can't contain elements less than Β―1"); + if (ria > (i64)(USZ_MAX)) thrOOM(); + + Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); + B* rp = fillarr_ptr(r); + for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors + B xf = getFillQ(x); + + Arr* rf = m_fillarrp(0); if (xr==1) arr_shVec(rf); else arr_shChangeLen(rf, xr, xsh, 0); + fillarr_setFill(rf, m_f64(0)); + B z = taga(rf); + fillarr_setFill(r, z); + + // Both cases needed to make sure wia>0 for ip[wia-1] below + if (ria==0) goto setfill_dec_ret; + if (neg==xia) { + for (usz i = 0; i < ria; i++) rp[i] = inc(z); + goto setfill_dec_ret; + } + TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1; + + bool notB = TI(x,elType) != el_B; + u8 xt = arrNewType(TY(x)); + u8 xl = arrTypeBitsLog(TY(x)); + bool bits = xl == 0; + u64 width = bits ? 1 : 1<<(xl-3); // cell width in bits if bits==1, bytes otherwise + usz csz = 1; + if (RARE(xr>1)) { + width *= csz = arr_csz(x); + xl += CTZ(csz); + if (bits && xl>=3) { bits=0; width>>=3; } + if ((csz & (csz-1)) || xl>7) xl = 7; + } + + // Few changes in 𝕨: move in chunks + if (xia>64 && notB && change<(xia*width)/32) { + #define C1(F,X ) F##_c1(m_f64(0),X ) + #define C2(F,X,W) F##_c2(m_f64(0),X,W) + + u64* mp; B m = m_bitarrv(&mp, xia); + u8* wp0 = tyany_ptr(w); + we = TI(w,elType); + CMP_AA_IMM(ne, we, mp, wp0-elWidth(we), wp0, xia); + bitp_set(mp, 0, -1!=o2fG(IGetU(w,0))); + + B ind = C1(slash, m); + w = C2(select, inc(ind), w); + #undef C1 + #undef C2 + if (TI(ind,elType)!=el_i32) ind = taga(cpyI32Arr(ind)); + if (TI(w ,elType)!=el_i32) w = taga(cpyI32Arr(w )); + wia = IA(ind); + + i32* ip = i32any_ptr(ind); + i32* wp = i32any_ptr(w); + usz i0 = ip[0]; + for (usz i=0; i32 && neg>xia/4+xia/8) { + if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); + B m = ne_c2(m_f64(0), m_f64(-1), inc(w)); + w = slash_c2(m_f64(0), inc(m), w); + x = slash_c2(m_f64(0), m, x); xia = IA(x); + neg = 0; + } + if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w)); + i32* wp = i32any_ptr(w); + for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; + for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check + + u8 xk = xl - 3; + if (notB && sort) { // Sorted 𝕨, that is, partition 𝕩 + void* xp = tyany_ptr(x); + u64 i=neg*width; + #define GROUP_SORT(CPY, ALLOC) \ + for (usz j=0; j=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break; + case 1: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break; + case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; + case 3: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u64*)tyarr_ptr(rp[n]))[pos[n]++] = ((u64*)xp)[i]; } break; + } + } else { // Generic case + for (usz i = 0; i < ria; i++) { + usz l = len[i]; + Arr* c = m_fillarrp(l*csz); + c->ia = 0; + fillarr_setFill(c, inc(xf)); + if (xr==1) arr_shVec(c); else arr_shChangeLen(c, xr, xsh, l); + rp[i] = taga(c); + } + SLOW2("π•¨βŠ”π•©", w, x); + SGet(x) + if (csz == 1) { + for (usz i = 0; i < xia; i++) { + i32 n = wp[i]; + if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); + } + } else { + for (usz i = 0; i < xia; i++) { + i32 n = wp[i]; + if (n<0) continue; + usz p = (pos[n]++)*csz; + B* rnp = fillarr_ptr(a(rp[n])) + p; + for (usz j = 0; j < csz; j++) rnp[j] = Get(x, i*csz + j); + } + } + for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]*csz; + } + + done: + TFREE(pos); + setfill_dec_ret: + fillarr_setFill(rf, xf); + decG(w); decG(x); + return taga(r); +} + extern B rt_group; B group_c2(B t, B w, B x) { if (!isArr(x)) thrM("βŠ”: 𝕩 must be an array"); @@ -43,181 +247,7 @@ B group_c2(B t, B w, B x) { if (wia-xia > 1) thrF("βŠ”: ≠𝕨 must be either ≠𝕩 or one bigger (%s≑≠𝕨, %s≑≠𝕩)", wia, xia); u8 we = TI(w,elType); if (elInt(we)) { - if (we==el_bit) w = taga(cpyI8Arr(w)); - i64 ria = 0; - bool bad = false, sort = true; - usz neg = 0, change = 0; - void *wp0 = tyany_ptr(w); - #define CASE(T) case el_##T: { \ - T max = -1, prev = -1; \ - for (usz i = 0; i < xia; i++) { \ - T n = ((T*)wp0)[i]; \ - if (n>max) max = n; \ - bad |= n < -1; \ - neg += n == -1; \ - sort &= prev <= n; \ - change += prev != n; \ - prev = n; \ - } \ - if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \ - i64 m=(i64)max+1; if (m>ria) ria=m; \ - break; } - switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) } - #undef CASE - if (bad) thrM("βŠ”: 𝕨 can't contain elements less than Β―1"); - if (ria > (i64)(USZ_MAX)) thrOOM(); - - Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); - B* rp = fillarr_ptr(r); - for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors - B xf = getFillQ(x); - - Arr* rf = m_fillarrp(0); if (xr==1) arr_shVec(rf); else arr_shChangeLen(rf, xr, xsh, 0); - fillarr_setFill(rf, m_f64(0)); - B z = taga(rf); - fillarr_setFill(r, z); - - // Both cases needed to make sure wia>0 for ip[wia-1] below - if (ria==0) goto setfill_dec_ret; - if (neg==xia) { - for (usz i = 0; i < ria; i++) rp[i] = inc(z); - goto setfill_dec_ret; - } - TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1; - - bool notB = TI(x,elType) != el_B; - u8 xt = arrNewType(TY(x)); - u8 xl = arrTypeBitsLog(TY(x)); - bool bits = xl == 0; - u64 width = bits ? 1 : 1<<(xl-3); // cell width in bits if bits==1, bytes otherwise - usz csz = 1; - if (RARE(xr>1)) { - width *= csz = arr_csz(x); - xl += CTZ(csz); - if (bits && xl>=3) { bits=0; width>>=3; } - if ((csz & (csz-1)) || xl>7) xl = 7; - } - if (xia>64 && notB && change<(xia*width)/32) { - #define C1(F,X ) F##_c1(m_f64(0),X ) - #define C2(F,X,W) F##_c2(m_f64(0),X,W) - - u64* mp; B m = m_bitarrv(&mp, xia); - u8* wp0 = tyany_ptr(w); - we = TI(w,elType); - CMP_AA_IMM(ne, we, mp, wp0-elWidth(we), wp0, xia); - bitp_set(mp, 0, -1!=o2fG(IGetU(w,0))); - - B ind = C1(slash, m); - w = C2(select, inc(ind), w); - #undef C1 - #undef C2 - if (TI(ind,elType)!=el_i32) ind = taga(cpyI32Arr(ind)); - if (TI(w ,elType)!=el_i32) w = taga(cpyI32Arr(w )); - wia = IA(ind); - - i32* ip = i32any_ptr(ind); - i32* wp = i32any_ptr(w); - usz i0 = ip[0]; - for (usz i=0; i32 && neg>xia/4+xia/8) { - if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); - B m = ne_c2(m_f64(0), m_f64(-1), inc(w)); - w = slash_c2(m_f64(0), inc(m), w); - x = slash_c2(m_f64(0), m, x); xia = IA(x); - neg = 0; - } - if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w)); - i32* wp = i32any_ptr(w); - for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; - for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check - - u8 xk = xl - 3; - if (notB && sort) { - void* xp = tyany_ptr(x); - u64 i=neg*width; - #define GROUP_SORT(CPY, ALLOC) \ - for (usz j=0; j=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break; - case 1: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break; - case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; - case 3: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u64*)tyarr_ptr(rp[n]))[pos[n]++] = ((u64*)xp)[i]; } break; - } - } else { - for (usz i = 0; i < ria; i++) { - usz l = len[i]; - Arr* c = m_fillarrp(l*csz); - c->ia = 0; - fillarr_setFill(c, inc(xf)); - if (xr==1) arr_shVec(c); else arr_shChangeLen(c, xr, xsh, l); - rp[i] = taga(c); - } - SLOW2("π•¨βŠ”π•©", w, x); - SGet(x) - if (csz == 1) { - for (usz i = 0; i < xia; i++) { - i32 n = wp[i]; - if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); - } - } else { - for (usz i = 0; i < xia; i++) { - i32 n = wp[i]; - if (n<0) continue; - usz p = (pos[n]++)*csz; - B* rnp = fillarr_ptr(a(rp[n])) + p; - for (usz j = 0; j < csz; j++) rnp[j] = Get(x, i*csz + j); - } - } - for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]*csz; - } - } - TFREE(pos); - setfill_dec_ret: - fillarr_setFill(rf, xf); - decG(w); decG(x); - return taga(r); + return group_simple(w, x, xr, wia, xia, xsh, we); } else if (xr==1) { SLOW2("π•¨βŠ”π•©", w, x); SGetU(w) From a3da018055c33aecdb2d46a5294e353d749dd69d Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Wed, 9 Nov 2022 19:56:52 -0500 Subject: [PATCH 3/9] Group code for 1-bit cells --- src/builtins/group.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index 7c951cb0..30565664 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -13,8 +13,8 @@ // If ∧´1β†“Β»βŠΈ<𝕨, that is, βˆ§βŠΈβ‰‘π•¨, each result array is a slice of 𝕩 // COULD use slice types; seems dangerous--when will they be freed? // Remaining cases copy cells from 𝕩 individually -// CPU-sized cells handled quickly -// SHOULD use bit ops for 1-bit cells +// Converts 𝕨 to i32, COULD handle smaller types +// CPU-sized cells handled quickly, 1-bit with bitp_get/set // SHOULD use memcpy and bit_cpy for other sizes #include "../core.h" @@ -158,7 +158,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { } // Many Β―1s: filter out, then continue - if (xia>32 && neg>xia/4+xia/8) { + if (xia>32 && neg>(bits?0:xia/4)+xia/8) { if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); B m = ne_c2(m_f64(0), m_f64(-1), inc(w)); w = slash_c2(m_f64(0), inc(m), w); @@ -200,6 +200,13 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; case 3: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u64*)tyarr_ptr(rp[n]))[pos[n]++] = ((u64*)xp)[i]; } break; } + } else if (xl == 0) { // 1-bit cells + u64* xp = bitarr_ptr(x); + allocBitGroups(rp, ria, z, xr, xsh, len, width); + for (usz i = 0; i < xia; i++) { + bool b = bitp_get(xp,i); i32 n = wp[i]; + if (n>=0) bitp_set(bitarr_ptr(rp[n]), pos[n]++, b); + } } else { // Generic case for (usz i = 0; i < ria; i++) { usz l = len[i]; From d2cdae49626dec8bb732926d4a3d07c95ef60401 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Thu, 10 Nov 2022 15:47:43 -0500 Subject: [PATCH 4/9] =?UTF-8?q?Fast=20case=20for=20bool=E2=8A=94?= =?UTF-8?q?=F0=9D=95=A9=20using=20compress?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/builtins/group.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index 30565664..420b6a8f 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -4,9 +4,9 @@ // Group: native code for rank-1 𝕨 only, optimizations for integers // SHOULD squeeze 𝕨 -// SHOULD handle boolean 𝕨 with replicate -// COULD handle small-range 𝕨 with equals-replicate // All statistics computed in the initial pass that finds βŒˆΒ΄π•¨ +// If 𝕨 is boolean, compute from π•¨Β¬βŠΈ/𝕩 and 𝕨/𝕩 +// COULD handle small-range 𝕨 with equals-replicate // If +Β΄Β»βŠΈβ‰ π•¨ is small, process in chunks as a separate case // If +´𝕨<Β―1 is large, filter out Β―1s. // COULD recompute statistics, may have enabled chunked or sorted code @@ -16,6 +16,7 @@ // Converts 𝕨 to i32, COULD handle smaller types // CPU-sized cells handled quickly, 1-bit with bitp_get/set // SHOULD use memcpy and bit_cpy for other sizes +// TRIED separating neg>0 and neg==0 loops, no effect #include "../core.h" #include "../utils/talloc.h" @@ -24,6 +25,7 @@ #include "../utils/mut.h" extern B ud_c1(B, B); +extern B not_c1(B, B); extern B ne_c2(B, B, B); extern B slash_c1(B, B); extern B slash_c2(B, B, B); @@ -53,7 +55,6 @@ static void allocBitGroups(B* rp, usz ria, B z, ur xr, usz* xsh, i32* len, usz w // Integer list w static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { - if (we==el_bit) w = taga(cpyI8Arr(w)); i64 ria = 0; bool bad = false, sort = true; usz neg = 0, change = 0; @@ -72,7 +73,11 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \ i64 m=(i64)max+1; if (m>ria) ria=m; \ break; } - switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) } + switch (we) { default:UD; + CASE(i8) CASE(i16) CASE(i32) + // Boolean w is special-cased before we would check sort or change + case el_bit: ria = xia? 1+bit_has(wp0,xia,1) : wia? bitp_get(wp0,0) : 0; break; + } #undef CASE if (bad) thrM("βŠ”: 𝕨 can't contain elements less than Β―1"); if (ria > (i64)(USZ_MAX)) thrOOM(); @@ -87,8 +92,19 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { B z = taga(rf); fillarr_setFill(r, z); - // Both cases needed to make sure wia>0 for ip[wia-1] below - if (ria==0) goto setfill_dec_ret; + if (ria <= 1) { + if (ria == 0) goto setfill_dec_ret; // Needed so wia>0 + if (neg == 0) { rp[0]=inc(x); goto setfill_dec_ret; } + } + if (we==el_bit) { + assert(ria == 2); + fillarr_setFill(rf, xf); + if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); + rp[1] = slash_c2(m_f64(0), inc(w), inc(x)); + rp[0] = slash_c2(m_f64(0), not_c1(m_f64(0), w), x); + return taga(r); + } + // Needed to make sure wia>0 for ip[wia-1] below if (neg==xia) { for (usz i = 0; i < ria; i++) rp[i] = inc(z); goto setfill_dec_ret; From eb880d71357a6aff05eba78f1906ee12c8d41921 Mon Sep 17 00:00:00 2001 From: dzaima Date: Sat, 12 Nov 2022 12:56:12 +0200 Subject: [PATCH 5/9] set result fill fill immediately instead of delaying to before return --- src/builtins/group.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index 420b6a8f..d1ca59ff 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -85,20 +85,21 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); B* rp = fillarr_ptr(r); for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors - B xf = getFillQ(x); - Arr* rf = m_fillarrp(0); if (xr==1) arr_shVec(rf); else arr_shChangeLen(rf, xr, xsh, 0); - fillarr_setFill(rf, m_f64(0)); + B xf = getFillQ(x); + Arr* rf = m_fillarrp(0); fillarr_setFill(rf, xf); + if (xr==1) arr_shVec(rf); else arr_shChangeLen(rf, xr, xsh, 0); + B z = taga(rf); fillarr_setFill(r, z); if (ria <= 1) { - if (ria == 0) goto setfill_dec_ret; // Needed so wia>0 - if (neg == 0) { rp[0]=inc(x); goto setfill_dec_ret; } + if (ria == 0) goto dec_ret; // Needed so wia>0 + if (neg == 0) { rp[0]=inc(x); goto dec_ret; } + // else, Β―1β€Ώn βŠ” ⟨v⟩ } if (we==el_bit) { assert(ria == 2); - fillarr_setFill(rf, xf); if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); rp[1] = slash_c2(m_f64(0), inc(w), inc(x)); rp[0] = slash_c2(m_f64(0), not_c1(m_f64(0), w), x); @@ -107,7 +108,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { // Needed to make sure wia>0 for ip[wia-1] below if (neg==xia) { for (usz i = 0; i < ria; i++) rp[i] = inc(z); - goto setfill_dec_ret; + goto dec_ret; } TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1; @@ -253,8 +254,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { done: TFREE(pos); - setfill_dec_ret: - fillarr_setFill(rf, xf); + dec_ret: decG(w); decG(x); return taga(r); } From 1241da4d7401884a2e723d7048fd90abc8b914ae Mon Sep 17 00:00:00 2001 From: dzaima Date: Sat, 12 Nov 2022 13:40:43 +0200 Subject: [PATCH 6/9] fix group of array with empty cells --- src/builtins/group.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index d1ca59ff..a8455934 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -122,7 +122,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { width *= csz = arr_csz(x); xl += CTZ(csz); if (bits && xl>=3) { bits=0; width>>=3; } - if ((csz & (csz-1)) || xl>7) xl = 7; + if ((csz & (csz-1)) || !csz || xl>7) xl = 7; } // Few changes in 𝕨: move in chunks From a1e12106ce81eafacd5fca74bb46dd90e0277993 Mon Sep 17 00:00:00 2001 From: dzaima Date: Sat, 12 Nov 2022 13:45:52 +0200 Subject: [PATCH 7/9] use FILL_TO for more compact edge-case handling --- src/builtins/group.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index a8455934..aaec198f 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -107,7 +107,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { } // Needed to make sure wia>0 for ip[wia-1] below if (neg==xia) { - for (usz i = 0; i < ria; i++) rp[i] = inc(z); + FILL_TO(rp, el_B, 0, z, ria); goto dec_ret; } TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1; From beb997ccb91c2bd5ea67ded706b8cb6bc1e605d0 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Sat, 12 Nov 2022 07:25:41 -0500 Subject: [PATCH 8/9] =?UTF-8?q?Avoid=20data=20movement=20for=20empty=20cel?= =?UTF-8?q?ls=20in=20Group=20=F0=9D=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/builtins/group.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index aaec198f..bf562b43 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -96,7 +96,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { if (ria <= 1) { if (ria == 0) goto dec_ret; // Needed so wia>0 if (neg == 0) { rp[0]=inc(x); goto dec_ret; } - // else, Β―1β€Ώn βŠ” ⟨v⟩ + // else, 𝕨 is a mix of 0 and Β―1 (and maybe trailing 1) } if (we==el_bit) { assert(ria == 2); @@ -120,9 +120,10 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { usz csz = 1; if (RARE(xr>1)) { width *= csz = arr_csz(x); - xl += CTZ(csz); + usz cs = csz | (csz==0); + xl += CTZ(cs); if (bits && xl>=3) { bits=0; width>>=3; } - if ((csz & (csz-1)) || !csz || xl>7) xl = 7; + if ((cs & (cs-1)) || xl>7) xl = 7; } // Few changes in 𝕨: move in chunks @@ -162,7 +163,9 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { CPY(tyarr_ptr(rp[n]), pos[n], xp, k0, l); \ pos[n] += l; \ } - if (!bits) { + if (csz==0) { + allocBitGroups(rp, ria, z, xr, xsh, len, width); + } if (!bits) { allocGroups(rp, ria, z, xt, xr, xsh, len, width, csz); GROUP_CHUNKED(MEM_CPY) } else { @@ -188,7 +191,9 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check u8 xk = xl - 3; - if (notB && sort) { // Sorted 𝕨, that is, partition 𝕩 + if (notB && csz==0) { // Empty cells, no movement needed + allocBitGroups(rp, ria, z, xr, xsh, len, width); + } else if (notB && sort) { // Sorted 𝕨, that is, partition 𝕩 void* xp = tyany_ptr(x); u64 i=neg*width; #define GROUP_SORT(CPY, ALLOC) \ @@ -233,6 +238,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { if (xr==1) arr_shVec(c); else arr_shChangeLen(c, xr, xsh, l); rp[i] = taga(c); } + if (csz==0) goto done; SLOW2("π•¨βŠ”π•©", w, x); SGet(x) if (csz == 1) { From a7daeea6d9f3e59ad71779b2b4cb07357a379409 Mon Sep 17 00:00:00 2001 From: dzaima Date: Sat, 12 Nov 2022 19:20:34 +0200 Subject: [PATCH 9/9] =?UTF-8?q?fix=20(500=E2=A5=8A=C2=AF1=E2=80=BF5)=20?= =?UTF-8?q?=E2=8A=94=20500=E2=80=BF1=E2=80=BF3=E2=A5=8A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/builtins/group.c | 76 ++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/builtins/group.c b/src/builtins/group.c index bf562b43..6d945136 100644 --- a/src/builtins/group.c +++ b/src/builtins/group.c @@ -54,29 +54,29 @@ static void allocBitGroups(B* rp, usz ria, B z, ur xr, usz* xsh, i32* len, usz w } // Integer list w -static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { +static B group_simple(B w, B x, ur xr, usz wia, usz xn, usz* xsh, u8 we) { i64 ria = 0; bool bad = false, sort = true; usz neg = 0, change = 0; void *wp0 = tyany_ptr(w); #define CASE(T) case el_##T: { \ - T max = -1, prev = -1; \ - for (usz i = 0; i < xia; i++) { \ - T n = ((T*)wp0)[i]; \ - if (n>max) max = n; \ - bad |= n < -1; \ - neg += n == -1; \ - sort &= prev <= n; \ - change += prev != n; \ - prev = n; \ - } \ - if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \ - i64 m=(i64)max+1; if (m>ria) ria=m; \ + T max = -1, prev = -1; \ + for (usz i = 0; i < xn; i++) { \ + T n = ((T*)wp0)[i]; \ + if (n>max) max = n; \ + bad |= n < -1; \ + neg += n == -1; \ + sort &= prev <= n; \ + change += prev != n; \ + prev = n; \ + } \ + if (wia>xn) { ria=((T*)wp0)[xn]; bad|=ria<-1; } \ + i64 m=(i64)max+1; if (m>ria) ria=m; \ break; } switch (we) { default:UD; CASE(i8) CASE(i16) CASE(i32) // Boolean w is special-cased before we would check sort or change - case el_bit: ria = xia? 1+bit_has(wp0,xia,1) : wia? bitp_get(wp0,0) : 0; break; + case el_bit: ria = xn? 1+bit_has(wp0,xn,1) : wia? bitp_get(wp0,0) : 0; break; } #undef CASE if (bad) thrM("βŠ”: 𝕨 can't contain elements less than Β―1"); @@ -100,13 +100,13 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { } if (we==el_bit) { assert(ria == 2); - if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); + if (wia>xn) w = take_c2(m_f64(0), m_f64(xn), w); rp[1] = slash_c2(m_f64(0), inc(w), inc(x)); rp[0] = slash_c2(m_f64(0), not_c1(m_f64(0), w), x); return taga(r); } // Needed to make sure wia>0 for ip[wia-1] below - if (neg==xia) { + if (neg==xn) { FILL_TO(rp, el_B, 0, z, ria); goto dec_ret; } @@ -127,14 +127,14 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { } // Few changes in 𝕨: move in chunks - if (xia>64 && notB && change<(xia*width)/32) { + if (xn>64 && notB && change<(xn*width)/32) { #define C1(F,X ) F##_c1(m_f64(0),X ) #define C2(F,X,W) F##_c2(m_f64(0),X,W) - u64* mp; B m = m_bitarrv(&mp, xia); + u64* mp; B m = m_bitarrv(&mp, xn); u8* wp0 = tyany_ptr(w); we = TI(w,elType); - CMP_AA_IMM(ne, we, mp, wp0-elWidth(we), wp0, xia); + CMP_AA_IMM(ne, we, mp, wp0-elWidth(we), wp0, xn); bitp_set(mp, 0, -1!=o2fG(IGetU(w,0))); B ind = C1(slash, m); @@ -149,7 +149,7 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { i32* wp = i32any_ptr(w); usz i0 = ip[0]; for (usz i=0; i32 && neg>(bits?0:xia/4)+xia/8) { - if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w); + if (xn>32 && neg>(bits?0:xn/4)+xn/8) { + if (wia>xn) w = take_c2(m_f64(0), m_f64(xn), w); B m = ne_c2(m_f64(0), m_f64(-1), inc(w)); w = slash_c2(m_f64(0), inc(m), w); - x = slash_c2(m_f64(0), m, x); xia = IA(x); + x = slash_c2(m_f64(0), m, x); xn = *SH(x); neg = 0; } if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w)); i32* wp = i32any_ptr(w); for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; - for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check + for (usz i = 0; i < xn; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check u8 xk = xl - 3; if (notB && csz==0) { // Empty cells, no movement needed @@ -217,15 +217,15 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { void* xp = tyany_ptr(x); allocGroups(rp, ria, z, xt, xr, xsh, len, width, csz); switch(xk) { default: UD; - case 0: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break; - case 1: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break; - case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; - case 3: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u64*)tyarr_ptr(rp[n]))[pos[n]++] = ((u64*)xp)[i]; } break; + case 0: for (usz i = 0; i < xn; i++) { i32 n = wp[i]; if (n>=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break; + case 1: for (usz i = 0; i < xn; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break; + case 2: for (usz i = 0; i < xn; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break; + case 3: for (usz i = 0; i < xn; i++) { i32 n = wp[i]; if (n>=0) ((u64*)tyarr_ptr(rp[n]))[pos[n]++] = ((u64*)xp)[i]; } break; } } else if (xl == 0) { // 1-bit cells u64* xp = bitarr_ptr(x); allocBitGroups(rp, ria, z, xr, xsh, len, width); - for (usz i = 0; i < xia; i++) { + for (usz i = 0; i < xn; i++) { bool b = bitp_get(xp,i); i32 n = wp[i]; if (n>=0) bitp_set(bitarr_ptr(rp[n]), pos[n]++, b); } @@ -242,12 +242,12 @@ static B group_simple(B w, B x, ur xr, usz wia, usz xia, usz* xsh, u8 we) { SLOW2("π•¨βŠ”π•©", w, x); SGet(x) if (csz == 1) { - for (usz i = 0; i < xia; i++) { + for (usz i = 0; i < xn; i++) { i32 n = wp[i]; if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); } } else { - for (usz i = 0; i < xia; i++) { + for (usz i = 0; i < xn; i++) { i32 n = wp[i]; if (n<0) continue; usz p = (pos[n]++)*csz; @@ -272,21 +272,21 @@ B group_c2(B t, B w, B x) { if (isArr(w) && RNK(w)==1 && xr>=1 && depth(w)==1) { usz wia = IA(w); usz* xsh = SH(x); - usz xia = *xsh; - if (wia-xia > 1) thrF("βŠ”: ≠𝕨 must be either ≠𝕩 or one bigger (%s≑≠𝕨, %s≑≠𝕩)", wia, xia); + usz xn = *xsh; + if (wia-xn > 1) thrF("βŠ”: ≠𝕨 must be either ≠𝕩 or one bigger (%s≑≠𝕨, %s≑≠𝕩)", wia, xn); u8 we = TI(w,elType); if (elInt(we)) { - return group_simple(w, x, xr, wia, xia, xsh, we); + return group_simple(w, x, xr, wia, xn, xsh, we); } else if (xr==1) { SLOW2("π•¨βŠ”π•©", w, x); SGetU(w) - i64 ria = wia==xia? 0 : o2i64(GetU(w, xia)); + i64 ria = wia==xn? 0 : o2i64(GetU(w, xn)); if (ria<0) { if (ria<-1) thrM("βŠ”: 𝕨 can't contain elements less than Β―1"); ria = 0; } ria--; - for (usz i = 0; i < xia; i++) { + for (usz i = 0; i < xn; i++) { B cw = GetU(w, i); if (!q_i64(cw)) goto base; i64 c = o2i64G(cw); @@ -298,7 +298,7 @@ B group_c2(B t, B w, B x) { TALLOC(i32, lenO, ria+1); i32* len = lenO+1; TALLOC(i32, pos, ria); for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0; - for (usz i = 0; i < xia; i++) len[o2i64G(GetU(w, i))]++; + for (usz i = 0; i < xn; i++) len[o2i64G(GetU(w, i))]++; Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0)); B* rp = fillarr_ptr(r); @@ -316,7 +316,7 @@ B group_c2(B t, B w, B x) { fillarr_setFill(rf, xf); fillarr_setFill(r, taga(rf)); SGet(x) - for (usz i = 0; i < xia; i++) { + for (usz i = 0; i < xn; i++) { i64 n = o2i64G(GetU(w, i)); if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i); }