From 859be5efb2ae95cbb72fe00c295ad9d30caf583e Mon Sep 17 00:00:00 2001 From: dzaima Date: Thu, 30 Jun 2022 01:47:57 +0300 Subject: [PATCH] singeli chr_squeeze --- src/builtins/squeeze.c | 51 ++++++++++----- src/singeli/src/base.singeli | 18 ++++-- src/singeli/src/squeeze.singeli | 110 ++++++++++++++++++++------------ test/squeezeExact.bqn | 42 +++++++----- 4 files changed, 140 insertions(+), 81 deletions(-) diff --git a/src/builtins/squeeze.c b/src/builtins/squeeze.c index 35349382..4b365f24 100644 --- a/src/builtins/squeeze.c +++ b/src/builtins/squeeze.c @@ -73,7 +73,7 @@ B num_squeeze(B x) { if (xp==NULL) return num_squeezeF(x, ia); #if SINGELI - or = avx2_squeeze_B((u8*)xp, ia); + or = avx2_squeeze_numB((u8*)xp, ia); if (or==0xfffffffe) goto r_f64; goto r_orF64; r_orF64: if (or==0xffffffff) goto r_x; else goto r_or; @@ -98,31 +98,48 @@ B num_squeeze(B x) { B chr_squeeze(B x) { usz ia = a(x)->ia; u8 xe = TI(x,elType); - if (xe==el_c8) goto r_x; usz i = 0; i32 or = 0; - if (xe==el_c16) { - u16* xp = c16any_ptr(x); - for (; i < ia; i++) if (xp[i] != (u8)xp[i]) goto r_x; - goto r_c8; - } - if (xe==el_c32) { - u32* xp = c32any_ptr(x); - bool c8 = true; - for (; i < ia; i++) { - if (xp[i] != (u16)xp[i]) goto r_c32; - if (xp[i] != (u8 )xp[i]) c8 = false; + switch(xe) { default: UD; + case el_c8: goto r_x; + #if SINGELI + case el_c16: { u32 t = avx2_squeeze_c16((u8*)c16any_ptr(x), ia); if (t==0) goto r_c8; else goto r_x; } + case el_c32: { u32 t = avx2_squeeze_c32((u8*)c32any_ptr(x), ia); if (t==0) goto r_c8; else if (t==1) goto r_c16; else if (t==2) goto r_x; else UD; } + #else + case el_c16: { + u16* xp = c16any_ptr(x); + for (; i < ia; i++) if (xp[i] != (u8)xp[i]) goto r_x; + goto r_c8; } - if (c8) goto r_c8; - else goto r_c16; + case el_c32: { + u32* xp = c32any_ptr(x); + bool c8 = true; + for (; i < ia; i++) { + if (xp[i] != (u16)xp[i]) goto r_x; + if (xp[i] != (u8 )xp[i]) c8 = false; + } + if (c8) goto r_c8; + else goto r_c16; + } + #endif + case el_bit: case el_i8: case el_i16: case el_i32: case el_f64: case el_B:; /*fallthrough*/ } B* xp = arr_bptr(x); if (xp!=NULL) { + #if SINGELI + u32 t = avx2_squeeze_chrB((u8*)xp, ia); + if (t==0) goto r_c8; + else if (t==1) goto r_c16; + else if (t==2) goto r_c32; + else if (t==3) goto r_x; + else UD; + #else for (; i < ia; i++) { if (!isC32(xp[i])) goto r_x; or|= o2cu(xp[i]); } + #endif } else { SGetU(x) for (; i < ia; i++) { @@ -133,8 +150,8 @@ B chr_squeeze(B x) { } if (or<=U8_MAX ) r_c8: return FL_SET(toC8Any(x), fl_squoze); else if (or<=U16_MAX) r_c16: return FL_SET(toC16Any(x), fl_squoze); - else r_c32: return FL_SET(toC32Any(x), fl_squoze); - r_x: return FL_SET(x, fl_squoze); + else goto r_c32; r_c32: return FL_SET(toC32Any(x), fl_squoze); + /*when known typed:*/ r_x: return FL_SET(x, fl_squoze); } B any_squeeze(B x) { diff --git a/src/singeli/src/base.singeli b/src/singeli/src/base.singeli index 839b9518..ebb27c3c 100644 --- a/src/singeli/src/base.singeli +++ b/src/singeli/src/base.singeli @@ -20,6 +20,18 @@ def assert{x & x==0} = assert{'failed assertion'} def assert{x & x==1} = 1 def assert{x:u1} = emit{void, 'si_assert', x} + + +def tern{c, T, F & anyInt{c}} = { + if(c) T + else F +} +def tern{c, t:T, f:T & anyInt{c}} = { + res:T = f + if (c) res = t + res +} + def min{a, b & knum{a} & knum{b}} = tern{ab, a, b} @@ -48,12 +60,6 @@ def anyInt{x & isreg{x}|isconst{x}} = isint{x} def trunc{T, x:U & isint{T} & isint{U} & T<=U} = emit{T, '', x} def trunc{T, x & knum{x}} = cast{T, x} -def tern{c, T, F & anyInt{c}} = { - if(c) T - else F -} - - def ty_s{w== 8} = i8; def ty_u{w== 8} = u8 def ty_s{w==16} = i16; def ty_u{w==16} = u16 def ty_s{w==32} = i32; def ty_u{w==32} = u32 diff --git a/src/singeli/src/squeeze.singeli b/src/singeli/src/squeeze.singeli index 6f11bd26..e8bfbb0f 100644 --- a/src/singeli/src/squeeze.singeli +++ b/src/singeli/src/squeeze.singeli @@ -3,23 +3,25 @@ include './sse3' include './avx' include './avx2' include './mask' +include './cbqnDefs' include 'util/tup' def preserve_negative_zero = 0 -def inRangeLen{x:T, start, count & issigned{eltype{T}}} = { - def TU = ty_u{T} - (TU~~(x-broadcast{T,start})) < broadcast{TU,count} +def inRangeLen{x:TS, start, count & issigned{eltype{TS}}} = { + def TU = ty_u{TS} + TU~~(x-broadcast{TS,start}) < broadcast{TU,count} } -def inRangeLen{x:T, start, count & isunsigned{eltype{T}}} = { - def TS = ty_s{T} - def h = 1 << (width{eltype{T}}-1) - (TS~~x)-broadcast{TS,start-h} < broadcast{TS,count-h} +def inRangeLen{x:TU, start, count & isunsigned{eltype{TU}}} = { + def TS = ty_s{TU} + def h = 1 << (width{eltype{TU}}-1) + TS~~(x-broadcast{TU,start-h}) < broadcast{TS,count-h} } def inRangeIncl{x:T, start, end} = inRangeLen{x, start, end-start+1} def inRangeExcl{x:T, start, end} = inRangeLen{x, start, end-start} def isSNaN{x:T & isunsigned{eltype{T}}} = inRangeLen{x<<1, (0xFFE<<52)+2, (1<<52)-2} +def q_chr{x:T & isvec{T} & eltype{T}==u64} = inRangeLen{x, cbqn_c32Tag{}<<48, 1<<48} def fold{F, x:T} = { show{'WARNING: using fallback fold'} @@ -39,52 +41,76 @@ def fold{F, x:T & w128{T}} = { } def fold{F, x:T & w256{T}} = fold{F, F{half{x, 0}, half{x, 1}}} -squeeze{vw, X0}(x0:*u8, len:Size) : u32 = { - def X = tern{X0==u64, f64, X0} +squeeze{vw, X, CHR, B}(x0:*u8, len:Size) : u32 = { def bulk = vw / width{X} def XV = [bulk]X def E = tern{X==f64, u32, ty_u{X}} def EV = [bulk]E + show{XV, EV, CHR, B} xp:= *X~~x0 r1:= broadcast{EV, 0} - if (X==i8) { + if (CHR) { + def hw = width{E}/2 maskedLoop{bulk, len, {i, M} => { - v0:= loadBatch{xp, i, XV} - if (anyne{broadcast{EV, 0xfe} & EV~~v0, broadcast{EV, 0}, M}) return{2} + c:= EV~~loadBatch{xp, i, XV} + if (X!=u16) r1|= M{c} # for u64, just accept the garbage top 32 bits and deal with them at the end + if (B) { + if (any{M{~q_chr{c}}}) return{3} + } else { + if (anyne{broadcast{EV, (1<u32 and r2>=65536) return{2} + if (X>u16 and r2>=256) return{1} 0 } else { - maskedLoop{bulk, len, {i, M} => { - v0:= loadBatch{xp, i, XV} - def toint{x:T & isint{eltype{T}}} = x - def toint{flt:T & X==f64} = { - int:= cvt2{i32, flt} - - def conv{x} = tern{preserve_negative_zero, ty_u{x}, x} - - if (anyne{conv{flt}, conv{cvt2{f64, int}}, M}) { # is any not an integer - if (X0==f64) return{0xffff_ffff} - - maskedLoop{bulk, i, len, {i, M} => { - def XU = [bulk]u64 - v:= XU ~~ loadBatch{xp, i, XV} - if (any{M{isSNaN{v}}}) return{0xffff_ffff} # is any not even a float - }} - return{0xffff_fffe} + if (X==i8) { + maskedLoop{bulk, len, {i, M} => { + v0:= loadBatch{xp, i, XV} + if (anyne{broadcast{EV, 0xfe} & EV~~v0, broadcast{EV, 0}, M}) return{2} + }} + 0 + } else { + maskedLoop{bulk, len, {i, M} => { + v0:= loadBatch{xp, i, XV} + if (isunsigned{X}) { + r1|= EV~~v0 + } else { + def toint{x:T & isint{eltype{T}}} = x + def toint{flt:T & X==f64} = { + int:= cvt2{i32, flt} + + def conv{x} = tern{preserve_negative_zero, ty_u{x}, x} + + if (anyne{conv{flt}, conv{cvt2{f64, int}}, M}) { # is any not an integer + if (~B) return{0xffff_ffff} # f64arr→f64arr + + maskedLoop{bulk, i, len, {i, M} => { + def XU = [bulk]u64 + v:= XU ~~ loadBatch{xp, i, XV} + if (any{M{isSNaN{v}}}) return{0xffff_ffff} # is any not even a float + }} + return{0xffff_fffe} + } + int + } + v1:= toint{v0} + r1|= M{(broadcast{EV, ~E~~1} & EV~~v1) ^ EV~~(v1 >> (width{X}-1))} } - int - } - v1:= toint{v0} - r1|= M{(broadcast{EV, ~E~~1} & EV~~v1) ^ EV~~(v1 >> (width{X}-1))} - }} - promote{u32, fold{|, r1}} + }} + + promote{u32, fold{|, r1}} + } } } -'avx2_squeeze_i8' = squeeze{256, i8 } -'avx2_squeeze_i16' = squeeze{256, i16} -'avx2_squeeze_i32' = squeeze{256, i32} -'avx2_squeeze_f64' = squeeze{256, f64} -'avx2_squeeze_B' = squeeze{256, u64} -#'avx2_squeeze_u16' = squeeze{256, u16} -#'avx2_squeeze_u32' = squeeze{256, u32} \ No newline at end of file +'avx2_squeeze_i8' = squeeze{256, i8, 0, 0} +'avx2_squeeze_i16' = squeeze{256, i16, 0, 0} +'avx2_squeeze_i32' = squeeze{256, i32, 0, 0} +'avx2_squeeze_f64' = squeeze{256, f64, 0, 0} +'avx2_squeeze_numB'= squeeze{256, f64, 0, 1} + +'avx2_squeeze_c16' = squeeze{256, u16, 1, 0} +'avx2_squeeze_c32' = squeeze{256, u32, 1, 0} +'avx2_squeeze_chrB'= squeeze{256, u64, 1, 1} \ No newline at end of file diff --git a/test/squeezeExact.bqn b/test/squeezeExact.bqn index 78064a9a..00f92f74 100644 --- a/test/squeezeExact.bqn +++ b/test/squeezeExact.bqn @@ -14,28 +14,37 @@ ctv ← "Ac8"‿"Ac16"‿"Ac32" cmax ← 1114112⌊2⋆8×2⋆↕3 ⟨specF64⟩ ← ⟨r⟩ •Import "utils.bqn" -spec ← specF64∾{⇐}∾"a⍉𝕨"∾<"foo" +spec ← specF64∾{⇐}∾"a⍉𝕨"∾(@+1114111-↕5)∾<"foo" + +RandEl ← r.Range∘3◶⟨ + {𝕊: r.Range∘≠⊸⊑ spec} # some special values + {𝕊: -⍟(r.Range 2) × (¯5+r.Range 10) + 2⋆r.Range 64} # random near-power-of-two number + {𝕊: @+0⌈1114111⌊(¯5+r.Range 10) + 2⋆2+r.Range 20} # random near-power-of-two character +⟩ -# currently tests an array of 0s, with only one outstanding element Do ← { 𝕊: - val ← {r.Range∘≠◶𝕩𝕩} ⟨ - {𝕊: r.Range∘≠⊸⊑ spec} - {𝕊: (¯5+r.Range 10) + 2⋆r.Range 64} - ⟩ - base ← 0 + val ← RandEl@ + base ← RandEl@ len ← 1+r.Range 2⋆3+r.Range 7 pos ← r.Range len arr ← "Ah" Variation val⌾(pos⊸⊑) len⥊1) ⟨val⟩ + expg ← (∧´⊑=⊢)◶3‿⊑ { + 1=𝕩? 1; + 2=𝕩? 2; + 3 + }∘•type¨ vals + tOut‿tIn ← { - 1=•Type val? - msk ← ((¬int) ∨ val≡⌊val) ∧ 1∾˜ (≥⟜nmin∧≤⟜nmax)val + expg=1? + msk ← ∧´ {((¬int) ∨ 𝕩≡⌊𝕩) ∧ 1∾˜ (≥⟜nmin∧≤⟜nmax)𝕩}¨ vals ⟨1↑msk/ntn ⋄ "Ah"‿"Af"∾msk/ntv⟩; - (2≡•Type val) ∧ 1≡len? - msk ← {2≡•Type val? (1≡len) ∧ (val-@)𝕩-@}¨ vals ⟨1↑msk/ctn ⋄ "Ah"‿"Af"∾msk/ctv⟩; - # else + expg=3? ⟨"h"‿"fill" ⋄ "Ah"‿"Af"⟩ } tIn ↩ {'S'∾1↓𝕩}¨⊸∾ ∾⟜"Inc"¨⊸∾ tIn @@ -50,10 +59,11 @@ Do ← { 𝕊: } ¬ (arrv EEqual arr) ∧ (arrv EEqual sq) ∧ (⊑(