#include "../../core.h" #include "../../utils/each.h" #include "../../builtins.h" #include "arithdDispatch.h" #include #if ARITH_DEBUG char* execAA_repr(u8 ex) { switch(ex) { default: return "(unknown)"; #define F(X) case X: return #X; FOR_ExecAA(F) #undef F } } #endif NOINLINE B dyArith_AA(DyTableAA* table, B w, B x) { u8 we = TI(w, elType); if (we==el_B) goto rec; u8 xe = TI(x, elType); if (xe==el_B) goto rec; ur wr = RNK(w); ur xr = RNK(x); if (wr!=xr) { usz* xsh=SH(x); usz* wsh=SH(w); ur mr=wrmainFn, w, x, wsh, xsh, mr); } if (!eqShPart(SH(w), SH(x), wr)) goto rec; B r, t; usz ia = IA(w); EntAA* e = &table->entsAA[we*8 + xe]; newEnt:; FnInfoAA* fn = &e->bundles[0]; newFn:; u8 ex = fn->ex1; newEx: #if ARITH_DEBUG printf("opcode %d / %s\n", ex, execAA_repr(ex)); #endif switch(ex) { default: UD; case wi8_reg: w=taga( cpyI8Arr(w)); goto do_ex2; case xi8_reg: x=taga( cpyI8Arr(x)); goto do_ex2; case wi16_reg: w=taga(cpyI16Arr(w)); goto do_ex2; case xi16_reg: x=taga(cpyI16Arr(x)); goto do_ex2; case wi32_reg: w=taga(cpyI32Arr(w)); goto do_ex2; case xi32_reg: x=taga(cpyI32Arr(x)); goto do_ex2; case wf64_reg: w=taga(cpyF64Arr(w)); goto do_ex2; case xf64_reg: x=taga(cpyF64Arr(x)); goto do_ex2; case wc16_reg: w=taga(cpyC16Arr(w)); goto do_ex2; case xc16_reg: x=taga(cpyC16Arr(x)); goto do_ex2; case wc32_reg: w=taga(cpyC32Arr(w)); goto do_ex2; case xc32_reg: x=taga(cpyC32Arr(x)); goto do_ex2; case wi8_swap: t=x; x=taga( cpyI8Arr(w)); w=t; goto do_ex2; case xi8_swap: t=w; w=taga( cpyI8Arr(x)); x=t; goto do_ex2; case wi16_swap: t=x; x=taga(cpyI16Arr(w)); w=t; goto do_ex2; case xi16_swap: t=w; w=taga(cpyI16Arr(x)); x=t; goto do_ex2; case wi32_swap: t=x; x=taga(cpyI32Arr(w)); w=t; goto do_ex2; case xi32_swap: t=w; w=taga(cpyI32Arr(x)); x=t; goto do_ex2; case wf64_swap: t=x; x=taga(cpyF64Arr(w)); w=t; goto do_ex2; case xf64_swap: t=w; w=taga(cpyF64Arr(x)); x=t; goto do_ex2; case wc16_swap: t=x; x=taga(cpyC16Arr(w)); w=t; goto do_ex2; case xc16_swap: t=w; w=taga(cpyC16Arr(x)); x=t; goto do_ex2; case wc32_swap: t=x; x=taga(cpyC32Arr(w)); w=t; goto do_ex2; case xc32_swap: t=w; w=taga(cpyC32Arr(x)); x=t; goto do_ex2; case swap: t=w; w=x; x=t; goto do_ex2; do_ex2: ex = fn->ex2; goto newEx; case c_call_rbyte: { c_call_rbyte:; u64 got = fn->cFn(m_tyarrlc(&r, fn->width, x, fn->type), tyany_ptr(w), tyany_ptr(x), ia); if (got==ia) goto decG_ret; decG(r); fn++; goto newFn; } case u_call_rbyte: { fn->uFn(m_tyarrlc(&r, fn->width, x, fn->type), tyany_ptr(w), tyany_ptr(x), ia); goto decG_ret; } case e_call_rbyte: { u64 got = fn->cFn(m_tyarrlc(&r, fn->width, x, fn->type), tyany_ptr(w), tyany_ptr(x), ia); if (got) goto rec; goto decG_ret; } case u_call_bit: { u64* rp; r = m_bitarrc(&rp, x); fn->uFn(rp, tyany_ptr(w), tyany_ptr(x), ia); goto decG_ret; } case u_call_wxf64sq: { f64* rp; r = m_f64arrc(&rp, x); fn->uFn(rp, tyany_ptr(w = toF64Any(w)), tyany_ptr(x = toF64Any(x)), ia); r = num_squeeze(r); goto decG_ret; } case c_call_wxi8: { assert(TI(x,elType)==el_bit && TI(w,elType)==el_bit); w = taga(cpyI8Arr(w)); x = taga(cpyI8Arr(x)); goto c_call_rbyte; } case e_call_sqx: { assert(TI(x,elType)==el_f64); x = num_squeezeChk(x); u8 xe = TI(x,elType); if (xe==el_f64) goto rec; e = &table->entsAA[TI(w,elType)*8 + xe]; goto newEnt; } case fail: goto rec; } rec: return arith_recd(table->mainFn, w, x); decG_ret: decG(w); decG(x); return r; } 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(void* r, u64 w, void* x, u64 len) { return 0; } u64 failAtomArr2(void* r, u64 w, void* 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, }; NOINLINE B dyArith_SA(DyTableSA* table, B w, B x) { usz ia = IA(x); u8 xe = TI(x,elType); u8 width, type; // the currently supported character functions (+ and -) have the result type be character when left xor right is character, so it can be hard-coded u64 wa; EntSA* e; if (ia==0) { u8 fillVal; bool charX; if (xe!=el_B) { charX = elChr(xe); } else { B xf = getFillQ(x); if (isNum(xf)) charX=0; else if (isC32(xf)) charX=1; else if (noFill(xf)) { fillVal=0; goto fillSel; } else { dec(xf); goto rec; } // whatever } bool charW; if (isNum(w)) charW=0; else if (isC32(w)) charW=1; else goto rec; fillVal = table->fill[charW][charX]; fillSel: if (RNK(x)==1) { decG(x); if (fillVal==1) return emptyIVec(); if (fillVal==0) return emptyHVec(); assert(fillVal==2); return emptyCVec(); } else { Arr* r; if (fillVal==1) { u64* rp; r = m_bitarrp(&rp, 0); } else if (fillVal==0) { r = (Arr*) m_harrUp(0).c; } else { assert(fillVal==2); u8* rp; r = m_c8arrp (&rp, 0); } arr_shCopy(r, x); decG(x); return taga(r); } } if (!isF64(w)) { if (!isC32(w)) goto rec; DyTableSA* t2 = table->chrAtom; if (t2==NULL) goto rec; table = t2; wa = o2cG(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 (wa==(u16)wa) { type=t_c16arr; goto cpy_i16; } cwiden_i16: { type=t_c32arr; goto cpy_i32; } cwiden_c8: if (wa==(u16)wa) { 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)o2iG(w); goto f1; wf64: wa=w.u; goto f1; iwiden_i8: if (q_i16(w)) { wa=(u32)o2iG(w); type=t_i16arr; goto cpy_i16; } iwiden_i16: if (q_i32(w)) { wa=(u32)o2iG(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)o2iG(w); type=t_c16arr; goto cpy_c16; } iwiden_c16: if (q_i32(w)) { wa=(u32)o2iG(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; ChkFnSA 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], opts[1]); } } #define SINGELI_FILE dyarith #include "../../utils/includeSingeli.h" static void rootAAu_f64_f64_f64(void* r, void* w, void* x, u64 len) { for (u64 i = 0; i < len; i++) ((f64*)r)[i] = pow(((f64*)x)[i], 1.0/((f64*)w)[i]); } static void powAAu_f64_f64_f64(void* r, void* w, void* x, u64 len) { for (u64 i = 0; i < len; i++) ((f64*)r)[i] = pow(((f64*)w)[i], ((f64*)x)[i]); } static void stileAAu_f64_f64_f64(void* r, void* w, void* 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(void* r, void* w, void* x, u64 len) { for (u64 i = 0; i < len; i++) ((f64*)r)[i] = log(((f64*)x)[i])/log(((f64*)w)[i]); } bool add_forBitselNN_SA (DyTableSA* table, B w, B* r) { f64 f=o2fG(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=o2fG(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=o2fG(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=o2fG(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=o2fG(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=o2fG(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=o2cG(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=o2cG(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:; f64 wf = o2fG(w); return bit_sel(x, m_f64(bqn_or(wf, 0)), m_f64(bqn_or(wf, 1))); } x = num_squeezeChk(x); u8 xe = TI(x,elType); if (xe==el_bit) goto bitsel; if (!elNum(xe)) return arith_recd(or_c2, w, x); x = toF64Any(x); f64* rp; B r = m_f64arrc(&rp, x); usz ia = a(x)->ia; orSAc_f64_f64_f64(rp, w.u, tyany_ptr(x), ia); decG(x); return r; } #define SINGELI_FILE arTables #include "../../utils/includeSingeli.h" DyTableAA* dyTableAAFor(B f) { assert(isFun(f)); switch(v(f)->flags-1) { default: return NULL; case n_add: return &addDyTableAA; case n_sub: return &subDyTableAA; case n_mul: return &mulDyTableAA; case n_and: return &andDyTableAA; case n_or: return &orDyTableAA; case n_floor: return &floorDyTableAA; case n_ceil: return &ceilDyTableAA; } } DyTableSA* dyTableSAFor(B f, bool atomChar) { assert(isFun(f)); switch(v(f)->flags-1) { default: return NULL; case n_add: return atomChar? &addDyTableCA : &addDyTableNA; case n_sub: return atomChar? &subDyTableCA : &subDyTableNA; case n_mul: return atomChar? NULL : &mulDyTableNA; case n_and: return atomChar? NULL : &andDyTableNA; case n_floor: return atomChar? NULL : &floorDyTableNA; case n_ceil: return atomChar? NULL : &ceilDyTableNA; } } DyTableSA* dyTableASFor(B f, bool atomChar) { assert(isFun(f)); switch(v(f)->flags-1) { default: return NULL; case n_add: return atomChar? &addDyTableCA : &addDyTableNA; case n_sub: return atomChar? &subDyTableAC : &subDyTableAN; case n_mul: return atomChar? NULL : &mulDyTableNA; case n_and: return atomChar? NULL : &andDyTableNA; case n_floor: return atomChar? NULL : &floorDyTableNA; case n_ceil: return atomChar? NULL : &ceilDyTableNA; } }