uCBQN/src/singeli/c/arithdDispatch.c
2023-11-23 18:13:51 +02:00

342 lines
13 KiB
C

#include "../../core.h"
#include "../../utils/each.h"
#include "../../builtins.h"
#include "arithdDispatch.h"
#include <math.h>
#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=wr<xr?wr:xr;
if (IA(w)==0 || IA(x)==0) goto rec;
if (!eqShPart(wsh, xsh, mr)) goto rec;
return leading_axis_arith(table->mainFn, 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;
}
}