CPPSPMD_FORCE_INLINE vfloat fmod_inv(const vfloat& a, const vfloat& b, const vfloat& b_inv)
{
vfloat c = frac(abs(a * b_inv)) * abs(b);
return spmd_ternaryf(a < 0, -c, c);
}
CPPSPMD_FORCE_INLINE vfloat fmod_inv_p(const vfloat& a, const vfloat& b, const vfloat& b_inv)
{
return frac(a * b_inv) * b;
}
CPPSPMD_FORCE_INLINE vfloat safe_div(vfloat a, vfloat b, float fDivThresh = 1e-7f)
{
return a / spmd_ternaryf( abs(b) > fDivThresh, b, spmd_ternaryf(b < 0.0f, -fDivThresh, fDivThresh) );
}
inline vfloat spmd_kernel::log2_est(vfloat v)
{
vfloat signif, fexp;
vfloat x = max(v, 2.2e-38f);
vint ux1_i = cast_vfloat_to_vint(x);
vint exp = VUINT_SHIFT_RIGHT(ux1_i & 0x7F800000, 23);
vint ux2_i;
vfloat ux2_f;
vint greater = ux1_i & 0x00400000; SPMD_SIF(greater != 0)
{
store_all(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f000000);
store_all(ux2_f, cast_vint_to_vfloat(ux2_i));
store_all(fexp, vfloat(exp - 126));
}
SPMD_SELSE(greater != 0)
{
store(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f800000);
store(ux2_f, cast_vint_to_vfloat(ux2_i));
store(fexp, vfloat(exp - 127));
}
SPMD_SENDIF
store_all(signif, ux2_f);
store_all(signif, signif - 1.0f);
const float a = 0.1501692f, b = 3.4226132f, c = 5.0225057f, d = 4.1130283f, e = 3.4813372f;
vfloat xm1 = signif;
vfloat xm1sqr = xm1 * xm1;
return fexp + ((a * (xm1sqr * xm1) + b * xm1sqr + c * xm1) / (xm1sqr + d * xm1 + e));
}
inline vfloat spmd_kernel::log_est(vfloat v)
{
return log2_est(v) * 0.693147181f;
}
CPPSPMD_FORCE_INLINE void spmd_kernel::reduce_expb(vfloat& arg, vfloat& two_int_a, vint& adjustment)
{
store_all(adjustment, 0);
vint int_arg = (vint)arg;
SPMD_SIF((arg - int_arg) > 0.5f)
{
store(adjustment, 1);
store(arg, arg - 0.5f);
}
SPMD_SENDIF
store_all(arg, arg - (vfloat)int_arg);
store_all(int_arg, min(int_arg + 127, 254));
store_all(two_int_a, cast_vint_to_vfloat(VINT_SHIFT_LEFT(int_arg, 23)));
}
inline vfloat spmd_kernel::exp2_est(vfloat arg)
{
SPMD_BEGIN_CALL
const vfloat P00 = +7.2152891521493f;
const vfloat P01 = +0.0576900723731f;
const vfloat Q00 = +20.8189237930062f;
const vfloat Q01 = +1.0f;
const vfloat sqrt2 = 1.4142135623730950488f;
vfloat result = 0.0f;
SPMD_IF(abs(arg) > 126.0f)
{
spmd_return();
}
SPMD_END_IF
vfloat two_int_a;
vint adjustment;
vint negative = 0;
SPMD_SIF(arg < 0.0f)
{
store(arg, -arg);
store(negative, 1);
}
SPMD_SENDIF
store_all(arg, min(arg, 126.0f));
reduce_expb(arg, two_int_a, adjustment);
vfloat Q = vfma(Q01, (arg * arg), Q00);
vfloat x_P = arg * (vfma(P01, arg * arg, P00));
vfloat answer = (Q + x_P) / (Q - x_P);
store_all(answer, answer * two_int_a);
store_all(answer, spmd_ternaryf(adjustment != 0, answer * sqrt2, answer));
SPMD_SIF(negative != 0)
{
store(answer, 1.0f / answer);
}
SPMD_SENDIF
store(result, answer);
return result;
}
inline vfloat spmd_kernel::exp_est(vfloat arg)
{
return exp2_est(arg * 1.44269504f);
}
inline vfloat spmd_kernel::pow_est(vfloat arg1, vfloat arg2)
{
return exp_est(log_est(arg1) * arg2);
}
inline vfloat spmd_kernel::sincos_est_a(vfloat a, bool sin_flag)
{
const float c0_x = 0.0f, c0_y = 0.5f, c0_z = 1.0f;
const float c1_x = 0.25f, c1_y = -9.0f, c1_z = 0.75f, c1_w = 0.159154943091f;
const float c2_x = 24.9808039603f, c2_y = -24.9808039603f, c2_z = -60.1458091736f, c2_w = 60.1458091736f;
const float c3_x = 85.4537887573f, c3_y = -85.4537887573f, c3_z = -64.9393539429f, c3_w = 64.9393539429f;
const float c4_x = 19.7392082214f, c4_y = -19.7392082214f, c4_z = -1.0f, c4_w = 1.0f;
vfloat r0_x, r0_y, r0_z, r1_x, r1_y, r1_z, r2_x, r2_y, r2_z;
store_all(r1_x, sin_flag ? vfms(c1_w, a, c1_x) : c1_w * a);
store_all(r1_y, frac(r1_x));
store_all(r2_x, (vfloat)(r1_y < c1_x));
store_all(r2_y, (vfloat)(r1_y >= c1_y));
store_all(r2_z, (vfloat)(r1_y >= c1_z));
store_all(r2_y, vfma(r2_x, c4_z, vfma(r2_y, c4_w, r2_z * c4_z)));
store_all(r0_x, c0_x - r1_y);
store_all(r0_y, c0_y - r1_y);
store_all(r0_z, c0_z - r1_y);
store_all(r0_x, r0_x * r0_x);
store_all(r0_y, r0_y * r0_y);
store_all(r0_z, r0_z * r0_z);
store_all(r1_x, vfma(c2_x, r0_x, c2_z));
store_all(r1_y, vfma(c2_y, r0_y, c2_w));
store_all(r1_z, vfma(c2_x, r0_z, c2_z));
store_all(r1_x, vfma(r1_x, r0_x, c3_x));
store_all(r1_y, vfma(r1_y, r0_y, c3_y));
store_all(r1_z, vfma(r1_z, r0_z, c3_x));
store_all(r1_x, vfma(r1_x, r0_x, c3_z));
store_all(r1_y, vfma(r1_y, r0_y, c3_w));
store_all(r1_z, vfma(r1_z, r0_z, c3_z));
store_all(r1_x, vfma(r1_x, r0_x, c4_x));
store_all(r1_y, vfma(r1_y, r0_y, c4_y));
store_all(r1_z, vfma(r1_z, r0_z, c4_x));
store_all(r1_x, vfma(r1_x, r0_x, c4_z));
store_all(r1_y, vfma(r1_y, r0_y, c4_w));
store_all(r1_z, vfma(r1_z, r0_z, c4_z));
store_all(r0_x, vfnma(r1_x, r2_x, vfnma(r1_y, r2_y, r1_z * -r2_z)));
return r0_x;
}
CPPSPMD_FORCE_INLINE vfloat spmd_kernel::recip_est1(const vfloat& q)
{
const int mag = 0x7EF311C3;
const float fMinThresh = .0000125f;
vfloat l = spmd_ternaryf(q >= fMinThresh, q, cast_vint_to_vfloat(vint(mag)));
vint x_l = vint(mag) - cast_vfloat_to_vint(l);
vfloat rcp_l = cast_vint_to_vfloat(x_l);
return rcp_l * vfnma(rcp_l, q, 2.0f);
}
CPPSPMD_FORCE_INLINE vfloat spmd_kernel::recip_est1_pn(const vfloat& t)
{
const int mag = 0x7EF311C3;
const float fMinThresh = .0000125f;
vfloat s = sign(t);
vfloat q = abs(t);
vfloat l = spmd_ternaryf(q >= fMinThresh, q, cast_vint_to_vfloat(vint(mag)));
vint x_l = vint(mag) - cast_vfloat_to_vint(l);
vfloat rcp_l = cast_vint_to_vfloat(x_l);
return rcp_l * vfnma(rcp_l, q, 2.0f) * s;
}
CPPSPMD_FORCE_INLINE vfloat spmd_kernel::rsqrt_est1(vfloat x0)
{
vfloat xhalf = 0.5f * x0;
vfloat x = cast_vint_to_vfloat(vint(0x5F375A82) - (VINT_SHIFT_RIGHT(cast_vfloat_to_vint(x0), 1)));
return x * vfnma(xhalf * x, x, 1.5008909f);
}
CPPSPMD_FORCE_INLINE vfloat spmd_kernel::rsqrt_est2(vfloat x0)
{
vfloat xhalf = 0.5f * x0;
vfloat x = cast_vint_to_vfloat(vint(0x5F37599E) - (VINT_SHIFT_RIGHT(cast_vfloat_to_vint(x0), 1)));
vfloat x1 = x * vfnma(xhalf * x, x, 1.5);
vfloat x2 = x1 * vfnma(xhalf * x1, x1, 1.5);
return x2;
}
CPPSPMD_FORCE_INLINE vfloat spmd_kernel::atan2_est(vfloat y, vfloat x)
{
vfloat t1 = abs(y);
vfloat t3 = abs(x);
vfloat t0 = max(t3, t1);
store_all(t1, min(t3, t1));
store_all(t3, t1 / t0);
vfloat t4 = t3 * t3;
store_all(t0, vfma(-0.013480470f, t4, 0.057477314f));
store_all(t0, vfms(t0, t4, 0.121239071f));
store_all(t0, vfma(t0, t4, 0.195635925f));
store_all(t0, vfms(t0, t4, 0.332994597f));
store_all(t0, vfma(t0, t4, 0.999995630f));
store_all(t3, t0 * t3);
store_all(t3, spmd_ternaryf(abs(y) > abs(x), vfloat(1.570796327f) - t3, t3));
store_all(t3, spmd_ternaryf(x < 0.0f, vfloat(3.141592654f) - t3, t3));
store_all(t3, spmd_ternaryf(y < 0.0f, -t3, t3));
return t3;
}
CPPSPMD_FORCE_INLINE vfloat spmd_kernel::tan82(vfloat x)
{
const float c1 = 211.849350f, c2 = -12.5288887f, c3 = 269.734985f, c4 = -71.4145203f;
vfloat x2 = x * x;
return (x * (vfma(c2, x2, c1)) / (vfma(x2, (c4 + x2), c3)));
}
inline vfloat spmd_kernel::tan_est(vfloat x)
{
const float fPi = 3.141592653589793f, fOneOverPi = 0.3183098861837907f;
CPPSPMD_DECL(const uint8_t, s_table0[16]) = { 128 + 0, 128 + 2, 128 + -2, 128 + 4, 128 + 0, 128 + 2, 128 + -2, 128 + 4, 128 + 0, 128 + 2, 128 + -2, 128 + 4, 128 + 0, 128 + 2, 128 + -2, 128 + 4 };
vint table = init_lookup4(s_table0); vint sgn = cast_vfloat_to_vint(x) & 0x80000000;
store_all(x, abs(x));
vfloat orig_x = x;
vfloat q = x * fOneOverPi;
store_all(x, q - floor(q));
vfloat x4 = x * 4.0f;
vint octant = (vint)(x4);
vfloat x0 = spmd_ternaryf((octant & 1) != 0, -x4, x4);
vint k = table_lookup4_8(octant, table) & 0xFF;
vfloat bias = (vfloat)k + -128.0f;
vfloat y = x0 + bias;
vfloat z = tan82(y);
vfloat r;
vbool octant_one_or_two = (octant == 1) || (octant == 2);
if (spmd_any(octant_one_or_two))
{
const float fDivThresh = .4371e-7f;
vfloat one_over_z = 1.0f / spmd_ternaryf(abs(z) > fDivThresh, z, spmd_ternaryf(z < 0.0f, -fDivThresh, fDivThresh));
vfloat b = spmd_ternaryf(octant_one_or_two, one_over_z, z);
store_all(r, spmd_ternaryf((octant & 2) != 0, -b, b));
}
else
{
store_all(r, spmd_ternaryf(octant == 0, z, -z));
}
SPMD_SIF(x >= (1.0f - .0003125f*4.0f))
{
store(r, vfnma(floor(q) + 1.0f, fPi, orig_x));
}
SPMD_SENDIF
return cast_vint_to_vfloat(cast_vfloat_to_vint(r) ^ sgn);
}
inline void spmd_kernel::seed_rand(rand_context& x, vint seed)
{
store(x.a, 0xf1ea5eed);
store(x.b, seed ^ 0xd8487b1f);
store(x.c, seed ^ 0xdbadef9a);
store(x.d, seed);
for (int i = 0; i < 20; ++i)
(void)get_randu(x);
}
inline vint spmd_kernel::get_randu(rand_context& x)
{
vint e = x.a - VINT_ROT(x.b, 27);
store(x.a, x.b ^ VINT_ROT(x.c, 17));
store(x.b, x.c + x.d);
store(x.c, x.d + e);
store(x.d, e + x.a);
return x.d;
}
inline vint spmd_kernel::get_randi(rand_context& x, vint low, vint high)
{
vint rnd = get_randu(x);
vint range = high - low;
vint rnd_range = mulhiu(rnd, range);
return spmd_ternaryi(low < high, low + rnd_range, low);
}
inline vfloat spmd_kernel::get_randf(rand_context& x, vfloat low, vfloat high)
{
vint rndi = get_randu(x) & 0x7fffff;
vfloat rnd = (vfloat)(rndi) * (1.0f / 8388608.0f);
return spmd_ternaryf(low < high, vfma(high - low, rnd, low), low);
}
CPPSPMD_FORCE_INLINE void spmd_kernel::init_reverse_bits(vint& tab1, vint& tab2)
{
const uint8_t tab1_bytes[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
const uint8_t tab2_bytes[16] = { 0, 8 << 4, 4 << 4, 12 << 4, 2 << 4, 10 << 4, 6 << 4, 14 << 4, 1 << 4, 9 << 4, 5 << 4, 13 << 4, 3 << 4, 11 << 4, 7 << 4, 15 << 4 };
store_all(tab1, init_lookup4(tab1_bytes));
store_all(tab2, init_lookup4(tab2_bytes));
}
CPPSPMD_FORCE_INLINE vint spmd_kernel::reverse_bits(vint k, vint tab1, vint tab2)
{
vint r0 = table_lookup4_8(k & 0x7F7F7F7F, tab2);
vint r1 = table_lookup4_8(VUINT_SHIFT_RIGHT(k, 4) & 0x7F7F7F7F, tab1);
vint r3 = r0 | r1;
return byteswap(r3);
}
CPPSPMD_FORCE_INLINE vint spmd_kernel::count_leading_zeros(vint x)
{
CPPSPMD_DECL(const uint8_t, s_tab[16]) = { 0, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
vint tab = init_lookup4(s_tab);
vbool c0 = (x & 0xFFFF0000) == 0;
vint n0 = spmd_ternaryi(c0, 16, 0);
vint x0 = spmd_ternaryi(c0, VINT_SHIFT_LEFT(x, 16), x);
vbool c1 = (x0 & 0xFF000000) == 0;
vint n1 = spmd_ternaryi(c1, n0 + 8, n0);
vint x1 = spmd_ternaryi(c1, VINT_SHIFT_LEFT(x0, 8), x0);
vbool c2 = (x1 & 0xF0000000) == 0;
vint n2 = spmd_ternaryi(c2, n1 + 4, n1);
vint x2 = spmd_ternaryi(c2, VINT_SHIFT_LEFT(x1, 4), x1);
return table_lookup4_8(VUINT_SHIFT_RIGHT(x2, 28), tab) + n2;
}
CPPSPMD_FORCE_INLINE vint spmd_kernel::count_leading_zeros_alt(vint x)
{
vbool c0 = (x & 0xFFFF0000) == 0;
vint n0 = spmd_ternaryi(c0, 16, 0);
vint x0 = spmd_ternaryi(c0, VINT_SHIFT_LEFT(x, 16), x);
vbool c1 = (x0 & 0xFF000000) == 0;
vint n1 = spmd_ternaryi(c1, n0 + 8, n0);
vint x1 = spmd_ternaryi(c1, VINT_SHIFT_LEFT(x0, 8), x0);
vbool c2 = (x1 & 0xF0000000) == 0;
vint n2 = spmd_ternaryi(c2, n1 + 4, n1);
vint x2 = spmd_ternaryi(c2, VINT_SHIFT_LEFT(x1, 4), x1);
vbool c3 = (x2 & 0xC0000000) == 0;
vint n3 = spmd_ternaryi(c3, n2 + 2, n2);
vint x3 = spmd_ternaryi(c3, VINT_SHIFT_LEFT(x2, 2), x2);
vbool c4 = (x3 & 0x80000000) == 0;
return spmd_ternaryi(c4, n3 + 1, n3);
}
CPPSPMD_FORCE_INLINE vint spmd_kernel::count_trailing_zeros(vint x)
{
vfloat f = (vfloat)(x & -x);
return VUINT_SHIFT_RIGHT(cast_vfloat_to_vint(f), 23) - 0x7F;
}
CPPSPMD_FORCE_INLINE vint spmd_kernel::count_set_bits(vint x)
{
vint v = x - (VUINT_SHIFT_RIGHT(x, 1) & 0x55555555);
vint v1 = (v & 0x33333333) + (VUINT_SHIFT_RIGHT(v, 2) & 0x33333333);
return VUINT_SHIFT_RIGHT(((v1 + VUINT_SHIFT_RIGHT(v1, 4) & 0xF0F0F0F) * 0x1010101), 24);
}
CPPSPMD_FORCE_INLINE vint cmple_epu16(const vint &a, const vint &b)
{
return cmpeq_epi16(subs_epu16(a, b), vint(0));
}
CPPSPMD_FORCE_INLINE vint cmpge_epu16(const vint &a, const vint &b)
{
return cmple_epu16(b, a);
}
CPPSPMD_FORCE_INLINE vint cmpgt_epu16(const vint &a, const vint &b)
{
return andnot(cmpeq_epi16(a, b), cmple_epu16(b, a));
}
CPPSPMD_FORCE_INLINE vint cmplt_epu16(const vint &a, const vint &b)
{
return cmpgt_epu16(b, a);
}
CPPSPMD_FORCE_INLINE vint cmpge_epi16(const vint &a, const vint &b)
{
return cmpeq_epi16(a, b) | cmpgt_epi16(a, b);
}
CPPSPMD_FORCE_INLINE vint cmple_epi16(const vint &a, const vint &b)
{
return cmpge_epi16(b, a);
}
void spmd_kernel::print_vint(vint v)
{
for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
printf("%i ", extract(v, i));
printf("\n");
}
void spmd_kernel::print_vbool(vbool v)
{
for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
printf("%i ", extract(v, i) ? 1 : 0);
printf("\n");
}
void spmd_kernel::print_vint_hex(vint v)
{
for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
printf("0x%X ", extract(v, i));
printf("\n");
}
void spmd_kernel::print_active_lanes(const char *pPrefix)
{
CPPSPMD_DECL(int, flags[PROGRAM_COUNT]);
memset(flags, 0, sizeof(flags));
storeu_linear(flags, vint(1));
if (pPrefix)
printf("%s", pPrefix);
for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
{
if (flags[i])
printf("%u ", i);
}
printf("\n");
}
void spmd_kernel::print_vfloat(vfloat v)
{
for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
printf("%f ", extract(v, i));
printf("\n");
}