From c0b2164dc84bf442e31b13b9bfd52cfa5c9a8066 Mon Sep 17 00:00:00 2001 From: dzaima Date: Mon, 5 Sep 2022 22:52:53 +0300 Subject: [PATCH] new array-atom arith --- src/builtins/arithd.c | 222 +++++++++++++---------------- src/singeli/c/arithdDispatch.c | 165 ++++++++++++++++++++- src/singeli/src/base.singeli | 31 ++-- src/singeli/src/dyarith.singeli | 85 ++++++----- src/singeli/src/genArithTables.bqn | 105 ++++++++++---- 5 files changed, 401 insertions(+), 207 deletions(-) diff --git a/src/builtins/arithd.c b/src/builtins/arithd.c index 3b010222..2959e3ce 100644 --- a/src/builtins/arithd.c +++ b/src/builtins/arithd.c @@ -7,6 +7,8 @@ static f64 pfmod(f64 a, f64 b) { if (a<0 != b<0 && r!=0) r+= b; return r; } +static f64 bqn_or(f64 w, f64 x) { return (w+x)-(w*x); } + B add_c2(B, B, B); B ceil_c2(B, B, B); B sub_c2(B, B, B); B div_c2(B, B, B); B not_c2(B, B, B); B pow_c2(B, B, B); @@ -59,52 +61,6 @@ B floor_c2(B, B, B); #define DOI8(EXPR,A,W,X,BASE) { Ri8(A) for (usz i=0; ixv?xv:wv, 2, {}) AR_I_AA("⌈", ceil , wv>xv?wv:xv, 1, {}) AR_I_AA("+", add, wv+xv, 0, {}) AR_I_AA("-", sub, wv-xv, 0, { - IFN_SINGELI(if (we==el_c32 && xe==el_i32) { + if (we==el_c32 && xe==el_i32) { u32* wp = c32any_ptr(w); usz wia = IA(w); u32* rp; r = m_c32arrc(&rp, w); i32* xp = i32any_ptr(x); @@ -218,82 +200,80 @@ B floor_c2(B, B, B); if (rp[i]>CHR_MAX) thrM("-: Invalid character"); // safe - see add } goto dec_ret; - }) + } }) #undef AR_I_AA + #define AR_I_AS(CHR, NAME, EXPR, DO_AS, EXTRA) NOINLINE B NAME##_AS(B t, B w, B x) { \ + B r; u8 we=TI(w,elType); EXTRA \ + if (isF64(x)) { usz ia=IA(w); DO_AS(NAME,EXPR) } \ + ARITH_SLOW; return arith_recd(NAME##_c2, w, x); \ + dec_ret: decG(w); return r; \ + } + + #define AR_I_SA(CHR, NAME, EXPR, DO_SA, EXTRA) NOINLINE B NAME##_SA(B t, B w, B x) { \ + B r; u8 xe=TI(x,elType); EXTRA \ + if (isF64(w)) { usz ia=IA(x); DO_SA(NAME,EXPR) } \ + ARITH_SLOW; return arith_recd(NAME##_c2, w, x); \ + dec_ret: decG(x); return r; \ + } + + static NOINLINE B bit_sel1Fn(BBB2B f, B w, B x, bool bitX) { // consumes both + B b = bitX? x : w; + u64* bp = bitarr_ptr(b); + usz ia = IA(b); + + bool b0 = ia? bp[0]&1 : 0; + bool both = false; + for (usz i = 0; i < ia; i++) if (bitp_get(bp,i) != b0) { both=true; break; } + + B e0=m_f64(0), e1=m_f64(0); // initialized to have something to decrement later + bool h0=both || b0==0; if (h0) e0 = bitX? f(bi_N, inc(w), m_f64(0)) : f(bi_N, m_f64(0), inc(x)); + bool h1=both || b0==1; if (h1) e1 = bitX? f(bi_N, w, m_f64(1)) : f(bi_N, m_f64(1), x); + // non-bitarr arg has been consumed + B r = bit_sel(b, e0, h0, e1, h1); // and now the bitarr arg is consumed too + dec(e0); dec(e1); + return r; + } + + AR_I_SA("-", sub, wv-xv, SI_SA, {}) + AR_I_SA("×", mul, wv*xv, SI_SA, {}) + AR_I_SA("∧", and, wv*xv, REG_SA, {}) + AR_I_SA("∨", or , (wv+xv)-(wv*xv), REG_SA, {}) + AR_I_SA("⌊", floor, wv>xv?xv:wv, REG_SA, {}) + AR_I_SA("⌈", ceil , wv>xv?wv:xv, REG_SA, {}) + AR_I_SA("+", add, wv+xv, SI_SA, { + if (isC32(w) && xe==el_i32) { + u32 wv = o2cu(w); + i32* xp = i32any_ptr(x); usz xia = IA(x); + u32* rp; r = m_c32arrc(&rp, x); + for (usz i = 0; i < xia; i++) { + rp[i] = (u32)(xp[i]+(i32)wv); + if (rp[i]>CHR_MAX) thrM("+: Invalid character"); // safe to only check this as wv already must be below CHR_MAX, which is less than U32_MAX/2 + } + goto dec_ret; + } + }) + #undef AR_I_SA + + + AR_I_AS("-", sub, wv-xv, SI_AS, { + if (we==el_c32 && isC32(x)) { + i32 xv = (i32)o2cu(x); + u32* wp = c32any_ptr(w); usz wia = IA(w); + i32* rp; r = m_i32arrc(&rp, w); + for (usz i = 0; i < wia; i++) rp[i] = (i32)wp[i] - xv; + goto dec_ret; + } + }) + #undef AR_I_AS #endif // !SINGELI - - - #define AR_I_AS(CHR, NAME, EXPR, DO_AS, EXTRA) NOINLINE B NAME##_AS(B t, B w, B x) { \ - B r; u8 we=TI(w,elType); EXTRA \ - if (isF64(x)) { usz ia=IA(w); DO_AS(NAME,EXPR) } \ - ARITH_SLOW; return arith_recd(NAME##_c2, w, x); \ - dec_ret: decG(w); return r; \ - } - - #define AR_I_SA(CHR, NAME, EXPR, DO_SA, EXTRA) NOINLINE B NAME##_SA(B t, B w, B x) { \ - B r; u8 xe=TI(x,elType); EXTRA \ - if (isF64(w)) { usz ia=IA(x); DO_SA(NAME,EXPR) } \ - ARITH_SLOW; return arith_recd(NAME##_c2, w, x); \ - dec_ret: decG(x); return r; \ - } - - static NOINLINE B bit_sel1Fn(BBB2B f, B w, B x, bool bitX) { // consumes both - B b = bitX? x : w; - u64* bp = bitarr_ptr(b); - usz ia = IA(b); - - bool b0 = ia? bp[0]&1 : 0; - bool both = false; - for (usz i = 0; i < ia; i++) if (bitp_get(bp,i) != b0) { both=true; break; } - - B e0=m_f64(0), e1=m_f64(0); // initialized to have something to decrement later - bool h0=both || b0==0; if (h0) e0 = bitX? f(bi_N, inc(w), m_f64(0)) : f(bi_N, m_f64(0), inc(x)); - bool h1=both || b0==1; if (h1) e1 = bitX? f(bi_N, w, m_f64(1)) : f(bi_N, m_f64(1), x); - // non-bitarr arg has been consumed - B r = bit_sel(b, e0, h0, e1, h1); // and now the bitarr arg is consumed too - dec(e0); dec(e1); - return r; - } - - AR_I_SA("-", sub, wv-xv, SI_SA, {}) - AR_I_SA("×", mul, wv*xv, SI_SA, {}) - AR_I_SA("∧", and, wv*xv, REG_SA, {}) - AR_I_SA("∨", or , (wv+xv)-(wv*xv), REG_SA, {}) - AR_I_SA("⌊", floor, wv>xv?xv:wv, REG_SA, {}) - AR_I_SA("⌈", ceil , wv>xv?wv:xv, REG_SA, {}) - AR_I_SA("+", add, wv+xv, SI_SA, { - if (isC32(w) && xe==el_i32) { - u32 wv = o2cu(w); - i32* xp = i32any_ptr(x); usz xia = IA(x); - u32* rp; r = m_c32arrc(&rp, x); - for (usz i = 0; i < xia; i++) { - rp[i] = (u32)(xp[i]+(i32)wv); - if (rp[i]>CHR_MAX) thrM("+: Invalid character"); // safe to only check this as wv already must be below CHR_MAX, which is less than U32_MAX/2 - } - goto dec_ret; - } - }) - #undef AR_I_SA - - - AR_I_AS("-", sub, wv-xv, SI_AS, { - if (we==el_c32 && isC32(x)) { - i32 xv = (i32)o2cu(x); - u32* wp = c32any_ptr(w); usz wia = IA(w); - i32* rp; r = m_i32arrc(&rp, w); - for (usz i = 0; i < wia; i++) rp[i] = (i32)wp[i] - xv; - goto dec_ret; - } - }) #define add_AS(T, W, X) add_SA(T, X, W) #define mul_AS(T, W, X) mul_SA(T, X, W) #define and_AS(T, W, X) and_SA(T, X, W) #define or_AS(T, W, X) or_SA(T, X, W) #define floor_AS(T, W, X) floor_SA(T, X, W) #define ceil_AS(T, W, X) ceil_SA(T, X, W) - #undef AR_I_AS #define AR_F_TO_ARR(NAME) return NAME##_c2_arr(t, w, x); #define AR_I_TO_ARR(NAME) \ @@ -326,7 +306,7 @@ AR_I_SCALAR("-", sub, w.f-x.f, { }) AR_I_SCALAR("×", mul, w.f*x.f, {}) AR_I_SCALAR("∧", and, w.f*x.f, {}) -AR_I_SCALAR("∨", or , (w.f+x.f)-(w.f*x.f), {}) +AR_I_SCALAR("∨", or , bqn_or(w.f, x.f), {}) AR_I_SCALAR("⌊", floor, w.f>x.f?x.f:w.f, {}) AR_I_SCALAR("⌈", ceil , w.f>x.f?w.f:x.f, {}) #undef AR_I_SCALAR diff --git a/src/singeli/c/arithdDispatch.c b/src/singeli/c/arithdDispatch.c index 549bc028..fe00017f 100644 --- a/src/singeli/c/arithdDispatch.c +++ b/src/singeli/c/arithdDispatch.c @@ -52,7 +52,7 @@ typedef struct EntAA { } EntAA; typedef struct DyTableAA { - EntAA entsAA[8*8]; // one for each instruction + EntAA entsAA[el_B*el_B]; // one for each instruction BBB2B mainFn; char* repr; } DyTableAA; @@ -130,7 +130,7 @@ NOINLINE B dyArith_AA(DyTableAA* table, B w, B x) { } case e_call_sqx: { assert(TI(x,elType)==el_f64); - x = num_squeeze(x); + x = num_squeezeChk(x); u8 xe = TI(x,elType); if (xe==el_f64) goto rec; e = &table->entsAA[TI(w,elType)*8 + xe]; @@ -147,6 +147,135 @@ NOINLINE B dyArith_AA(DyTableAA* table, B w, B x) { } +typedef struct DyTableSA DyTableSA; +typedef bool (*ForBitsel)(DyTableSA*, B w, B* r); +typedef u64 (*AtomArrFnC)(u8* r, u64 w, u8* x, u64 len); +typedef B (*DyArithChrFn)(DyTableSA*, B, B, usz, u8); + +typedef struct { + // >=el_i8 el_bit + union { AtomArrFnC f1; ForBitsel bitsel; }; + union { AtomArrFnC f2; }; +} EntSA; + + +struct DyTableSA { + EntSA ents[el_B]; + BBB2B mainFn; + char* repr; + DyTableSA* chrAtom; +}; + +bool bad_forBitselNN_SA(DyTableSA* table, B w, B* r) { return false; } +#define bad_forBitselCN_SA bad_forBitselNN_SA + +B bad_chrAtomSA(DyTableSA* table, B w, B x, usz ia, u8 xe) { return arith_recd(table->mainFn, w, x); } +#define bad_chrAtomAS bad_chrAtomSA + +u64 failAtomArr1(u8* r, u64 w, u8* x, u64 len) { return 0; } +u64 failAtomArr2(u8* r, u64 w, u8* x, u64 len) { return 1; } + +u8 nextType[] = { + [t_i8arr ] = t_i16arr, [t_c8arr ] = t_c16arr, + [t_i16arr] = t_i32arr, [t_c16arr] = t_c32arr, + [t_i32arr] = t_f64arr, [t_c32arr] = t_empty, + [t_f64arr] = t_empty, +}; + +B dyArith_SA(DyTableSA* table, B w, B x) { + usz ia = IA(x); + u8 xe = TI(x,elType); + + u8 width, type; // when one argument is a number, both + and - have character array result iif the other argument is a character array; therefore result type doesn't need a lookup + u64 wa; + + EntSA* e; + + if (!isF64(w)) { + if (!isC32(w)) goto rec; + DyTableSA* t2 = table->chrAtom; + if (t2==NULL) goto rec; + table = t2; + + + wa = o2cu(w); + newXEc: + switch(xe) { default: UD; + case el_bit: goto bitsel; + case el_i8: if (wa==( u8)wa) { e=&table->ents[el_i8 ]; width=0; type=t_c8arr; goto f1; } else goto cwiden_i8; + case el_i16: if (wa==(u16)wa) { e=&table->ents[el_i16]; width=1; type=t_c16arr; goto f1; } else goto cwiden_i16; + case el_i32: e=&table->ents[el_i32]; width=2; type=t_c32arr; goto f1; + case el_f64: x=num_squeezeChk(x); xe=TI(x,elType); if (xe!=el_f64) goto newXEc; else goto rec; + case el_c8: if (wa==( u8)wa) { e=&table->ents[el_c8 ]; width=0; type=t_i8arr; goto f1; } goto cwiden_c8; // TODO check for & use unsigned w + case el_c16: if (wa==(u16)wa) { e=&table->ents[el_c16]; width=1; type=t_i16arr; goto f1; } goto cwiden_c16; + case el_c32: e=&table->ents[el_c32]; width=2; type=t_i32arr; goto f1; + case el_B: goto rec; + } + + cwiden_i8: if (q_c16(w)) { type=t_c16arr; goto cpy_i16; } + cwiden_i16: { type=t_c32arr; goto cpy_i32; } + + cwiden_c8: if (q_c16(w)) { type=t_i16arr; goto cpy_c16; } + cwiden_c16: { type=t_i32arr; goto cpy_c32; } + goto rec; + } + + switch(xe) { default: UD; + case el_bit: goto bitsel; + case el_i8: if (q_i8 (w)) { e=&table->ents[el_i8 ]; width=0; type=t_i8arr; goto wint; } goto iwiden_i8; + case el_i16: if (q_i16(w)) { e=&table->ents[el_i16]; width=1; type=t_i16arr; goto wint; } goto iwiden_i16; + case el_i32: if (q_i32(w)) { e=&table->ents[el_i32]; width=2; type=t_i32arr; goto wint; } goto iwiden_i32; + case el_f64: e=&table->ents[el_f64]; width=3; type=t_f64arr; goto wf64; + case el_c8: if (q_i8 (w)) { e=&table->ents[el_c8 ]; width=0; type=t_c8arr; goto wint; } goto iwiden_c8; + case el_c16: if (q_i16(w)) { e=&table->ents[el_c16]; width=1; type=t_c16arr; goto wint; } goto iwiden_c16; + case el_c32: if (q_i32(w)) { e=&table->ents[el_c32]; width=2; type=t_c32arr; goto wint; } goto rec; + case el_B: goto rec; + } + + wint: wa=(u32)o2iu(w); goto f1; + wf64: wa=w.u; goto f1; + + iwiden_i8: if (q_i16(w)) { wa=(u32)o2iu(w); type=t_i16arr; goto cpy_i16; } + iwiden_i16: if (q_i32(w)) { wa=(u32)o2iu(w); type=t_i32arr; goto cpy_i32; } + iwiden_i32: { wa=w.u; type=t_f64arr; goto cpy_f64; } + + iwiden_c8: if (q_i16(w)) { wa=(u32)o2iu(w); type=t_c16arr; goto cpy_c16; } + iwiden_c16: if (q_i32(w)) { wa=(u32)o2iu(w); type=t_c32arr; goto cpy_c32; } + goto rec; + + // TODO reuse the copied array for the result; maybe even alternate copy & operation to stay in cache + cpy_c16: x = taga(cpyC16Arr(x)); width=1; e=&table->ents[el_c16]; goto f1; + cpy_c32: x = taga(cpyC32Arr(x)); width=2; e=&table->ents[el_c32]; goto f1; + + cpy_i16: x = taga(cpyI16Arr(x)); width=1; e=&table->ents[el_i16]; goto f1; + cpy_i32: x = taga(cpyI32Arr(x)); width=2; e=&table->ents[el_i32]; goto f1; + cpy_f64: x = taga(cpyF64Arr(x)); width=3; e=&table->ents[el_f64]; goto f1; + + AtomArrFnC fn; B r; + f1: fn = e->f1; + u64 got = fn(m_tyarrlc(&r, width, x, type), wa, tyany_ptr(x), ia); + if (got==ia) goto decG_ret; + decG(r); + + type = nextType[type]; + if (type==t_empty) goto rec; + fn = e->f2; + if (fn(m_tyarrlc(&r, width+1, x, type), wa, tyany_ptr(x), ia)==0) goto decG_ret; + decG(r); + goto rec; + + + decG_ret: decG(x); return r; + + rec: return arith_recd(table->mainFn, w, x); + + bitsel: { + B opts[2]; + if (!table->ents[el_bit].bitsel(table, w, opts)) goto rec; + return bit_sel(x, opts[0], 1, opts[1], 1); + } +} + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" #include "../gen/dyarith.c" @@ -157,4 +286,36 @@ static void powAAu_f64_f64_f64(u8* r, u8* w, u8* x, u64 len) { for (u64 i = 0; static void stileAAu_f64_f64_f64(u8* r, u8* w, u8* x, u64 len) { for (u64 i = 0; i < len; i++) ((f64*)r)[i] = pfmod(((f64*)x)[i], ((f64*)w)[i]); } static void logAAu_f64_f64_f64(u8* r, u8* w, u8* x, u64 len) { for (u64 i = 0; i < len; i++) ((f64*)r)[i] = log(((f64*)x)[i])/log(((f64*)w)[i]); } +#define BI_C2(N, W, X) ({ B w_ = (W); N##_c2(w_, w_, X); }) +// bool sub_forBitselCN_SA (DyTableSA* table, B w, B* r) { u32 v=o2cu(w); r[0] = m_c32(v-0); r[1] = m_c32(v-1); if (v==0) BI_C2(sub, w, m_f64(1)); return true; } +bool add_forBitselNN_SA (DyTableSA* table, B w, B* r) { f64 f=o2fu(w); r[0] = m_f64(f+0); r[1] = m_f64(f+1); return true; } +bool sub_forBitselNN_SA (DyTableSA* table, B w, B* r) { f64 f=o2fu(w); r[0] = m_f64(f-0); r[1] = m_f64(f-1); return true; } +bool subR_forBitselNN_SA(DyTableSA* table, B w, B* r) { f64 f=o2fu(w); r[0] = m_f64(0-f); r[1] = m_f64(1-f); return true; } +bool mul_forBitselNN_SA (DyTableSA* table, B w, B* r) { f64 f=o2fu(w); r[0] = m_f64(f*0); r[1] = m_f64(f*1); return true; } +bool min_forBitselNN_SA (DyTableSA* table, B w, B* r) { f64 f=o2fu(w); r[0] = m_f64(f<=0?f:0); r[1] = m_f64(f<=1?f:1); return true; } +bool max_forBitselNN_SA (DyTableSA* table, B w, B* r) { f64 f=o2fu(w); r[0] = m_f64(f>=0?f:0); r[1] = m_f64(f>=1?f:1); return true; } + +bool add_forBitselCN_SA(DyTableSA* table, B w, B* r) { u32 wc=o2cu(w); if(wc+1<=CHR_MAX) return false; r[0] = m_c32(wc); r[1] = m_c32(wc+1); return true; } +bool sub_forBitselCN_SA(DyTableSA* table, B w, B* r) { u32 wc=o2cu(w); if(wc !=0 ) return false; r[0] = m_c32(wc); r[1] = m_c32(wc-1); return true; } + +B sub_c2R(B t, B w, B x) { return sub_c2(t, x, w); } + +static NOINLINE B or_SA(B t, B w, B x) { + if (!isF64(w)) return arith_recd(or_c2, w, x); + if (LIKELY(TI(x,elType)==el_bit)) { + bitsel: + return bit_sel(x, BI_C2(or, w, m_f64(0)), 1, BI_C2(or, w, m_f64(1)), 1); + } + x = num_squeezeChk(x); + if (TI(x,elType)==el_bit) goto bitsel; + + f64* rp; + B r = m_f64arrc(&rp, x); + usz ia = a(x)->ia; + x = toF64Any(x); + orSAc_f64_f64_f64((u8*)rp, w.u, tyany_ptr(x), ia); + decG(x); + return r; +} + #include "../gen/arTables.c" diff --git a/src/singeli/src/base.singeli b/src/singeli/src/base.singeli index ebb27c3c..1319486b 100644 --- a/src/singeli/src/base.singeli +++ b/src/singeli/src/base.singeli @@ -21,22 +21,6 @@ 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} - - - # various checks def knum{x} = match{kind{x},'number'} def isreg{x} = match{kind{x},'register'} @@ -113,6 +97,21 @@ def maxvalue{T & isunsigned{T}} = (1<b, a, b} + + # tuple operations def broadcast{T, v & isprim{T}} = v def any{v:T & isprim{T}} = v diff --git a/src/singeli/src/dyarith.singeli b/src/singeli/src/dyarith.singeli index ec234674..88af76c4 100644 --- a/src/singeli/src/dyarith.singeli +++ b/src/singeli/src/dyarith.singeli @@ -22,9 +22,12 @@ def fmt_op{X== max}= 'max' def rootty{T & isprim{T}} = T def rootty{T & isvec{T}} = eltype{T} +def is_s{X} = issigned{rootty{X}} +def is_u{X} = isunsigned{rootty{X}} + def ty_sc{O, R} = R # keep floats as-is -def ty_sc{O, R & issigned{O} & isunsigned{rootty{R}}} = ty_s{R} -def ty_sc{O, R & isunsigned{O} & issigned{rootty{R}}} = ty_u{R} +def ty_sc{O, R & is_s{O} & is_u{R}} = ty_s{R} +def ty_sc{O, R & is_u{O} & is_s{R}} = ty_u{R} def bqn_or{a, b} = (a+b)-(a*b) @@ -37,7 +40,7 @@ def arithChk1{F==__sub, M, w:T, x:T, r:T & isvec{T} & width{eltype{T}}<=16} = an -def arithChk2{F, M, w:T, x:T & issigned{rootty{T}} & (match{F,__add} | match{F,__sub})} = { +def arithChk2{F, M, w:T, x:T & is_s{T} & (match{F,__add} | match{F,__sub})} = { r:= F{w,x} tup{r, arithChk1{F, M, w, x, r}} } @@ -81,9 +84,9 @@ def arithChk2{F, M, w:T, x:T & match{F,__mul} & isvec{T} & i32==eltype{T}} = { def runner{u, R, F} = { def c = ~u - def run{F, OO, M, w, x} = { show{'todo', fmt_op{F}, c, w, x}; emit{void,'__builtin_abort'}; w } + def run{F, OO, M, w, x} = { show{'todo', c, R, fmt_op{F}, w, x}; emit{void,'__builtin_abort'}; w } - def run{F, OO, M, w:T, x:T & c} = { + def run{F, OO, M, w:T, x:T & c & R!=u32} = { def r2 = arithChk2{F, M, w, x} if (rare{tupsel{1,r2}}) OO{} tupsel{0,r2} @@ -92,54 +95,24 @@ def runner{u, R, F} = { def run{F, OO, M, w, x & u} = F{w, x} # trivial base implementation def toggleTop{x:X} = x ^ broadcast{X, 1<<(width{eltype{X}}-1)} - def run{F==__sub, OO, M, w:VU, x:VU & isunsigned{eltype{VU}}} = { # 'b'-'a' + def run{F==__sub, OO, M, w:VU, x:VU & is_u{VU}} = { # 'b'-'a' def VS = ty_s{VU} run{F, OO, M, VS~~toggleTop{w}, VS~~toggleTop{x}} } - def run{F, OO, M, w:VU, x:VS & isunsigned{eltype{VU}} & issigned{eltype{VS}}} = { # 'a'+3, 'a'-3 + def run{F, OO, M, w:VU, x:VS & is_u{VU} & is_s{VS}} = { # 'a'+3, 'a'-3 toggleTop{VU~~run{F, OO, M, VS~~toggleTop{w}, x}} } - # def run{F==__add, OO, M, w:VS, x:VU & issigned{eltype{VS}} & isunsigned{eltype{VU}}} = run{F, OO, M, x, w} # 3+'a' → 'a'+3 + def run{F==__add, OO, M, w:VS, x:VU & is_s{VS} & is_u{VU}} = run{F, OO, M, x, w} # 3+'a' → 'a'+3 + + def run{F, OO, M, w:VW, x:VX & c & R==u32 & (match{F,__add} | match{F,__sub})} = { # 'a'+1, 'a'-1 + r:= F{ty_u{w}, ty_u{x}} + if (any{M{r > broadcast{type{r}, 1114111}}}) OO{} + to_el{R, VW}~~r + } run } -# old atom F array & array F atom -def arithAny{VT, F, W, X, r, len} = { - def bulk = vcount{VT} - def run = runner{eltype{VT}==f64, eltype{VT}, F} - maskedLoop{bulk, len, {i, M} => storeBatch{r, i, run{F, {} => return{i}, M, W{i}, X{i}}, M}} - len -} -# cast a guaranteed float to a more specific type; return{0} if not possible -def cast_fB{T, x:(u64) & f64==T} = from_B{f64, x} -def cast_fB{T, x:(u64) & issigned{T} & Tload{*VT~~w, i}, {i}=>xv, r, len} } -def arithSA{VT, F, w, x, r, len} = { wv:= broadcast{VT, w}; arithAny{VT, F, {i}=>wv, {i}=>load{*VT~~x, i}, r, len} } -arithAS{F,VT}(w: *u8, x: u64, r: *u8, len: Size) : Size = { def T=eltype{VT}; arithAS{VT, F, *T ~~ w, cast_fB{T, x}, *T~~r, len} } -arithSA{F,VT}(w: u64, x: *u8, r: *u8, len: Size) : Size = { def T=eltype{VT}; arithSA{VT, F, cast_fB{T, w}, *T ~~ x, *T~~r, len} } - -'avx2_addAS_i8' = arithAS{__add,[32]i8 }; 'avx2_addSA_i8' = arithSA{__add,[32]i8 } -'avx2_addAS_i16' = arithAS{__add,[16]i16}; 'avx2_addSA_i16' = arithSA{__add,[16]i16} -'avx2_addAS_i32' = arithAS{__add,[ 8]i32}; 'avx2_addSA_i32' = arithSA{__add,[ 8]i32} -'avx2_addAS_f64' = arithAS{__add,[ 4]f64}; 'avx2_addSA_f64' = arithSA{__add,[ 4]f64} -'avx2_subAS_i8' = arithAS{__sub,[32]i8 }; 'avx2_subSA_i8' = arithSA{__sub,[32]i8 } -'avx2_subAS_i16' = arithAS{__sub,[16]i16}; 'avx2_subSA_i16' = arithSA{__sub,[16]i16} -'avx2_subAS_i32' = arithAS{__sub,[ 8]i32}; 'avx2_subSA_i32' = arithSA{__sub,[ 8]i32} -'avx2_subAS_f64' = arithAS{__sub,[ 4]f64}; 'avx2_subSA_f64' = arithSA{__sub,[ 4]f64} -'avx2_mulAS_i8' = arithAS{__mul,[32]i8 }; 'avx2_mulSA_i8' = arithSA{__mul,[32]i8 } -'avx2_mulAS_i16' = arithAS{__mul,[16]i16}; 'avx2_mulSA_i16' = arithSA{__mul,[16]i16} -'avx2_mulAS_i32' = arithAS{__mul,[ 8]i32}; 'avx2_mulSA_i32' = arithSA{__mul,[ 8]i32} -'avx2_mulAS_f64' = arithAS{__mul,[ 4]f64}; 'avx2_mulSA_f64' = arithSA{__mul,[ 4]f64} - - - -# new array F array def arithAAimpl{vw, mode, F, W, X, R, w, x, r, len} = { # show{fmt_op{F}, mode, W, X, R} if (R==u1) { @@ -180,4 +153,28 @@ def arithAA{mode, F, W, X, R} = { else arithAAu{vw, mode, F, W, X, R} } +# mode: 0:overflow-checked, needed; 1:overflow-erroring; 2: overflow-checked, not needed +arithSAf{vw, mode, F, swap, W, X, R}(r:*u8, w:u64, x:*u8, len:u64) : u64 = { + # show{fmt_op{F}, swap, mode, W, X, R} + def bulk = vw / max{width{W}, width{R}} + def TY = [bulk]R + def overflow = tern{mode==1, {i}=>return{1}, {i}=>return{i}} + + def run = runner{(R==f64) | (mode==2), R, F} + def getW{v} = trunc{W, v} + def getW{v & W==f64} = interp_f64{v} + cw:= broadcast{ty_sc{W, TY}, getW{w}} + + maskedLoop{bulk, len, {i, M} => { + cx:= loadBatch{*X~~x, i, ty_sc{X, TY}} + storeBatch{*R~~r, i, TY~~run{F, {} => overflow{i}, M, tern{swap,cx,cw}, tern{swap,cw,cx}}, M} + }} + + if (mode==1) 0 + else len +} + +def arithSA{mode, F, swap, W, X, R} = arithSAf{256, mode, F, swap, W, X, R} + +'orSAc_f64_f64_f64'=arithSA{2,bqn_or,0,f64,f64,f64} include './../gen/arDefs' \ No newline at end of file diff --git a/src/singeli/src/genArithTables.bqn b/src/singeli/src/genArithTables.bqn index 443f4ef2..1ac131e2 100644 --- a/src/singeli/src/genArithTables.bqn +++ b/src/singeli/src/genArithTables.bqn @@ -1,6 +1,4 @@ debug ← 0=≠•args -•term.OutRaw⍟debug ∾⟨@+27 ⋄ "[H" ⋄ @+27 ⋄ "[2J" ⋄ @+27 ⋄ "[3J"⟩ -•Out⍟(3×debug) 200⥊'-' impls‿tables ← 2↑•args T ← =⊸{<⎉𝕨⍉⍟𝕨>𝕩} @@ -17,14 +15,7 @@ tmLit ← "uceue" tyWidth ← 99‿0‿1‿2‿3‿0‿1‿2 # in log2(bytes) tyName ← "bit"‿"i8"‿"i16"‿"i32"‿"f64"‿"c8"‿"c16"‿"c32" -tySiType ← "u1"‿"i8"‿"i16"‿"i32"‿"f64"‿"u8"‿"u16"‿"u32" - -ShowTbl ← { - # 𝕩 ↩ {∧´⥊𝕩≡¨@? @; 𝕩/˜𝕩≢¨@}¨ 𝕩 - 𝕩 ≍˘⍟=¨ ↩ - •Show 𝕩 - #•Out •Repr 𝕩 -}⍟debug +tySiName ← "u1"‿"i8"‿"i16"‿"i32"‿"f64"‿"u8"‿"u16"‿"u32" mdNone ← 0 mdExact ← 1 @@ -33,21 +24,26 @@ mdBit2i8 ← 3 mdF64Chr ← 4 mdSqF64 ← 5 -singeliFns ← ⟨⟩ -GetSingeli ← { tm‿w‿x‿r‿id‿si: +singeliAAFns ← ⟨⟩ +GetSingeliAA ← { tm‿w‿x‿r‿id‿si: { r≡@? @; name ← ∾⟨id, "AA", tm⊑tmLit, "_", w⊑tyName, "_", x⊑tyName, "_", r⊑tyName⟩ - singeliFns∾↩