diff --git a/build/singeliSubmodule b/build/singeliSubmodule index 3b1f6937..29ad697a 160000 --- a/build/singeliSubmodule +++ b/build/singeliSubmodule @@ -1 +1 @@ -Subproject commit 3b1f6937bce4243aa511c8efa621c26f4778d24d +Subproject commit 29ad697ae528032b76403275d9cf9f09c7918927 diff --git a/src/singeli/src/base.singeli b/src/singeli/src/base.singeli index 53ad444a..d9905189 100644 --- a/src/singeli/src/base.singeli +++ b/src/singeli/src/base.singeli @@ -4,6 +4,7 @@ include 'util/kind' oper ~~ reinterpret infix right 55 oper ** broadcast infix right 55 +def same = is def Size = u64 def load{x} = *x def reinterpret{T, x:X & T==X} = x @@ -49,11 +50,12 @@ def unreachable{} = emit{void, 'si_unreachable'} def assert{x:u1} = { if (not x) emit{void, 'si_unreachable'} } # various checks -def oneType{{h:H, ...t}} = { - each{{c:C} => assert{C==H}, t} - H +def oneVal{{h, ...t}} = { + each{{c} => assert{c==h}, t} + h } -def oneType{{}} = {} +def oneVal{{}} = {} +def oneType{x} = oneVal{each{type, x}} def isreg = kreg def isconst = kcon @@ -62,9 +64,9 @@ def istup = ktup def isunsigned{T} = isint{T} & ~issigned{T} -def isvec {T} = 0; def isvec {T & istype{T}} = match{typekind{T},'vector'} -def isprim{T} = 0; def isprim{T & istype{T}} = match{typekind{T},'primitive'} -def isptr {T} = 0; def isptr {T & istype{T}} = match{typekind{T},'pointer'} +def isvec {T} = 0; def isvec {T & istype{T}} = same{typekind{T},'vector'} +def isprim{T} = 0; def isprim{T & istype{T}} = same{typekind{T},'primitive'} +def isptr {T} = 0; def isptr {T & istype{T}} = same{typekind{T},'pointer'} def anyNum{x} = isconst{x} | knum{x} diff --git a/src/singeli/src/cmp.singeli b/src/singeli/src/cmp.singeli index dcc7a56c..63ad0e64 100644 --- a/src/singeli/src/cmp.singeli +++ b/src/singeli/src/cmp.singeli @@ -23,15 +23,15 @@ fn cmpIX(dst:*u64, len:Size, x:u64, v:u1) : void = { fillbits{dst, len, v&~nan, x} } -def eqne{op} = match{op,__eq}|match{op,__ne} +def eqne{op} = same{op,__eq}|same{op,__ne} def pathAS{dst, len, T, op, x & issigned{T}} = { def R{f & eqne{op}} = { if (rare{floor{f}!=f}) fillbits{dst, len, op{0,1}, x} # also includes check for NaN/sNaN ftrunc{i64,f} } - def R{f & match{op,__lt}|match{op,__ge}} = ftrunc{i64,ceil{f}} - def R{f & match{op,__gt}|match{op,__le}} = ftrunc{i64,floor{f}} + def R{f & same{op,__lt}|same{op,__ge}} = ftrunc{i64,ceil{f}} + def R{f & same{op,__gt}|same{op,__le}} = ftrunc{i64,floor{f}} xf:f64 = interp_f64{x} xi64:i64 = R{xf} @@ -126,7 +126,7 @@ def table{aa, F, w, G_bit, G_vec} = { tup{ G_bit{}, ...each{{E}=>{ - def E2 = (if (aa and isunsigned{E} and ((match{F,__eq} | match{F,__ne}) | (E==u32))) {ty_s{E}} else E) + def E2 = (if (aa and isunsigned{E} and ((same{F,__eq} | same{F,__ne}) | (E==u32))) {ty_s{E}} else E) def bulk = w/width{E2} G_vec{[bulk]E2, max{tern{hasarch{'AARCH64'},2,1}, 8/bulk}} }, tup{i8, i16, i32, f64, u8, u16, u32}} diff --git a/src/singeli/src/dyarith.singeli b/src/singeli/src/dyarith.singeli index ea73f7be..5d12da00 100644 --- a/src/singeli/src/dyarith.singeli +++ b/src/singeli/src/dyarith.singeli @@ -36,13 +36,13 @@ def arithChk1{F==__sub, M, w:T, x:T, r:T & isvec{T} & tern{hasarch{'X86_64'}, el -def arithChk2{F, M, w:T, x:T & is_s{T} & (match{F,__add} | match{F,__sub})} = { +def arithChk2{F, M, w:T, x:T & is_s{T} & (same{F,__add} | same{F,__sub})} = { r:= F{w,x} tup{r, arithChk1{F, M, w, x, r}} } # × -def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & i8==eltype{T} & hasarch{'X86_64'}} = { +def arithChk2{F, M, w:T, x:T & same{F,__mul} & isvec{T} & i8==eltype{T} & hasarch{'X86_64'}} = { def wp = unpackQ{w, T ~~ (T**0 > w)} def xp = unpackQ{x, T ~~ (T**0 > x)} def rp = each{__mul, wp, xp} @@ -55,12 +55,12 @@ def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & i8==eltype{T} & hasar tup{packQ{rp}, tup{'~andAllZero', RU~~tree_fold{|, bad}, RU**0xff80}} } } -def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & i16==eltype{T} & hasarch{'X86_64'}} = { +def arithChk2{F, M, w:T, x:T & same{F,__mul} & isvec{T} & i16==eltype{T} & hasarch{'X86_64'}} = { rl:= __mul {w,x} rh:= __mulhi{w,x} tup{rl, tup{'anyne', rh, rl>>15}} } -def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & i32==eltype{T} & hasarch{'X86_64'}} = { +def arithChk2{F, M, w:T, x:T & same{F,__mul} & isvec{T} & i32==eltype{T} & hasarch{'X86_64'}} = { max:= to_el{f32, (ty_u{T})**0x4efffffe} def cf32{x:X} = emit{to_el{f32,X}, tern{T==[8]i32, '_mm256_cvtepi32_ps', '_mm_cvtepi32_ps'}, x} f32mul:= cf32{w} * cf32{x} @@ -77,7 +77,7 @@ def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & i32==eltype{T} & hasa # tup{packQQ{each{{v} => v & T2**0xFFFFFFFF, rp}}, tup{'homAny', tree_fold{|,bad}}} this doesn't use M } -def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & hasarch{'AARCH64'}} = { +def arithChk2{F, M, w:T, x:T & same{F,__mul} & isvec{T} & hasarch{'AARCH64'}} = { def r12 = mul12{w, x} rl:= packLo{r12} rh:= packHi{r12} @@ -108,7 +108,7 @@ def runner{u, R, F} = { } def run{F==__add, M, w:VS, x:VU & is_s{VS} & is_u{VU}} = run{F, M, x, w} # 3+'a' → 'a'+3 - def run{F, M, w:VW, x:VX & c & R==u32 & (match{F,__add} | match{F,__sub})} = { # 'a'+1, 'a'-1 + def run{F, M, w:VW, x:VX & c & R==u32 & (same{F,__add} | same{F,__sub})} = { # 'a'+1, 'a'-1 r:= F{ty_u{w}, ty_u{x}} tup{to_el{R, VW}~~r, tup{'homAny', M{r > type{r}**1114111}}} } @@ -133,8 +133,7 @@ def runChecks{type=='anyne', vals, M} = { def arithProcess{F, run, overflow, M, is, cw, cx, TY} = { def {values, checks} = flip{each{{w1, x1} => run{F, M, w1, x1}, cw, cx}} - def ctype = tupsel{0,tupsel{0,checks}} - assert{tree_fold{&, each{{c}=>match{ctype, tupsel{0,c}}, checks}}} + def ctype = oneVal{each{{c}=>tupsel{0,c}, checks}} if (rare{runChecks{ctype, checks, M}}) overflow{tupsel{0,is}*vcount{TY}} each{{c} => TY~~c, values} } @@ -145,7 +144,7 @@ def arithAAimpl{vw, mode, F, W, X, R, w, x, r, len} = { def bulk = vw/64 def VT = [bulk]u64 @maskedLoop{bulk}(r in tup{'g',*u64~~r}, cw in tup{VT,*u64~~w}, cx in tup{VT,*u64~~x} over cdiv{len, 64}) r{F{cw,cx}} - } else if (match{F,__mul} and W!=u1 and X==u1 and W==R) { # 0‿1‿1‿1‿1‿0‿1‿1×3‿1‿4‿1‿5‿9‿2‿6 + } else if (same{F,__mul} and W!=u1 and X==u1 and W==R) { # 0‿1‿1‿1‿1‿0‿1‿1×3‿1‿4‿1‿5‿9‿2‿6 def bulk = vw / width{W} def TU = ty_u{R} def TV = [bulk]TU @@ -158,7 +157,7 @@ def arithAAimpl{vw, mode, F, W, X, R, w, x, r, len} = { def overflow = tern{mode==1, {i}=>return{i}, tern{mode==2, {i}=>return{1}, 0}} def TY = [bulk]R - def run = runner{match{overflow, 0}, R, F} + def run = runner{same{overflow, 0}, R, F} def unr = tern{mode==0, 2, 1} # 2x unroll non-overflowing cases; suppresses clang's default unrolling, which unrolls a lot more; 2x appears to be plenty @muLoop{bulk, unr}(sr in tup{'g',*R~~r}, cw in tup{ty_sc{W,TY},*W~~w}, cx in tup{ty_sc{X,TY},*X~~x}, M in 'm' over is to len) { diff --git a/src/singeli/src/mask.singeli b/src/singeli/src/mask.singeli index 687d63a4..557b8840 100644 --- a/src/singeli/src/mask.singeli +++ b/src/singeli/src/mask.singeli @@ -70,8 +70,8 @@ def storeBatch{ptr:P, ns, xs, M & istup{ns}} = each{{n,x} => storeBatch{ptr, n, # "harmless" pointer cast that'll only cast void* def hCast{T,p} = assert{show{'expected pointer with element',T,'or void but got ',p}} -def hCast{T,p:P & match{T,eltype{P}}} = p -def hCast{T,p:P & match{P,*void}} = *T~~p +def hCast{T,p:P & same{T,eltype{P}}} = p +def hCast{T,p:P & same{P,*void}} = *T~~p # masked loop arguments # p:*T - regular pointer, loaded by the batch index(es) diff --git a/src/singeli/src/neon.singeli b/src/singeli/src/neon.singeli index 550535e5..a860fc20 100644 --- a/src/singeli/src/neon.singeli +++ b/src/singeli/src/neon.singeli @@ -8,7 +8,7 @@ def nvecu = genchk{nvec, {T} => isunsigned{T}} def nvecf = genchk{nvec, {T} => isfloat{T}} -def reinterpret{T, v & match{'pointer',typekind{T}} & ktup{v}} = { tmp:T=v } +def reinterpret{T, v & same{'pointer',typekind{T}} & ktup{v}} = { tmp:T=v } def nty{T== u8} = 'u8'; def nty{T== i8} = 's8' def nty{T==u16} = 'u16'; def nty{T==i16} = 's16' @@ -89,9 +89,9 @@ def fold_add {a:T & nvec{T}} = emit{eltype{T}, ntyp{'vaddv', T}, a} def fold_addw{a:T & nveci{T}} = emit{ty_dbl{eltype{T}}, ntyp{'vaddlv', T}, a} def fold_min {a:T & nvec{T} & ~nveci{T,64}} = emit{eltype{T}, ntyp{'vminv', T}, a} def fold_max {a:T & nvec{T} & ~nveci{T,64}} = emit{eltype{T}, ntyp{'vmaxv', T}, a} -def vfold{F, x:T & nvec{T} & ~nveci{T,64} & match{F, min}} = fold_min{x} -def vfold{F, x:T & nvec{T} & ~nveci{T,64} & match{F, max}} = fold_max{x} -def vfold{F, x:T & nvec{T} & match{F, +}} = fold_add{x} +def vfold{F, x:T & nvec{T} & ~nveci{T,64} & same{F, min}} = fold_min{x} +def vfold{F, x:T & nvec{T} & ~nveci{T,64} & same{F, max}} = fold_max{x} +def vfold{F, x:T & nvec{T} & same{F, +}} = fold_add{x} # TODO don't rely on regular stores being unaligned local def storeu{ptr:P, e:T} = store{ptr, 0, e} diff --git a/src/singeli/src/scan.singeli b/src/singeli/src/scan.singeli index 5cabacf3..d2dba497 100644 --- a/src/singeli/src/scan.singeli +++ b/src/singeli/src/scan.singeli @@ -72,7 +72,7 @@ export{'avx2_scan_min_init_f64', avx2_scan_idem{f64, min}}; export{'avx2_scan_ma fn avx2_scan_idem_id{T, op}(x:*T, r:*T, len:u64) : void = { def m = 1 << (width{T}-1) - def id = (if (match{op,min}) m-1; else -m) + def id = (if (same{op,min}) m-1; else -m) avx2_scan_idem{T, op}(x, r, len, id) } export{'avx2_scan_min_i8', avx2_scan_idem_id{i8 , min}}; export{'avx2_scan_max_i8', avx2_scan_idem_id{i8 , max}} diff --git a/src/singeli/src/search.singeli b/src/singeli/src/search.singeli index 67db0711..eac86377 100644 --- a/src/singeli/src/search.singeli +++ b/src/singeli/src/search.singeli @@ -156,7 +156,7 @@ def do_bittab{x0:*void, n:u64, tab:*void, u:u8, t, mode, r0} = { 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}} + if (rbit or rval) assert{same{t,0}} btab:= *i8~~tab def settab_sub{x, v, i} = { @@ -204,7 +204,7 @@ def do_bittab{x0:*void, n:u64, tab:*void, u:u8, t, mode, r0} = { 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} + if (not same{t,0}) m^= uk~~promote{ik, t} i+= k if (i > n) m&= (~uk~~0)>>((-n)%k) # Any new values?