use super::high_fidelity::scalar_tanh_poly;
use crate::math::activations::sigmoid::high_fidelity_avx512::simd_sigmoid_poly_avx512;
use crate::math::constants::*;
use core::arch::x86_64::*;
#[inline]
#[target_feature(enable = "avx512f,avx512vl")]
unsafe fn simd_exp_poly_avx512(x: __m512) -> __m512 {
let log2e = _mm512_set1_ps(POLY_LOG2_E);
let ln2 = _mm512_set1_ps(POLY_LN2);
let c6 = _mm512_set1_ps(POLY_EXP_C6);
let c5 = _mm512_set1_ps(POLY_EXP_C5);
let c4 = _mm512_set1_ps(POLY_EXP_C4);
let c3 = _mm512_set1_ps(POLY_EXP_C3);
let c2 = _mm512_set1_ps(POLY_EXP_C2);
let one = _mm512_set1_ps(1.0f32);
let bias = _mm512_set1_epi32(127);
let k_f = _mm512_roundscale_ps(
_mm512_mul_ps(x, log2e),
_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC,
);
let r = _mm512_fnmadd_ps(k_f, ln2, x);
let p = _mm512_fmadd_ps(c6, r, c5);
let p = _mm512_fmadd_ps(p, r, c4);
let p = _mm512_fmadd_ps(p, r, c3);
let p = _mm512_fmadd_ps(p, r, c2);
let p = _mm512_fmadd_ps(p, r, one);
let p = _mm512_fmadd_ps(p, r, one);
let k_i = _mm512_cvtps_epi32(k_f);
let exp_bits = _mm512_slli_epi32(_mm512_add_epi32(k_i, bias), 23);
let scale = _mm512_castsi512_ps(exp_bits);
_mm512_mul_ps(p, scale)
}
#[inline]
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn simd_tanh_poly_avx512(x: __m512) -> __m512 {
let clamp_lo = _mm512_set1_ps(-POLY_ACTIVATION_CLAMP);
let clamp_hi = _mm512_set1_ps(POLY_ACTIVATION_CLAMP);
let one = _mm512_set1_ps(1.0f32);
let neg_one = _mm512_set1_ps(-1.0f32);
let x = _mm512_max_ps(clamp_lo, _mm512_min_ps(clamp_hi, x));
let exp_x = unsafe { simd_exp_poly_avx512(x) };
let u2 = _mm512_mul_ps(exp_x, exp_x); let num = _mm512_sub_ps(u2, one); let den = _mm512_add_ps(u2, one); let tanh_val = _mm512_div_ps(num, den);
_mm512_max_ps(neg_one, _mm512_min_ps(one, tanh_val))
}
#[inline]
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn simd_tanh_sigmoid_dual_poly_avx512(x1: __m512, x2: __m512) -> (__m512, __m512) {
let t1 = unsafe { simd_tanh_poly_avx512(x1) };
let s2 = unsafe { simd_sigmoid_poly_avx512(x2) };
(t1, s2)
}
#[inline]
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn simd_tanh_poly_nr1_avx512(x: __m512) -> __m512 {
let clamp_lo = _mm512_set1_ps(-POLY_ACTIVATION_CLAMP);
let clamp_hi = _mm512_set1_ps(POLY_ACTIVATION_CLAMP);
let one = _mm512_set1_ps(1.0f32);
let neg_one = _mm512_set1_ps(-1.0f32);
let two = _mm512_set1_ps(2.0f32);
let x = _mm512_max_ps(clamp_lo, _mm512_min_ps(clamp_hi, x));
let exp_x = unsafe { simd_exp_poly_avx512(x) };
let u2 = _mm512_mul_ps(exp_x, exp_x);
let num = _mm512_sub_ps(u2, one);
let den = _mm512_add_ps(u2, one);
let mut r = _mm512_rcp14_ps(den);
r = _mm512_mul_ps(r, _mm512_fnmadd_ps(den, r, two));
let tanh_val = _mm512_mul_ps(num, r);
_mm512_max_ps(neg_one, _mm512_min_ps(one, tanh_val))
}
#[inline]
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn simd_tanh_poly_nr2_avx512(x: __m512) -> __m512 {
let clamp_lo = _mm512_set1_ps(-POLY_ACTIVATION_CLAMP);
let clamp_hi = _mm512_set1_ps(POLY_ACTIVATION_CLAMP);
let one = _mm512_set1_ps(1.0f32);
let neg_one = _mm512_set1_ps(-1.0f32);
let two = _mm512_set1_ps(2.0f32);
let x = _mm512_max_ps(clamp_lo, _mm512_min_ps(clamp_hi, x));
let exp_x = unsafe { simd_exp_poly_avx512(x) };
let u2 = _mm512_mul_ps(exp_x, exp_x);
let num = _mm512_sub_ps(u2, one);
let den = _mm512_add_ps(u2, one);
let mut r = _mm512_rcp14_ps(den);
r = _mm512_mul_ps(r, _mm512_fnmadd_ps(den, r, two));
r = _mm512_mul_ps(r, _mm512_fnmadd_ps(den, r, two));
let tanh_val = _mm512_mul_ps(num, r);
_mm512_max_ps(neg_one, _mm512_min_ps(one, tanh_val))
}
#[inline]
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn tanh_poly_slice_avx512(slice: &mut [f32]) {
let mut i = 0;
let len = slice.len();
unsafe {
crate::activation_simd_avx512!(i, len, {
let x = _mm512_loadu_ps(slice.as_ptr().add(i));
let y = simd_tanh_poly_avx512(x);
_mm512_storeu_ps(slice.as_mut_ptr().add(i), y);
});
}
for item in slice.iter_mut().skip(i) {
*item = scalar_tanh_poly(*item);
}
}