monadic arith
This commit is contained in:
parent
7284eb7010
commit
721dd8889b
@ -514,7 +514,8 @@ cachedBin‿linkerCache ← {
|
|||||||
⟨"src/jit/", "nvm.c"⟩
|
⟨"src/jit/", "nvm.c"⟩
|
||||||
⟨"src/utils/", "ryu.c", "utf.c", "hash.c", "file.c", "mut.c", "each.c", "bits.c"⟩
|
⟨"src/utils/", "ryu.c", "utf.c", "hash.c", "file.c", "mut.c", "each.c", "bits.c"⟩
|
||||||
⟩
|
⟩
|
||||||
singeliMap ← {po.arch≡"aarch64"? 𝕩/˜(1⊑¨𝕩)∊"cmp"‿"bits"‿"equal"‿"dyarith"; 𝕩} ⟨
|
singeliMap ← {po.arch≡"aarch64"? 𝕩/˜(1⊑¨𝕩)∊"cmp"‿"bits"‿"equal"‿"dyarith"‿"monarith"; 𝕩} ⟨
|
||||||
|
"src/builtins/arithm.c"‿"monarith",
|
||||||
"src/core/stuff.c"‿"equal", "src/utils/mut.c"‿"copy", "src/utils/bits.c"‿"bits"
|
"src/core/stuff.c"‿"equal", "src/utils/mut.c"‿"copy", "src/utils/bits.c"‿"bits"
|
||||||
"src/builtins/arithd.c"‿"dyarith", "src/builtins/cmp.c"‿"cmp", "src/builtins/squeeze.c"‿"squeeze"
|
"src/builtins/arithd.c"‿"dyarith", "src/builtins/cmp.c"‿"cmp", "src/builtins/squeeze.c"‿"squeeze"
|
||||||
"src/builtins/select.c"‿"select", "src/builtins/fold.c"‿"fold", "src/builtins/scan.c"‿"scan"
|
"src/builtins/select.c"‿"select", "src/builtins/fold.c"‿"fold", "src/builtins/scan.c"‿"scan"
|
||||||
|
|||||||
2
makefile
2
makefile
@ -298,7 +298,7 @@ endif
|
|||||||
@"${MAKE}" i_singeli=0 singeli=0 force_build_dir=build/obj/presingeli REPLXX=0 f= lf= postmsg="singeli sources:" i_t=presingeli i_f='-O1 -DPRE_SINGELI' FFI=0 OUTPUT=build/obj/presingeli/BQN c
|
@"${MAKE}" i_singeli=0 singeli=0 force_build_dir=build/obj/presingeli REPLXX=0 f= lf= postmsg="singeli sources:" i_t=presingeli i_f='-O1 -DPRE_SINGELI' FFI=0 OUTPUT=build/obj/presingeli/BQN c
|
||||||
|
|
||||||
|
|
||||||
build_singeli: ${addprefix src/singeli/gen/, cmp.c dyarith.c copy.c equal.c squeeze.c select.c fold.c scan.c neq.c slash.c constrep.c bits.c}
|
build_singeli: ${addprefix src/singeli/gen/, cmp.c dyarith.c monarith.c copy.c equal.c squeeze.c select.c fold.c scan.c neq.c slash.c constrep.c bits.c}
|
||||||
@echo $(postmsg)
|
@echo $(postmsg)
|
||||||
src/singeli/gen/%.c: src/singeli/src/%.singeli preSingeliBin
|
src/singeli/gen/%.c: src/singeli/src/%.singeli preSingeliBin
|
||||||
@echo $< | cut -c 17- | sed 's/^/ /'
|
@echo $< | cut -c 17- | sed 's/^/ /'
|
||||||
|
|||||||
@ -22,33 +22,6 @@ B bit_negate(B x) { // consumes
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GC1i(SYMB,NAME,FEXPR,IBAD,IEXPR,SQF,TMIN,RMIN) B NAME##_c1(B t, B x) { \
|
|
||||||
if (isF64(x)) { f64 v = x.f; return m_f64(FEXPR); } \
|
|
||||||
if (RARE(!isArr(x))) thrM(SYMB ": Expected argument to be a number"); \
|
|
||||||
u8 xe = TI(x,elType); \
|
|
||||||
if (xe<=TMIN) return RMIN; \
|
|
||||||
i64 sz = IA(x); \
|
|
||||||
if (xe==el_i8) { i8 MAX=I8_MAX; i8 MIN=I8_MIN; i8* xp=i8any_ptr(x); i8* rp; B r=m_i8arrc(&rp,x); \
|
|
||||||
for (i64 i = 0; i < sz; i++) { i8 v = xp[i]; if (RARE(IBAD)) { decG(r); goto base; } rp[i] = IEXPR; } \
|
|
||||||
decG(x); (void)MIN;(void)MAX; return r; \
|
|
||||||
} \
|
|
||||||
if (xe==el_i16) { i16 MAX=I16_MAX; i16 MIN=I16_MIN; i16* xp=i16any_ptr(x); i16* rp; B r=m_i16arrc(&rp,x); \
|
|
||||||
for (i64 i = 0; i < sz; i++) { i16 v = xp[i]; if (RARE(IBAD)) { decG(r); goto base; } rp[i] = IEXPR; } \
|
|
||||||
decG(x); (void)MIN;(void)MAX; return r; \
|
|
||||||
} \
|
|
||||||
if (xe==el_i32) { i32 MAX=I32_MAX; i32 MIN=I32_MIN; i32* xp=i32any_ptr(x); i32* rp; B r=m_i32arrc(&rp,x); \
|
|
||||||
for (i64 i = 0; i < sz; i++) { i32 v = xp[i]; if (RARE(IBAD)) { decG(r); goto base; } rp[i] = IEXPR; } \
|
|
||||||
decG(x); (void)MIN;(void)MAX; return r; \
|
|
||||||
} \
|
|
||||||
if (xe==el_f64) { f64* xp = f64any_ptr(x); \
|
|
||||||
f64* rp; B r = m_f64arrc(&rp, x); \
|
|
||||||
for (i64 i = 0; i < sz; i++) { f64 v = xp[i]; rp[i] = FEXPR; } \
|
|
||||||
decG(x); return SQF? num_squeeze(r) : r; \
|
|
||||||
} \
|
|
||||||
base: SLOW1(SYMB"𝕩", x); return arith_recm(NAME##_c1, x); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
B add_c1(B t, B x) {
|
B add_c1(B t, B x) {
|
||||||
if (isF64(x)) return x;
|
if (isF64(x)) return x;
|
||||||
if (!isArr(x)) thrM("+: Argument must consist of numbers");
|
if (!isArr(x)) thrM("+: Argument must consist of numbers");
|
||||||
@ -56,13 +29,69 @@ B add_c1(B t, B x) {
|
|||||||
dec(eachm_fn(m_f64(0), inc(x), add_c1));
|
dec(eachm_fn(m_f64(0), inc(x), add_c1));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
#if SINGELI
|
||||||
|
#define SINGELI_FILE monarith
|
||||||
|
#include "../utils/includeSingeli.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
GC1i("-", sub, -v, v== MIN, -v, 0, el_bit, bit_sel(x,m_f64(0),m_f64(-1))) // change icond to v==-v to support ¯0 (TODO that won't work for i8/i16)
|
#define GC1i(SYMB,NAME,FEXPR,TMIN,RMIN,MAIN) B NAME##_c1(B t, B x) { \
|
||||||
GC1i("|", stile, fabs(v), v== MIN, v<0?-v:v,0, el_bit, x)
|
if (isF64(x)) { f64 v = x.f; return m_f64(FEXPR); } \
|
||||||
GC1i("⌊", floor, floor(v), 0, v, 1, el_i32, x)
|
if (RARE(!isArr(x))) thrM(SYMB ": Expected argument to be a number"); \
|
||||||
GC1i("⌈", ceil, ceil(v), 0, v, 1, el_i32, x)
|
u8 xe = TI(x,elType); \
|
||||||
GC1i("×", mul, v==0?0:v>0?1:-1, 0,v==0?0:v>0?1:-1,1, el_bit, x)
|
if (elNum(xe)) { \
|
||||||
GC1i("¬", not, 1-v, v<=-MAX, 1-v, 0, el_bit, bit_negate(x))
|
if (xe<=TMIN) return RMIN; \
|
||||||
|
MAIN(FEXPR) \
|
||||||
|
} \
|
||||||
|
SLOW1(SYMB"𝕩", x); return arith_recm(NAME##_c1, x); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOOP_BODY(INIT, EXPR, POST) { \
|
||||||
|
i64 ia = IA(x); INIT; \
|
||||||
|
void* xp = tyany_ptr(x); \
|
||||||
|
switch(xe) { default: UD; \
|
||||||
|
case el_i8: for(usz i=0; i<ia; i++) { i8 c = ((i8* )xp)[i]; EXPR(i8, c==I8_MIN) } break; \
|
||||||
|
case el_i16: for(usz i=0; i<ia; i++) { i16 c = ((i16*)xp)[i]; EXPR(i16, c==I16_MIN) } break; \
|
||||||
|
case el_i32: for(usz i=0; i<ia; i++) { i32 c = ((i32*)xp)[i]; EXPR(i32, c==I32_MIN) } break; \
|
||||||
|
case el_f64: for(usz i=0; i<ia; i++) { f64 c = ((f64*)xp)[i]; EXPR(f64, 0) } break; \
|
||||||
|
} \
|
||||||
|
decG(x); return r; POST \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIGN_EXPR(T, C) rp[i] = c>0? 1 : c==0? 0 : -1;
|
||||||
|
#define SIGN_MAIN(FEXPR) LOOP_BODY(i8* rp; B r=m_i8arrc(&rp,x);, SIGN_EXPR,)
|
||||||
|
|
||||||
|
#if SINGELI
|
||||||
|
#define STILE_BODY(FEXPR) { usz ia = IA(x); B r; retry: \
|
||||||
|
void* rp = m_tyarrlc(&r, elWidth(xe), x, el2t(xe)); \
|
||||||
|
u64 got = simd_abs[xe-el_i8](rp, tyany_ptr(x), ia); \
|
||||||
|
if (LIKELY(got==ia)) { decG(x); return r; } \
|
||||||
|
tyarr_freeF(v(r)); \
|
||||||
|
xe++;if (xe==el_i16) x=taga(cpyI16Arr(x)); \
|
||||||
|
else if (xe==el_i32) x=taga(cpyI32Arr(x)); \
|
||||||
|
else x=taga(cpyF64Arr(x)); \
|
||||||
|
goto retry; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define STILE_EXPR(T, C) if(C) goto bad; ((T*)rp)[i] = c>=0? c : -c;
|
||||||
|
#define STILE_BODY(FEXPR) LOOP_BODY(B r; void* rp = m_tyarrlc(&r, elWidth(xe), x, el2t(xe));, STILE_EXPR, bad: tyarr_freeF(v(r));)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FLOAT_BODY(FEXPR) { i64 ia = IA(x); \
|
||||||
|
assert(xe==el_f64); f64* xp = f64any_ptr(x); \
|
||||||
|
f64* rp; B r = m_f64arrc(&rp, x); \
|
||||||
|
for (usz i = 0; i < ia; i++) { f64 v=xp[i]; rp[i]=FEXPR; } \
|
||||||
|
decG(x); return num_squeeze(r); \
|
||||||
|
}
|
||||||
|
B sub_c2(B,B,B);
|
||||||
|
#define SUB_BODY(FEXPR) return sub_c2(t, m_f64(0), x);
|
||||||
|
#define NOT_BODY(FEXPR) x = num_squeezeChk(x); return TI(x,elType)==el_bit? bit_negate(x) : sub_c2(m_f64(0), m_f64(1), x);
|
||||||
|
|
||||||
|
GC1i("-", sub, -v, el_bit, bit_sel(x,m_f64(0),m_f64(-1)), SUB_BODY)
|
||||||
|
GC1i("|", stile, fabs(v), el_bit, x, STILE_BODY)
|
||||||
|
GC1i("⌊", floor, floor(v), el_i32, x, FLOAT_BODY)
|
||||||
|
GC1i("⌈", ceil, ceil(v), el_i32, x, FLOAT_BODY)
|
||||||
|
GC1i("×", mul, v==0?0:v>0?1:-1, el_bit, x, SIGN_MAIN)
|
||||||
|
GC1i("¬", not, 1-v, el_bit, bit_negate(x), NOT_BODY)
|
||||||
|
|
||||||
#define GC1f(N, F, MSG) B N##_c1(B t, B x) { \
|
#define GC1f(N, F, MSG) B N##_c1(B t, B x) { \
|
||||||
if (isF64(x)) { f64 xv=o2fG(x); return m_f64(F); } \
|
if (isF64(x)) { f64 xv=o2fG(x); return m_f64(F); } \
|
||||||
@ -86,6 +115,16 @@ GC1i("¬", not, 1-v, v<=-MAX, 1-v, 0, el_bit, bit_negate(x))
|
|||||||
|
|
||||||
GC1f( div, 1/xv, "÷: Getting reciprocal of non-number")
|
GC1f( div, 1/xv, "÷: Getting reciprocal of non-number")
|
||||||
GC1f(root, sqrt(xv), "√: Getting square root of non-number")
|
GC1f(root, sqrt(xv), "√: Getting square root of non-number")
|
||||||
|
#undef GC1i
|
||||||
|
#undef LOOP_BODY
|
||||||
|
#undef SIGN_EXPR
|
||||||
|
#undef SIGN_MAIN
|
||||||
|
#undef STILE_BODY
|
||||||
|
#undef STILE_EXPR
|
||||||
|
#undef STILE_BODY
|
||||||
|
#undef FLOAT_BODY
|
||||||
|
#undef SUB_BODY
|
||||||
|
#undef NOT_BODY
|
||||||
#undef GC1f
|
#undef GC1f
|
||||||
|
|
||||||
f64 fact(f64 x) { return tgamma(x+1); }
|
f64 fact(f64 x) { return tgamma(x+1); }
|
||||||
|
|||||||
@ -164,7 +164,7 @@ def arithAAimpl{vw, mode, F, W, X, R, w, x, r, len} = {
|
|||||||
|
|
||||||
def run = runner{match{overflow, 0}, R, F}
|
def run = runner{match{overflow, 0}, R, F}
|
||||||
|
|
||||||
def unr = tern{mode==0, 2, 1} # 2x unroll non-overflowing cases; surpresses clang's default unrolling, which unrolls a lot more; 2x appears to be plenty
|
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, len, {is, M} => {
|
muLoop{bulk, unr, len, {is, M} => {
|
||||||
def cw = loadBatch{*W~~w, is, ty_sc{W, TY}}
|
def cw = loadBatch{*W~~w, is, ty_sc{W, TY}}
|
||||||
def cx = loadBatch{*X~~x, is, ty_sc{X, TY}}
|
def cx = loadBatch{*X~~x, is, ty_sc{X, TY}}
|
||||||
|
|||||||
28
src/singeli/src/monarith.singeli
Normal file
28
src/singeli/src/monarith.singeli
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
include './base'
|
||||||
|
include './f64'
|
||||||
|
include './cbqnDefs'
|
||||||
|
if (hasarch{'X86_64'}) {
|
||||||
|
include './sse3'
|
||||||
|
include './avx'
|
||||||
|
include './avx2'
|
||||||
|
} else if (hasarch{'AARCH64'}) {
|
||||||
|
include './neon'
|
||||||
|
}
|
||||||
|
include './bitops'
|
||||||
|
include './mask'
|
||||||
|
|
||||||
|
|
||||||
|
absFn{T}(r:*void, x:*void, len:u64) : u64 = {
|
||||||
|
def bulk = arch_defvw/width{T}
|
||||||
|
def VT = [bulk]T
|
||||||
|
muLoop{bulk, tern{T==f64, 2, 1}, len, {is, M} => {
|
||||||
|
def cx = loadBatch{*T~~x, is, VT}
|
||||||
|
if (T!=f64 and homAny{M{tree_fold{&, eachx{==, cx, VT**minvalue{T}}}}}) return{tupsel{0,is}*bulk}
|
||||||
|
storeBatch{*T~~r, is, each{abs, cx}, M}
|
||||||
|
}}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
|
def tup_abs = each{{T}=>absFn{T}, tup{i8, i16, i32, f64}}
|
||||||
|
t_abs:*type{tupsel{0,tup_abs}} = tup_abs
|
||||||
|
'simd_abs' = t_abs
|
||||||
Loading…
Reference in New Issue
Block a user