#include "../core.h" #include "../utils/each.h" #include "../utils/calls.h" static NOINLINE void fillBits(u64* dst, u64 sz, bool v) { u64 x = 0-(u64)v; u64 am = (sz+63)/64; assert(am>0); for (usz i = 0; i < am; i++) dst[i] = x; } static NOINLINE void fillBitsDec(u64* dst, u64 sz, bool v, u64 x) { dec(b(x)); fillBits(dst, sz, v); } static NOINLINE u8 aMakeEq(B* w, B* x, u8 we, u8 xe) { // returns el_MAX if failed B* p = wexe?we:xe; if (elNum(we) & elNum(xe)) { switch(me) { default: UD; case el_i8: s = taga(cpyI8Arr (s)); break; case el_i16: s = taga(cpyI16Arr(s)); break; case el_i32: s = taga(cpyI32Arr(s)); break; case el_f64: s = taga(cpyF64Arr(s)); break; } } else if (elChr(we) & elChr(xe)) { switch(me) { default: UD; case el_c16: s = taga(cpyC16Arr(s)); break; case el_c32: s = taga(cpyC32Arr(s)); break; } } else return el_MAX; *p = s; return me; } B le_c2(B, B, B); B ge_c2(B, B, B); B lt_c2(B, B, B); B gt_c2(B, B, B); B eq_c2(B, B, B); B ne_c2(B, B, B); #define CMP_REC(NAME, RNAME, PRE) NOINLINE B NAME##_rec(i32 swapped, B w, B x) { PRE \ SLOWIF((!isArr(w) || TI(w,elType)!=el_B) && (!isArr(x) || TI(x,elType)!=el_B)) SLOW2("recursive cmp " #NAME, w, x); \ return swapped? arith_recd(RNAME##_c2, x, w) : arith_recd(NAME##_c2, w, x); \ } CMP_REC(le, ge, ) CMP_REC(lt, gt, ) CMP_REC(eq, eq, swapped=0;) CMP_REC(ne, ne, swapped=0;) #define ge_rec(S, W, X) le_rec(!S, X, W) #define gt_rec(S, W, X) lt_rec(!S, X, W) #undef CMP_REC #define CMPFN(A,F,S,T) A##_##F##S##_##T #define FN_LUT_T(B,F,S,...) Cmp##S##Fn B##_##F##S #define FN_LUT_C(B,A,F,S) FN_LUT_T(B,F,S)[] = {CMPFN(A,F,S,u1), CMPFN(A,F,S,i8), CMPFN(A,F,S,i16), CMPFN(A,F,S,i32), CMPFN(A,F,S,f64), CMPFN(A,F,S,u8), CMPFN(A,F,S,u16), CMPFN(A,F,S,u32)} #define FN_LUT_A(B,F,S) FN_LUT_T(B,F,S)[8] #if SINGELI #include "../singeli/c/cmp.c" #else void cmpA_init(void) { } #define BASE_CMP_LOOP(OP, W, X) \ for (usz j = 0; j < (l+7)>>3; j++) { \ u8 c = 0; \ for (usz k = 0; k < 8; k++) { \ usz i = j*8+k; \ c|= ((W) OP (X))< , wv & ~xv) CMP_AA_C1(gt, > ) CMP_AA_F(ge, >=, wv | ~xv) CMP_AA_C1(ge, >=) #undef CMP_AA_F #define CMP_SLOW(T, GW) void cmp_slow_##T(void* r, void* w, B x, u64 l, BBB2B fn) { \ assert(l>0); incBy(x,l-1); \ for (usz i=0; i0); B x=b(xr); \ if (LIKELY(q_##Q(x))) BODY; \ else SLOW(N, T); \ } #define CMP_SA1(N, T, Q, C, SLOW, OP) CMP_SA0(N, T, Q, SLOW, ({ T xv = C(x); BASE_CMP_LOOP(OP, ((T*)w)[i], xv) })) #define CMP_SA_F(N, OP, SLOW, BX) \ CMP_SA0(N, u1, bit, SLOW, ({usz bia = BIT_N(l); u64 xv=bitx(x); for (usz i=0; i=, CMP_TO_SLOW, wv | ~xv) CMP_SA_F(lt, < , CMP_TO_SLOW, ~wv & xv) CMP_SA_F(gt, > , CMP_TO_SLOW, wv & ~xv) #undef CMP_SA_F FN_LUT_C(cmp_fns, base, eq, AS); FN_LUT_C(cmp_fns, base, eq, AA); FN_LUT_C(cmp_fns, base, ne, AS); FN_LUT_C(cmp_fns, base, ne, AA); FN_LUT_C(cmp_fns, base, gt, AS); FN_LUT_C(cmp_fns, base, gt, AA); FN_LUT_C(cmp_fns, base, ge, AS); FN_LUT_C(cmp_fns, base, ge, AA); FN_LUT_C(cmp_fns, base, lt, AS); FN_LUT_C(cmp_fns, base, le, AS); #endif #if !CLANGD #undef FN_LUT_B #undef FN_LUT_C #undef FN_LUT_T #endif #define AL(X) u64* rp; B r = m_bitarrc(&rp, X); usz ria=IA(r) #define CMP_AA_D(CN, CR, NAME, PRE) NOINLINE B NAME##_AA(i32 swapped, B w, B x) { PRE \ u8 xe = TI(x, elType); if (xe==el_B) goto bad; \ u8 we = TI(w, elType); if (we==el_B) goto bad; \ if (RNK(w)==RNK(x)) { if (!eqShape(w, x)) thrF("%U: Expected equal shape prefix (%H ≡ ≢𝕨, %H ≡ ≢𝕩)", swapped?CR:CN, swapped?x:w, swapped?w:x); \ if (we!=xe) { B tw=w,tx=x; \ we = aMakeEq(&tw, &tx, we, xe); \ if (we==el_MAX) goto bad; \ w=tw; x=tx; \ } \ AL(x); \ if (ria) cmp_fns_##NAME##AA[we](rp, tyany_ptr(w), tyany_ptr(x), ria); \ decG(w);decG(x); return r; \ } \ bad: return NAME##_rec(swapped, w, x); \ } CMP_AA_D("≥", "≤", ge, ) CMP_AA_D(">", "<", gt, ) CMP_AA_D("=", "?", eq, swapped=0;) CMP_AA_D("≠", "?", ne, swapped=0;) #define le_AA(T, W, X) ge_AA(!T, X, W) #define lt_AA(T, W, X) gt_AA(!T, X, W) #undef CMP_AA_D #define CMP_SA_D(NAME, RNAME, PRE) B NAME##_SA(i32 swapped, B w, B x) { PRE \ u8 xe = TI(x, elType); if (xe==el_B) goto bad; \ AL(x); \ if (ria) cmp_fns_##RNAME##AS[xe](rp, tyany_ptr(x), w.u, ria); \ else dec(w); \ decG(x); return r; \ bad: return NAME##_rec(swapped, w, x); \ } CMP_SA_D(eq, eq, swapped=0;) CMP_SA_D(ne, ne, swapped=0;) CMP_SA_D(le, ge, ) CMP_SA_D(ge, le, ) CMP_SA_D(lt, gt, ) CMP_SA_D(gt, lt, ) #undef CMP_SA_D #undef AL #define CMP_TO_ARR(NAME, RNAME) \ if (isArr(x)) { \ if (isArr(w)) return NAME##_AA(0, w, x); \ else return NAME##_SA(0, w, x); \ } else if (isArr(w)) return RNAME##_SA(1, x, w); #define CMP_SCALAR(NAME, RNAME, OP, FC, CF) B NAME##_c2(B t, B w, B x) { \ if (isF64(w)&isF64(x)) return m_i32(w.f OP x.f); \ if (isC32(w)&isC32(x)) return m_i32(w.u OP x.u); \ CMP_TO_ARR(NAME, RNAME); \ if (isF64(w)&isC32(x)) return m_i32(FC); \ if (isC32(w)&isF64(x)) return m_i32(CF); \ return m_i32(compare(w, x) OP 0); \ } CMP_SCALAR(le, ge, <=, 1, 0) CMP_SCALAR(ge, le, >=, 0, 1) CMP_SCALAR(lt, gt, < , 1, 0) CMP_SCALAR(gt, lt, > , 0, 1) NOINLINE B eq_atom(B t, B w, B x) { B r = m_i32( atomEqual(w, x)); dec(w); dec(x); return r; } NOINLINE B ne_atom(B t, B w, B x) { B r = m_i32(!atomEqual(w, x)); dec(w); dec(x); return r; } B eq_c2(B t, B w, B x) { if(isF64(w)&isF64(x)) return m_i32(w.f==x.f); if(isC32(w)&isC32(x)) return m_i32(w.u==x.u); CMP_TO_ARR(eq, eq); return eq_atom(t, w, x); } B ne_c2(B t, B w, B x) { if(isF64(w)&isF64(x)) return m_i32(w.f!=x.f); if(isC32(w)&isC32(x)) return m_i32(w.u!=x.u); CMP_TO_ARR(ne, ne); return ne_atom(t, w, x); } #undef CMP_SCALAR #undef CMP_TO_ARR B gt_c1(B t, B x) { if (isAtm(x)) return x; return bqn_merge(x); }