Reverse Member-of hash lookup

This commit is contained in:
Marshall Lochbaum 2023-11-07 22:06:34 -05:00
parent 8a2190b092
commit c75fdbc277
2 changed files with 34 additions and 20 deletions

View File

@ -370,7 +370,7 @@ B memberOf_c2(B t, B w, B x) {
} }
CHECK_CHRS_ELSE { tyEls: // Both numbers CHECK_CHRS_ELSE { tyEls: // Both numbers
if (xia>32 && wia<=(xe<=el_i8?1:6)) { if (xia>32 && wia<=(xe<=el_i8?1:xe==el_i32?4:6)) {
SGetU(w); SGetU(w);
i8* rp; r = m_i8arrc(&rp, w); i8* rp; r = m_i8arrc(&rp, w);
for (usz i=0; i<wia; i++) rp[i] = indexOfOne(x, GetU(w,i)) < xia; for (usz i=0; i<wia; i++) rp[i] = indexOfOne(x, GetU(w,i)) < xia;

View File

@ -341,10 +341,9 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
def wt = width{T} def wt = width{T}
def prim = to_prim{name} def prim = to_prim{name}
ip := *T~~iv; fp := *T~~fv ip := *T~~iv; fp := *T~~fv
def swap_sides{} = each{{a,b}=>{t:=a; a=b; b=t}, tup{ip,m}, tup{fp,n}}
swap:u1 = 0 swap:u1 = 0
if (prim=='⊒' and (swap = n < m)) { if ((prim=='⊒' or prim=='∊') and (swap = n < m)) swap_sides{}
each{{a,b}=>{t:=a; a=b; b=t}, tup{ip,m}, tup{fp,n}}
}
def stop = m def stop = m
log := clzc{m} log := clzc{m}
@ -372,11 +371,24 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
def setm{found, i} = has_maxh |= found def setm{found, i} = has_maxh |= found
end := maxh>>sh # Clip trailing maxh if it shouldn't be in the table end := maxh>>sh # Clip trailing maxh if it shouldn't be in the table
def usem{} = { def usem{} = {
try_vec_memb{T, hash, sz+ext, sh, maxh, has_maxh, rp, fp, n, abort} if (swap) {
swap_sides{}; i=m # i==m return value is kind of dumb
@for (ip over m) { # Remove values in ip from hash
h := hash_val{ip}; j := h>>sh
if (h == maxh) { has_maxh = 0 } else {
k := load{hash,j}
if (k <= h) {
while (k < h) { ++j; k = load{hash,j} }
if (k==h) hash_remove{j,h}
}
}
}
}
try_vec_memb{T, hash, sz+ext, sh, maxh, has_maxh, swap, rp, fp, n, abort}
if (has_maxh) { while (load{hash,end}!=maxh) ++end } if (has_maxh) { while (load{hash,end}!=maxh) ++end }
else end += promote{T,ext} # Unreachable else end += promote{T,ext} # Unreachable
} }
def get{found, j} = promote{i8, found & (j<end)} def get{found, j} = promote{i8, swap ^ (found & (j<end))}
tup{set, setm, usem, get} tup{set, setm, usem, get}
} }
{('⊐')} => { {('⊐')} => {
@ -454,6 +466,16 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
} }
} }
def hash_remove{j,h} = {
do {
jp:=j; ++j
h=load{hash,j}
if (h>>sh == j) h = maxh
store{hash, jp, h}
each{{t} => store{t, jp, load{t,j}}, vals}
} while (h!=maxh)
}
setlabel{lookup} setlabel{lookup}
fixup{} fixup{}
def prog_lookup{swap} = { # Progressive Index-of lookup def prog_lookup{swap} = { # Progressive Index-of lookup
@ -471,17 +493,8 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
store{rp, ...rev{i, m-ti}} store{rp, ...rev{i, m-ti}}
c -= promote{usz,ti>0}; if (c==0) goto{shortcut} c -= promote{usz,ti>0}; if (c==0) goto{shortcut}
ti = load{link, ti} ti = load{link, ti}
if (ti > 0) { if (ti > 0) store{inds, j, ti}
store{inds, j, ti} else hash_remove{j,h}
} else {
do {
jp:=j; ++j
h=load{hash,j}
if (h>>sh == j) h = maxh
store{hash, jp, h}
store{inds, jp, load{inds,j}}
} while (h!=maxh)
}
} }
} }
} }
@ -503,7 +516,7 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
} }
def try_vec_memb{..._} = {} def try_vec_memb{..._} = {}
def try_vec_memb{T, hash, hashlen, sh, maxh, has_maxh, rp, fp, n, done def try_vec_memb{T, hash, hashlen, sh, maxh, has_maxh, swap, rp, fp, n, done
& hasarch{'SSE4.2'} & T==u32} = { & hasarch{'SSE4.2'} & T==u32} = {
# Hash h wants bin h>>sh, so the offset for h in slot i is (in infite-precision ints) # Hash h wants bin h>>sh, so the offset for h in slot i is (in infite-precision ints)
# i-h>>sh = i+((1<<sh-1)-h)>>sh = (((i+1)<<sh-1)-h)>>sh # i-h>>sh = i+((1<<sh-1)-h)>>sh = (((i+1)<<sh-1)-h)>>sh
@ -515,6 +528,7 @@ def try_vec_memb{T, hash, hashlen, sh, maxh, has_maxh, rp, fp, n, done
mv := V**0 mv := V**0
@for (h in *V~~(hash+o) over nh) { mv=max{mv, io-min{h,io}}; io+=id } @for (h in *V~~(hash+o) over nh) { mv=max{mv, io-min{h,io}}; io+=id }
max_off := vfold{max, mv} >> sh max_off := vfold{max, mv} >> sh
vswap := base{256,vl**1} * promote{T,swap}
def memb{test} = { def memb{test} = {
def R = i8; def rw = width{R}; def u = width{T}/rw def R = i8; def rw = width{R}; def u = width{T}/rw
@ -522,9 +536,9 @@ def try_vec_memb{T, hash, hashlen, sh, maxh, has_maxh, rp, fp, n, done
@for (r in *T~~rp over i to l) { @for (r in *T~~rp over i to l) {
c := V**0 # Will combine u results to avoid folding too much c := V**0 # Will combine u results to avoid folding too much
@unroll (f in fp+u*i over a to u) c |= V**(1<<(rw*a)) & test{f} @unroll (f in fp+u*i over a to u) c |= V**(1<<(rw*a)) & test{f}
r = vfold{|, c} r = vswap ^ vfold{|, c}
} }
@for (rp, fp over _ from u*l to n) rp = promote{R, homAny{test{fp}}} @for (rp, fp over _ from u*l to n) rp = promote{R, swap ^ homAny{test{fp}}}
goto{done} goto{done}
} }
def try{nv} = { def try{nv} = {