Merge pull request #82 from mlochbaum/search
1-byte bit table for search
This commit is contained in:
commit
0442dc010d
@ -609,7 +609,7 @@ cachedBin‿linkerCache ← {
|
|||||||
"xa."‿"src/builtins/arithd.c"‿"dyarith", "xa."‿"src/builtins/cmp.c"‿"cmp",
|
"xa."‿"src/builtins/arithd.c"‿"dyarith", "xa."‿"src/builtins/cmp.c"‿"cmp",
|
||||||
"xa."‿"src/builtins/squeeze.c"‿"squeeze", "xa."‿"src/utils/mut.c"‿"copy",
|
"xa."‿"src/builtins/squeeze.c"‿"squeeze", "xa."‿"src/utils/mut.c"‿"copy",
|
||||||
"xa."‿"src/utils/bits.c"‿"bits", "xag"‿"src/builtins/transpose.c"‿"transpose",
|
"xa."‿"src/utils/bits.c"‿"bits", "xag"‿"src/builtins/transpose.c"‿"transpose",
|
||||||
"xa."‿"src/builtins/search.c"‿"search", "xa."‿"src/builtins/fold.c"‿"fold",
|
"xag"‿"src/builtins/search.c"‿"search", "xa."‿"src/builtins/fold.c"‿"fold",
|
||||||
|
|
||||||
"2.."‿"src/builtins/select.c"‿"select", "2.."‿"src/builtins/scan.c"‿"scan",
|
"2.."‿"src/builtins/select.c"‿"select", "2.."‿"src/builtins/scan.c"‿"scan",
|
||||||
"2.."‿"src/builtins/slash.c"‿"constrep", "2.."‿"src/builtins/scan.c"‿"neq",
|
"2.."‿"src/builtins/slash.c"‿"constrep", "2.."‿"src/builtins/scan.c"‿"neq",
|
||||||
|
|||||||
@ -23,6 +23,11 @@
|
|||||||
#include "../utils/hash.h"
|
#include "../utils/hash.h"
|
||||||
#include "../utils/talloc.h"
|
#include "../utils/talloc.h"
|
||||||
|
|
||||||
|
#if SINGELI_SIMD
|
||||||
|
#define SINGELI_FILE search
|
||||||
|
#include "../utils/includeSingeli.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define C2i(F, W, X) C2(F, m_i32(W), X)
|
#define C2i(F, W, X) C2(F, m_i32(W), X)
|
||||||
extern B eq_c2(B,B,B);
|
extern B eq_c2(B,B,B);
|
||||||
extern B ne_c2(B,B,B);
|
extern B ne_c2(B,B,B);
|
||||||
@ -131,11 +136,6 @@ static B reduceI32Width(B r, usz count) {
|
|||||||
return count<=I8_MAX? taga(cpyI8Arr(r)) : count<=I16_MAX? taga(cpyI16Arr(r)) : r;
|
return count<=I8_MAX? taga(cpyI8Arr(r)) : count<=I16_MAX? taga(cpyI16Arr(r)) : r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SINGELI_SIMD
|
|
||||||
#define SINGELI_FILE search
|
|
||||||
#include "../utils/includeSingeli.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static NOINLINE usz indexOfOne(B l, B e) {
|
static NOINLINE usz indexOfOne(B l, B e) {
|
||||||
void* lp = tyany_ptr(l);
|
void* lp = tyany_ptr(l);
|
||||||
usz wia = IA(l);
|
usz wia = IA(l);
|
||||||
@ -201,7 +201,10 @@ B indexOf_c2(B t, B w, B x) {
|
|||||||
} else {
|
} else {
|
||||||
u8 we = TI(w,elType); usz wia = IA(w);
|
u8 we = TI(w,elType); usz wia = IA(w);
|
||||||
u8 xe = TI(x,elType); usz xia = IA(x);
|
u8 xe = TI(x,elType); usz xia = IA(x);
|
||||||
if (wia == 0) { B r=taga(arr_shCopy(allZeroes(xia), x)); decG(w); decG(x); return r; }
|
if (wia==0 || xia==0) {
|
||||||
|
B r=taga(arr_shCopy(allZeroes(xia), x));
|
||||||
|
decG(w); decG(x); return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (elNum(we) && elNum(xe)) { tyEls:
|
if (elNum(we) && elNum(xe)) { tyEls:
|
||||||
if (we==el_bit) {
|
if (we==el_bit) {
|
||||||
@ -223,6 +226,18 @@ B indexOf_c2(B t, B w, B x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xia+wia>20 && we<=el_i16 && xe<=el_i16) {
|
if (xia+wia>20 && we<=el_i16 && xe<=el_i16) {
|
||||||
|
#if SINGELI
|
||||||
|
if (wia>256 && we==el_i8 && xe==el_i8) {
|
||||||
|
TALLOC(u8, tab, 256*(1+sizeof(usz))); usz* ind = (usz*)(tab+256);
|
||||||
|
void* fp = tyany_ptr(x);
|
||||||
|
simd_index_tab_u8(tyany_ptr(w), wia, fp, xia, tab, ind);
|
||||||
|
decG(w);
|
||||||
|
i32* rp; B r = m_i32arrc(&rp, x);
|
||||||
|
for (usz i=0; i<xia; i++) rp[i]=ind[((u8*)fp)[i]];
|
||||||
|
TFREE(tab); decG(x);
|
||||||
|
return reduceI32Width(r, wia);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
B r;
|
B r;
|
||||||
TABLE(w, x, i32, wia, i)
|
TABLE(w, x, i32, wia, i)
|
||||||
return reduceI32Width(r, wia);
|
return reduceI32Width(r, wia);
|
||||||
@ -271,7 +286,10 @@ B memberOf_c2(B t, B w, B x) {
|
|||||||
many: {
|
many: {
|
||||||
u8 we = TI(w,elType); usz wia = IA(w);
|
u8 we = TI(w,elType); usz wia = IA(w);
|
||||||
u8 xe = TI(x,elType); usz xia = IA(x);
|
u8 xe = TI(x,elType); usz xia = IA(x);
|
||||||
if (xia == 0) { r=taga(arr_shCopy(allZeroes(wia), w)); decG(w); goto dec_x; }
|
if (wia==0 || xia==0) {
|
||||||
|
r=taga(arr_shCopy(allZeroes(wia), w));
|
||||||
|
decG(w); goto dec_x;
|
||||||
|
}
|
||||||
|
|
||||||
if (elNum(we) && elNum(xe)) { tyEls:
|
if (elNum(we) && elNum(xe)) { tyEls:
|
||||||
#define WEQ(V) C2(eq, incG(w), V)
|
#define WEQ(V) C2(eq, incG(w), V)
|
||||||
@ -283,7 +301,7 @@ B memberOf_c2(B t, B w, B x) {
|
|||||||
decG(w); goto dec_x;
|
decG(w); goto dec_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xia<=(xe==el_i16?8:16) && wia>16) {
|
if (xia<=(xe==el_i8?1:xe==el_i16?4:16) && wia>16) {
|
||||||
SGetU(x);
|
SGetU(x);
|
||||||
r = WEQ(GetU(x,0));
|
r = WEQ(GetU(x,0));
|
||||||
for (usz i=1; i<xia; i++) r = C2(or, r, WEQ(GetU(x,i)));
|
for (usz i=1; i<xia; i++) r = C2(or, r, WEQ(GetU(x,i)));
|
||||||
@ -292,7 +310,15 @@ B memberOf_c2(B t, B w, B x) {
|
|||||||
#undef WEQ
|
#undef WEQ
|
||||||
|
|
||||||
if (xia+wia>20 && we<=el_i16 && xe<=el_i16) {
|
if (xia+wia>20 && we<=el_i16 && xe<=el_i16) {
|
||||||
B r;
|
#if SINGELI
|
||||||
|
if (we==el_i8 && xe==el_i8) {
|
||||||
|
TALLOC(u8, tab, 256);
|
||||||
|
u64* rp; r = m_bitarrc(&rp, w);
|
||||||
|
simd_member_u8(tyany_ptr(x), xia, tyany_ptr(w), wia, rp, tab);
|
||||||
|
TFREE(tab); decG(w);
|
||||||
|
goto dec_x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
TABLE(x, w, i8, 0, 1)
|
TABLE(x, w, i8, 0, 1)
|
||||||
return taga(cpyBitArr(r));
|
return taga(cpyBitArr(r));
|
||||||
}
|
}
|
||||||
@ -321,7 +347,7 @@ B count_c2(B t, B w, B x) {
|
|||||||
x = t.n;
|
x = t.n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isArr(x) || IA(x)<=1) return C2(indexOf, w, x);
|
if (!isArr(x) || IA(x)<=1 || IA(w)==0) return C2(indexOf, w, x);
|
||||||
u8 we = TI(w,elType); usz wia = IA(w);
|
u8 we = TI(w,elType); usz wia = IA(w);
|
||||||
u8 xe = TI(x,elType); usz xia = IA(x);
|
u8 xe = TI(x,elType); usz xia = IA(x);
|
||||||
i32* rp; B r = m_i32arrc(&rp, x);
|
i32* rp; B r = m_i32arrc(&rp, x);
|
||||||
|
|||||||
@ -213,6 +213,9 @@ static NOINLINE void memset64(u64* p, u64 v, usz l) { for (usz i=0; i<l; i++) p[
|
|||||||
/*AUXEXTEND*/val -= dif; memset32(val, 0, dif); , \
|
/*AUXEXTEND*/val -= dif; memset32(val, 0, dif); , \
|
||||||
/*AUXMOVE*/u32 v = val[j]; val[j] = 0; val[k] = v;)
|
/*AUXMOVE*/u32 v = val[j]; val[j] = 0; val[k] = v;)
|
||||||
|
|
||||||
|
extern void (*const simd_mark_firsts_u8)(void*,uint64_t,void*,void*);
|
||||||
|
extern u64 (*const simd_deduplicate_u8)(void*,uint64_t,void*,void*);
|
||||||
|
|
||||||
B memberOf_c1(B t, B x) {
|
B memberOf_c1(B t, B x) {
|
||||||
if (isAtm(x) || RNK(x)==0) thrM("∊: Argument cannot have rank 0");
|
if (isAtm(x) || RNK(x)==0) thrM("∊: Argument cannot have rank 0");
|
||||||
u64 n = *SH(x);
|
u64 n = *SH(x);
|
||||||
@ -251,7 +254,17 @@ B memberOf_c1(B t, B x) {
|
|||||||
for (usz i=0; i<n; i++) { u##T j=xp[i]; rp[i]=tab[j]; tab[j]=0; } \
|
for (usz i=0; i<n; i++) { u##T j=xp[i]; rp[i]=tab[j]; tab[j]=0; } \
|
||||||
decG(x); TFREE(tab); \
|
decG(x); TFREE(tab); \
|
||||||
return taga(cpyBitArr(r))
|
return taga(cpyBitArr(r))
|
||||||
if (lw==3) { if (n<8) { BRUTE(8); } else { LOOKUP(8); } }
|
if (lw==3) { if (n<8) { BRUTE(8); } else {
|
||||||
|
#if SINGELI
|
||||||
|
TALLOC(u8, tab, 256);
|
||||||
|
u64* rp; B r = m_bitarrv(&rp, n);
|
||||||
|
simd_mark_firsts_u8(xv, n, rp, tab);
|
||||||
|
TFREE(tab); decG(x);
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
LOOKUP(8);
|
||||||
|
#endif
|
||||||
|
} }
|
||||||
if (lw==4) { if (n<8) { BRUTE(16); } else { LOOKUP(16); } }
|
if (lw==4) { if (n<8) { BRUTE(16); } else { LOOKUP(16); } }
|
||||||
#undef LOOKUP
|
#undef LOOKUP
|
||||||
#define HASHTAB(T, W, RAD, STOP, THRESH) T* xp = (T*)xv; SELFHASHTAB( \
|
#define HASHTAB(T, W, RAD, STOP, THRESH) T* xp = (T*)xv; SELFHASHTAB( \
|
||||||
@ -533,7 +546,8 @@ B find_c1(B t, B x) {
|
|||||||
if (isAtm(x) || RNK(x)==0) thrM("⍷: Argument cannot have rank 0");
|
if (isAtm(x) || RNK(x)==0) thrM("⍷: Argument cannot have rank 0");
|
||||||
usz n = *SH(x);
|
usz n = *SH(x);
|
||||||
if (n<=1) return x;
|
if (n<=1) return x;
|
||||||
if (TI(x,elType)==el_bit && RNK(x)==1) {
|
u8 xe = TI(x,elType);
|
||||||
|
if (xe==el_bit && RNK(x)==1) {
|
||||||
u64* xp = bitarr_ptr(x);
|
u64* xp = bitarr_ptr(x);
|
||||||
u64 x0 = 1 & *xp;
|
u64 x0 = 1 & *xp;
|
||||||
usz i = bit_find(xp, n, !x0); decG(x);
|
usz i = bit_find(xp, n, !x0); decG(x);
|
||||||
@ -541,5 +555,15 @@ B find_c1(B t, B x) {
|
|||||||
rp[0] = 2 ^ -x0;
|
rp[0] = 2 ^ -x0;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
#if SINGELI
|
||||||
|
if (elWidth(xe)==1 && RNK(x)==1 && !FL_HAS(x, fl_asc|fl_dsc)) {
|
||||||
|
TALLOC(u8, tab, 513); u8* res = tab+256;
|
||||||
|
usz ria = simd_deduplicate_u8(tyany_ptr(x), n, res, tab);
|
||||||
|
B r; i8* rp = m_tyarrv(&r, 1, ria, el2t(xe));
|
||||||
|
memcpy(rp, res, ria);
|
||||||
|
TFREE(tab); decG(x);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return C2(slash, C1(memberOf, incG(x)), x);
|
return C2(slash, C1(memberOf, incG(x)), x);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ if (hasarch{'AVX2'}) {
|
|||||||
include './sse'
|
include './sse'
|
||||||
include './avx'
|
include './avx'
|
||||||
include './avx2'
|
include './avx2'
|
||||||
|
} else if (hasarch{'SSSE3'}) {
|
||||||
|
include './sse'
|
||||||
} else if (hasarch{'X86_64'}) {
|
} else if (hasarch{'X86_64'}) {
|
||||||
include './sse2'
|
include './sse2'
|
||||||
} else if (hasarch{'AARCH64'}) {
|
} else if (hasarch{'AARCH64'}) {
|
||||||
@ -10,6 +12,8 @@ if (hasarch{'AVX2'}) {
|
|||||||
}
|
}
|
||||||
include './mask'
|
include './mask'
|
||||||
|
|
||||||
|
def ctzi{x} = promote{u64, ctz{x}} # Count trailing zeros, as index
|
||||||
|
|
||||||
def findFirst{C, M, F, ...v1} = {
|
def findFirst{C, M, F, ...v1} = {
|
||||||
def exit = makelabel{}
|
def exit = makelabel{}
|
||||||
def args = undef{M{...each{{c}=>tupsel{0,c}, v1}}}
|
def args = undef{M{...each{{c}=>tupsel{0,c}, v1}}}
|
||||||
@ -30,7 +34,7 @@ def search{E, x, n:u64, OP} = {
|
|||||||
def VT = [bulk]E
|
def VT = [bulk]E
|
||||||
def end = makeBranch{
|
def end = makeBranch{
|
||||||
tup{u64, ty_u{VT}},
|
tup{u64, ty_u{VT}},
|
||||||
{i,c} => return{i*bulk + promote{u64, ctz{homMask{c}}}}
|
{i,c} => return{i*bulk + ctzi{homMask{c}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
muLoop{bulk, tern{arch_defvw>=256, 1, 2}, n, {is, M} => {
|
muLoop{bulk, tern{arch_defvw>=256, 1, 2}, n, {is, M} => {
|
||||||
@ -75,3 +79,216 @@ export{'simd_search_u32', searchOne{u64, u32}}
|
|||||||
export{'simd_search_f64', searchOne{f64, f64}}
|
export{'simd_search_f64', searchOne{f64, f64}}
|
||||||
export{'simd_search_normalizable', searchNormalizable{}}
|
export{'simd_search_normalizable', searchNormalizable{}}
|
||||||
export{'simd_copy_ordered', copyOrdered{}}
|
export{'simd_copy_ordered', copyOrdered{}}
|
||||||
|
|
||||||
|
|
||||||
|
# In-register bit table
|
||||||
|
def arch_vec{T} = [arch_defvw/width{T}]T
|
||||||
|
def TI = i8 # Table values
|
||||||
|
def VI = arch_vec{TI}
|
||||||
|
def simd_bittab = hasarch{'SSSE3'}
|
||||||
|
|
||||||
|
def bittab_init{tab, z} = {
|
||||||
|
@for (t in *TI~~tab over 256) t = z
|
||||||
|
}
|
||||||
|
def bittab_init{tab, z & simd_bittab} = {
|
||||||
|
init:= VI**z
|
||||||
|
@unroll (t in *VI~~tab over 256/vcount{VI}) t = init
|
||||||
|
}
|
||||||
|
|
||||||
|
def bittab_selector{loadtab} = {
|
||||||
|
def nv = vcount{VI}
|
||||||
|
{t0, t1}:= loadtab{}
|
||||||
|
low:= VI**7
|
||||||
|
hi4:= VI**(-(1<<4))
|
||||||
|
b := VI~~make{[nv]u8, 1 << (iota{nv} & 7)}
|
||||||
|
def selector{x} = {
|
||||||
|
top := hi4 + VI~~((arch_vec{u32}~~(x&~low))>>3)
|
||||||
|
byte:= sel{[16]i8, t0, hi4^top} | sel{[16]i8, t1, top}
|
||||||
|
mask:= sel{[16]i8, b, x & low}
|
||||||
|
homMask{(mask & byte) == mask}
|
||||||
|
}
|
||||||
|
def reload{} = { tup{t0,t1} = loadtab{} }
|
||||||
|
tup{selector, reload}
|
||||||
|
}
|
||||||
|
|
||||||
|
def readbytes{vtab}{} = {
|
||||||
|
def k = vcount{VI}; def l = 128/vcount{VI}
|
||||||
|
def side{i} = {
|
||||||
|
def U = arch_vec{ty_u{k}}
|
||||||
|
def m = @collect (vtab over _ from i to i+l) homMask{vtab}
|
||||||
|
VI~~make{U, if (vcount{U}>l) merge{m,m} else m}
|
||||||
|
}
|
||||||
|
each{side, l*iota{2}}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Look up bits from table
|
||||||
|
def bittab_lookup{x0:*void, n:u64, r0:*void, tab:*void} = {
|
||||||
|
x:= *u8~~x0
|
||||||
|
t:= *TI~~tab
|
||||||
|
r:= *u64~~r0
|
||||||
|
rem:= n
|
||||||
|
while (rem > 0) {
|
||||||
|
k:= rem; if (k>64) k=64
|
||||||
|
rv:u64 = 0
|
||||||
|
@for (x over j to k) rv|= u64~~promote{i64,load{t,x}} & ((u64~~1)<<j)
|
||||||
|
store{r, 0, rv}
|
||||||
|
x+=k; rem-=k; ++r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def bittab_lookup{x0:*void, n:u64, r0:*void, tab:*void & simd_bittab} = {
|
||||||
|
def {bitsel, _} = bittab_selector{readbytes{*VI~~tab}}
|
||||||
|
def k = vcount{VI}
|
||||||
|
@for (x in *VI~~x0, r in *ty_u{k}~~r0 over cdiv{n,k}) r = bitsel{x}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fill table with t (0 or -1) at all bytes in x0
|
||||||
|
# Stop early if the sum u reaches 0, indicating all bytes in the table
|
||||||
|
# are equal: by the time it's checked at least one has been set to t,
|
||||||
|
# so they're all t
|
||||||
|
# Fill r0 depending on mode:
|
||||||
|
# - 'none': ignore
|
||||||
|
# - 'mask': Mark Firsts of x0
|
||||||
|
# - 'unique': Deduplicate of x0
|
||||||
|
# - 'index': First index of value x at r0+x
|
||||||
|
def do_bittab{x0:*void, n:u64, tab:*void, u:u8, t, mode, r0} = {
|
||||||
|
def rbit = mode == 'mask'
|
||||||
|
def rval = mode == 'unique'
|
||||||
|
def rind = mode == 'index'
|
||||||
|
def storebit{i, v:T} = if (rbit) store{*T~~r0, i, v}
|
||||||
|
if (rbit or rval) assert{match{t,0}}
|
||||||
|
|
||||||
|
btab:= *i8~~tab
|
||||||
|
def settab_sub{x, v, i} = {
|
||||||
|
if (rval) store{*u8~~r0, u, x}
|
||||||
|
if (rind and v!=t) store{r0, x, i}
|
||||||
|
u+= u8~~i8~~(t - v) # u tracks the total of btab
|
||||||
|
store{btab, x, t}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
def settab1{x, i} = settab_sub{x, -1 - t, i} # Known new
|
||||||
|
def settab{x, i} = settab_sub{x, load{btab, x}, i} # General case
|
||||||
|
def settab{T, x, i} = T~~promote{ty_s{T}, settab{x, i}}
|
||||||
|
|
||||||
|
x:= *u8~~x0
|
||||||
|
if (not simd_bittab) {
|
||||||
|
rem:= n
|
||||||
|
@for (i to cdiv{n,64}) {
|
||||||
|
k:= rem; if (k>64) k=64
|
||||||
|
rw:u64 = 0
|
||||||
|
@for (x over j to k) {
|
||||||
|
new:= settab{u64, x, i*64+j} # Index usually unused
|
||||||
|
if (rbit) rw|= new & ((u64~~1)<<j)
|
||||||
|
}
|
||||||
|
storebit{i, rw}
|
||||||
|
x+=k; rem-=k
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Do first few values with a scalar loop
|
||||||
|
# Avoids the cost of ever loading the table into vectors for n<=48
|
||||||
|
i:u64 = 32; if (n<=48) i=n
|
||||||
|
def k = vcount{VI}; def uk = ty_u{k}; def ik = ty_s{k}
|
||||||
|
{rw,rv} := undef{tup{u64,uk}} # Bit results, used if rbit
|
||||||
|
if (rbit) rw = 0
|
||||||
|
@for (x over j to i) {
|
||||||
|
new:= settab{u64, x, j}
|
||||||
|
if (rbit) rw|= new & ((u64~~1)<<j)
|
||||||
|
}
|
||||||
|
storebit{0, rw}
|
||||||
|
if ((mode == 'none' or rind) and u == 0) return{u} # Won't ever trigger (m != 0)!
|
||||||
|
|
||||||
|
def done = makelabel{}
|
||||||
|
def {bitsel, reload_tab} = bittab_selector{readbytes{*VI~~tab}}
|
||||||
|
xv:= *VI~~x0
|
||||||
|
while (i < n) {
|
||||||
|
i0:= i; iw:= i/k
|
||||||
|
v:= load{xv, iw}
|
||||||
|
m:= bitsel{v} # Mask of possibly-new values
|
||||||
|
if (not match{t,0}) m^= uk~~promote{ik, t}
|
||||||
|
i+= k
|
||||||
|
if (i > n) m&= (~uk~~0)>>((-n)%k)
|
||||||
|
# Any new values?
|
||||||
|
if (m == 0) {
|
||||||
|
storebit{iw, m}
|
||||||
|
} else {
|
||||||
|
# Add values to the table and filter m
|
||||||
|
if (rbit) rv = m
|
||||||
|
im:= i0 + ctzi{m}
|
||||||
|
xi:= load{x, im}
|
||||||
|
settab1{xi, im}
|
||||||
|
if ((m&(m-1)) != 0) { # More bits than one
|
||||||
|
# Filter out values equal to the previous, or first new
|
||||||
|
def pind = (iota{k}&15) - 1
|
||||||
|
prev:= make{VI, each{bind{max,0}, pind}}
|
||||||
|
e:= ~homMask{v == VI**TI~~xi}
|
||||||
|
e&= base{2,pind<0} | ~homMask{v == sel{[16]i8, v, prev}}
|
||||||
|
if (rbit) rv&= e | -m # Don't remove first bit
|
||||||
|
m&= e
|
||||||
|
while (m != 0) {
|
||||||
|
im:= i0 + ctzi{m}
|
||||||
|
new:= settab{uk, load{x, im}, im}
|
||||||
|
m1:= m-1; m&= m1 # Clear low bit
|
||||||
|
if (rbit) rv&= m1 | new # Clear if not new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storebit{iw, rv}
|
||||||
|
if (u == 0) { # All bytes seen
|
||||||
|
if (rbit) @for (r in *uk~~r0 over _ from iw+1 to cdiv{n,k}) r = 0
|
||||||
|
goto{done}
|
||||||
|
}
|
||||||
|
reload_tab{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setlabel{done}
|
||||||
|
}
|
||||||
|
u
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simd_mark_firsts_u8(x0:*void, n:u64, r0:*void, tab:*void) : void = {
|
||||||
|
bittab_init{tab, -1}
|
||||||
|
u:u8 = 0
|
||||||
|
do_bittab{x0, n, tab, u, 0, 'mask', r0}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simd_deduplicate_u8(x0:*void, n:u64, r0:*void, tab:*void) : u64 = {
|
||||||
|
assert{n != 0}
|
||||||
|
bittab_init{tab, -1}
|
||||||
|
u:u8 = 0
|
||||||
|
do_bittab{x0, n, tab, u, 0, 'unique', r0}
|
||||||
|
1 + promote{u64, u-1} # 0 to 256
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_bittab(x0:*void, n:u64, tab:*void, u:u8, t:i8) : u8 = {
|
||||||
|
do_bittab{x0, n, tab, u, t, 'none', 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simd_member_u8(w0:*void, nw:u64, x0:*void, nx:u64, r0:*void, tab:*void) : void = {
|
||||||
|
assert{nw > 0}
|
||||||
|
|
||||||
|
rev:u1 = nx < nw/4 # Reverse lookup
|
||||||
|
bittab_init{tab, -promote{i8,rev}}
|
||||||
|
u:u8 = 0 # Sum of table, either 0 or 256
|
||||||
|
if (rev) u = fill_bittab(x0, nx, tab, u, 0)
|
||||||
|
|
||||||
|
u = fill_bittab(w0, nw, tab, u, -1)
|
||||||
|
|
||||||
|
if (u == 0) { # All found!
|
||||||
|
@for (r in *u64~~r0 over cdiv{nx,64}) r = maxvalue{u64}
|
||||||
|
} else {
|
||||||
|
bittab_lookup{x0, nx, r0, tab}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simd_index_tab_u8{I}(w0:*void, nw:u64, x0:*void, nx:u64, tab:*void, i0:*void) : void = {
|
||||||
|
rev:u1 = nx < nw/4
|
||||||
|
bittab_init{tab, -promote{i8,rev}}
|
||||||
|
ind:= *I~~i0
|
||||||
|
@for (ind over 256) ind = cast_i{I, nw}
|
||||||
|
u:u8 = 0
|
||||||
|
if (rev) u = fill_bittab(x0, nx, tab, u, 0)
|
||||||
|
do_bittab{w0, nw, tab, u, -1, 'index', ind}
|
||||||
|
}
|
||||||
|
|
||||||
|
export{'simd_mark_firsts_u8', simd_mark_firsts_u8}
|
||||||
|
export{'simd_deduplicate_u8', simd_deduplicate_u8}
|
||||||
|
export{'simd_member_u8', simd_member_u8}
|
||||||
|
export{'simd_index_tab_u8', simd_index_tab_u8{usz}}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user