From ee856a4880af3770e80e7acc79df79a6dce2a86a Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Tue, 31 Oct 2023 12:16:51 -0400 Subject: [PATCH] Move hash resizing to a generator, and other refactoring --- src/builtins/selfsearch.c | 20 ------ src/singeli/src/selfsearch.singeli | 101 +++++++++++++++++------------ 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/src/builtins/selfsearch.c b/src/builtins/selfsearch.c index 8c5ed6bc..93de7f93 100644 --- a/src/builtins/selfsearch.c +++ b/src/builtins/selfsearch.c @@ -43,26 +43,6 @@ extern B mul_c2(B, B, B); extern B scan_add_bool(B x, u64 ia); extern B scan_max_num(B x, u8 xe, u64 ia); -// These hashes are stored in tables and must be invertible! -#if defined(__SSE4_2__) -#include -static inline u32 hash32(u32 x) { return _mm_crc32_u32(0x973afb51, x); } -#else -// Murmur3 -static inline u32 hash32(u32 x) { - x ^= x >> 16; x *= 0x85ebca6b; - x ^= x >> 13; x *= 0xc2b2ae35; - x ^= x >> 16; - return x; -} -#endif -static inline u64 hash64(u64 x) { - x ^= x >> 33; x *= 0xff51afd7ed558ccd; - x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53; - x ^= x >> 33; - return x; -} - static NOINLINE void memset32(u32* p, u32 v, usz l) { for (usz i=0; i> 16; x *= 0x85ebca6b + x ^= x >> 13; x *= 0xc2b2ae35 + x ^= x >> 16; x +} +def hash_val{x0:u64} = { + x := x0 + x ^= x >> 33; x *= 0xff51afd7ed558ccd + x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53 + x ^= x >> 33; x +} +# CRC32 +def hash_val{x:u32 & hasarch{'SSE4.2'}} = { + emit{u32, '_mm_crc32_u32', 0x973afb51, x} +} + +def hash_resize{hash,vals, x0,sh,sz,ext,cc, m} = { + dif := sz*((1< { val -= dif; memset{val, 0, dif} }, vals} + @for (j from dif to sz + ext) { + h := hash->j + if (h != x0) { + hash <-{j} x0 + k0 := h>>sh; k := k0; while (hash->k!=x0) ++k + cc += cast_i{usz, k-k0} + hash <-{k} h + each{{val} => { v := val->j; val <-{j} 0; val <-{k} v }, vals} + } + } +} + def names = tup{'memberOf', 'count', 'indexOf'} def prims = tup{'∊', '⊒', '⊐' } -def map{f,t,v} = if (v==tupsel{0,f}) tupsel{0,t} else map{slice{f,1}, slice{t,1}, v} +def map{{f,...fs}, {t,...ts}, v} = if (v==f) t else map{fs, ts, v} def to_prim = map{names, prims, .} # Resizing hash table, with fallback @@ -56,31 +94,27 @@ fn selfhashtab{T, name}(rp:*rty{name}, xp:*T, n:usz) = { sze := sz+ext # Initial table to end of allocation hash := *T~~halloc + szo memset{hash, x0, sze} - val := *u32~~(hash+sze) + szo - if (aux) { memset{val, 0, sze} } + vals := if (aux) tup{*u32~~(hash+sze) + szo} else tup{} + each{memset{., 0, sze}, vals} def {output, write_res} = match (prim) { {('∊')} => tup{{b}=>b, {j,h,k,x0} => { hash<-{j}h; k!=h }} {('⊒')} => { - ctr0:u32 = 1 - tup{ - {b}=>b, - {j,h,k,x0} => { - e0:=promote{u32,h==x0}; vj:=val->j; c0:=ctr0 - hash<-{j}h; val<-{j}vj+(e0^1); ctr0+=e0 - vj + (c0 & -e0) - } + ctr0:u32 = 1; def {val} = vals + def res{j,h,k,x0} = { + e0:=promote{u32,h==x0}; vj:=val->j; c0:=ctr0 + hash<-{j}h; val<-{j}vj+(e0^1); ctr0+=e0 + vj + (c0 & -e0) } + tup{{b}=>b, res} } {('⊐')} => { - ctr:u32 = 1 - tup{ - {b}=>promote{u32,b}*ctr, - {j,h,k,x0} => { - if (k!=h) { val<-{j}ctr; ++ctr; hash<-{j}h } - val->j - } + ctr:u32 = 1; def {val} = vals + def res{j,h,k,x0} = { + if (k!=h) { val<-{j}ctr; ++ctr; hash<-{j}h } + val->j } + tup{{b}=>promote{u32,b}*ctr, res} } } @@ -96,32 +130,15 @@ fn selfhashtab{T, name}(rp:*rty{name}, xp:*T, n:usz) = { ++i } if (i == n) goto{break} - def p64{a} = i64~~promote{u64,a} + # Check collision counter and possibly resize + def p64 = promote{u64,.} dc := p64{cc} - p64{div_thresh{i}} - if (dc >= 0) { + if (i64~~dc >= 0) { if (sz == msz) goto{break} # Abort if (has_radix and i < n/2 and sz >= 1<<18) goto{break} # Avoid resizing if close to the end - if (not (cc>(5+log-(wt-sh)))) { - # Resize hash, factor of 4 - def m = 2 - dif := sz*((1<j - if (h != x0) { - hash <-{j} x0 - k0 := h>>sh; k := k0; while (hash->k!=x0) ++k - cc += cast_i{usz, k-k0} - hash <-{k} h - if (aux) { v := val->j; val <-{j} 0; val <-{k} v } - } - } + if (cc>=stop or p64{n-i}*dc >= (p64{i}*p64{n+i})>>(5+log-(wt-sh))) { + hash_resize{hash,vals, x0,sh,sz,ext,cc, 2} # Resize hash, factor of 4 if (cc >= stop) goto{break} set_thresh{} }