use crate::types::*;
use core::arch::aarch64::*;
#[inline]
pub fn _mm_add_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vaddq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_sub_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vsubq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_mul_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vmulq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_div_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vdivq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_add_ss(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, _mm_add_ps(a, b))
}
#[inline]
pub fn _mm_sub_ss(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, _mm_sub_ps(a, b))
}
#[inline]
pub fn _mm_mul_ss(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, _mm_mul_ps(a, b))
}
#[inline]
pub fn _mm_div_ss(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, _mm_div_ps(a, b))
}
#[inline]
pub fn _mm_and_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vandq_u32(a.u32(), b.u32()) })
}
#[inline]
pub fn _mm_or_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vorrq_u32(a.u32(), b.u32()) })
}
#[inline]
pub fn _mm_xor_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { veorq_u32(a.u32(), b.u32()) })
}
#[inline]
pub fn _mm_andnot_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vbicq_u32(b.u32(), a.u32()) })
}
#[inline]
pub fn _mm_cmpeq_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vceqq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_cmpge_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vcgeq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_cmpgt_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vcgtq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_cmple_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vcleq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_cmplt_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vcltq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_cmpneq_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vmvnq_u32(vceqq_f32(a.f32(), b.f32())) })
}
#[inline]
pub fn _mm_cmpnge_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vmvnq_u32(vcgeq_f32(a.f32(), b.f32())) })
}
#[inline]
pub fn _mm_cmpngt_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vmvnq_u32(vcgtq_f32(a.f32(), b.f32())) })
}
#[inline]
pub fn _mm_cmpnle_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vmvnq_u32(vcleq_f32(a.f32(), b.f32())) })
}
#[inline]
pub fn _mm_cmpnlt_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_u32(unsafe { vmvnq_u32(vcltq_f32(a.f32(), b.f32())) })
}
#[inline]
pub fn _mm_cmpord_ps(a: __m128, b: __m128) -> __m128 {
unsafe {
let a_ord = vceqq_f32(a.f32(), a.f32());
let b_ord = vceqq_f32(b.f32(), b.f32());
__m128::from_u32(vandq_u32(a_ord, b_ord))
}
}
#[inline]
pub fn _mm_cmpunord_ps(a: __m128, b: __m128) -> __m128 {
unsafe {
let a_ord = vceqq_f32(a.f32(), a.f32());
let b_ord = vceqq_f32(b.f32(), b.f32());
__m128::from_u32(vmvnq_u32(vandq_u32(a_ord, b_ord)))
}
}
macro_rules! ss_cmp {
($name:ident, $full:ident, $doc:literal) => {
#[doc = $doc]
#[inline]
pub fn $name(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, $full(a, b))
}
};
}
ss_cmp!(
_mm_cmpeq_ss,
_mm_cmpeq_ps,
"Scalar `==` on lane 0. Matches `_mm_cmpeq_ss`."
);
ss_cmp!(
_mm_cmpge_ss,
_mm_cmpge_ps,
"Scalar `>=` on lane 0. Matches `_mm_cmpge_ss`."
);
ss_cmp!(
_mm_cmpgt_ss,
_mm_cmpgt_ps,
"Scalar `>` on lane 0. Matches `_mm_cmpgt_ss`."
);
ss_cmp!(
_mm_cmple_ss,
_mm_cmple_ps,
"Scalar `<=` on lane 0. Matches `_mm_cmple_ss`."
);
ss_cmp!(
_mm_cmplt_ss,
_mm_cmplt_ps,
"Scalar `<` on lane 0. Matches `_mm_cmplt_ss`."
);
ss_cmp!(
_mm_cmpneq_ss,
_mm_cmpneq_ps,
"Scalar `!=` on lane 0. Matches `_mm_cmpneq_ss`."
);
ss_cmp!(
_mm_cmpnge_ss,
_mm_cmpnge_ps,
"Scalar `!(>=)` on lane 0. Matches `_mm_cmpnge_ss`."
);
ss_cmp!(
_mm_cmpngt_ss,
_mm_cmpngt_ps,
"Scalar `!(>)` on lane 0. Matches `_mm_cmpngt_ss`."
);
ss_cmp!(
_mm_cmpnle_ss,
_mm_cmpnle_ps,
"Scalar `!(<=)` on lane 0. Matches `_mm_cmpnle_ss`."
);
ss_cmp!(
_mm_cmpnlt_ss,
_mm_cmpnlt_ps,
"Scalar `!(<)` on lane 0. Matches `_mm_cmpnlt_ss`."
);
ss_cmp!(
_mm_cmpord_ss,
_mm_cmpord_ps,
"Scalar ordered test on lane 0. Matches `_mm_cmpord_ss`."
);
ss_cmp!(
_mm_cmpunord_ss,
_mm_cmpunord_ps,
"Scalar unordered test on lane 0. Matches `_mm_cmpunord_ss`."
);
#[inline]
pub fn _mm_comieq_ss(a: __m128, b: __m128) -> i32 {
let x = _mm_cvtss_f32(a);
let y = _mm_cvtss_f32(b);
i32::from(x == y)
}
#[inline]
pub fn _mm_comige_ss(a: __m128, b: __m128) -> i32 {
i32::from(_mm_cvtss_f32(a) >= _mm_cvtss_f32(b))
}
#[inline]
pub fn _mm_comigt_ss(a: __m128, b: __m128) -> i32 {
i32::from(_mm_cvtss_f32(a) > _mm_cvtss_f32(b))
}
#[inline]
pub fn _mm_comile_ss(a: __m128, b: __m128) -> i32 {
i32::from(_mm_cvtss_f32(a) <= _mm_cvtss_f32(b))
}
#[inline]
pub fn _mm_comilt_ss(a: __m128, b: __m128) -> i32 {
i32::from(_mm_cvtss_f32(a) < _mm_cvtss_f32(b))
}
#[inline]
pub fn _mm_comineq_ss(a: __m128, b: __m128) -> i32 {
i32::from(_mm_cvtss_f32(a) != _mm_cvtss_f32(b))
}
#[inline]
pub fn _mm_ucomieq_ss(a: __m128, b: __m128) -> i32 {
_mm_comieq_ss(a, b)
}
#[inline]
pub fn _mm_ucomige_ss(a: __m128, b: __m128) -> i32 {
_mm_comige_ss(a, b)
}
#[inline]
pub fn _mm_ucomigt_ss(a: __m128, b: __m128) -> i32 {
_mm_comigt_ss(a, b)
}
#[inline]
pub fn _mm_ucomile_ss(a: __m128, b: __m128) -> i32 {
_mm_comile_ss(a, b)
}
#[inline]
pub fn _mm_ucomilt_ss(a: __m128, b: __m128) -> i32 {
_mm_comilt_ss(a, b)
}
#[inline]
pub fn _mm_ucomineq_ss(a: __m128, b: __m128) -> i32 {
_mm_comineq_ss(a, b)
}
#[inline]
pub fn _mm_max_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vmaxq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_min_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vminq_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_max_ss(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, _mm_max_ps(a, b))
}
#[inline]
pub fn _mm_min_ss(a: __m128, b: __m128) -> __m128 {
_mm_move_ss(a, _mm_min_ps(a, b))
}
#[inline]
pub fn _mm_move_ss(a: __m128, b: __m128) -> __m128 {
unsafe {
let lane0 = vgetq_lane_f32(b.f32(), 0);
__m128::from_f32(vsetq_lane_f32(lane0, a.f32(), 0))
}
}
#[inline]
pub fn _mm_movehl_ps(a: __m128, b: __m128) -> __m128 {
unsafe {
let a_hi = vget_high_f32(a.f32());
let b_hi = vget_high_f32(b.f32());
__m128::from_f32(vcombine_f32(b_hi, a_hi))
}
}
#[inline]
pub fn _mm_movelh_ps(a: __m128, b: __m128) -> __m128 {
unsafe {
let a_lo = vget_low_f32(a.f32());
let b_lo = vget_low_f32(b.f32());
__m128::from_f32(vcombine_f32(a_lo, b_lo))
}
}
#[inline]
pub fn _mm_unpackhi_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vzip2q_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_unpacklo_ps(a: __m128, b: __m128) -> __m128 {
__m128::from_f32(unsafe { vzip1q_f32(a.f32(), b.f32()) })
}
#[inline]
pub fn _mm_shuffle_ps<const IMM: i32>(a: __m128, b: __m128) -> __m128 {
const { assert!(IMM >= 0 && IMM < 256, "IMM must be in 0..256") };
let mut out = [0.0f32; 4];
let av = to_f32_array(a);
let bv = to_f32_array(b);
out[0] = av[(IMM & 0x3) as usize];
out[1] = av[((IMM >> 2) & 0x3) as usize];
out[2] = bv[((IMM >> 4) & 0x3) as usize];
out[3] = bv[((IMM >> 6) & 0x3) as usize];
__m128::from_f32(unsafe { vld1q_f32(out.as_ptr()) })
}
#[inline]
fn to_f32_array(a: __m128) -> [f32; 4] {
let mut out = [0.0f32; 4];
unsafe { vst1q_f32(out.as_mut_ptr(), a.f32()) };
out
}
#[inline]
pub fn _mm_movemask_ps(a: __m128) -> i32 {
unsafe {
let signs = vshrq_n_u32::<31>(a.u32());
let weights: uint32x4_t = {
let w = [1u32, 2, 4, 8];
vld1q_u32(w.as_ptr())
};
vaddvq_u32(vmulq_u32(signs, weights)) as i32
}
}
#[inline]
pub fn _mm_rcp_ps(a: __m128) -> __m128 {
unsafe {
let x = a.f32();
let mut e = vrecpeq_f32(x);
e = vmulq_f32(vrecpsq_f32(x, e), e);
__m128::from_f32(e)
}
}
#[inline]
pub fn _mm_rcp_ss(a: __m128) -> __m128 {
_mm_move_ss(a, _mm_rcp_ps(a))
}
#[inline]
pub fn _mm_rsqrt_ps(a: __m128) -> __m128 {
unsafe {
let x = a.f32();
let mut e = vrsqrteq_f32(x);
e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x, e), e), e);
let is_zero = vceqq_f32(x, vdupq_n_f32(0.0));
let sign = vandq_u32(a.u32(), vdupq_n_u32(0x8000_0000));
let inf = vorrq_u32(sign, vdupq_n_u32(0x7f80_0000));
let fixed = vbslq_u32(is_zero, inf, vreinterpretq_u32_f32(e));
__m128::from_u32(fixed)
}
}
#[inline]
pub fn _mm_rsqrt_ss(a: __m128) -> __m128 {
_mm_move_ss(a, _mm_rsqrt_ps(a))
}
#[inline]
pub fn _mm_sqrt_ps(a: __m128) -> __m128 {
__m128::from_f32(unsafe { vsqrtq_f32(a.f32()) })
}
#[inline]
pub fn _mm_sqrt_ss(a: __m128) -> __m128 {
_mm_move_ss(a, _mm_sqrt_ps(a))
}
#[inline]
pub fn _mm_set1_ps(w: f32) -> __m128 {
__m128::from_f32(unsafe { vdupq_n_f32(w) })
}
#[inline]
pub fn _mm_set_ps1(w: f32) -> __m128 {
_mm_set1_ps(w)
}
#[inline]
pub fn _mm_set_ps(w: f32, z: f32, y: f32, x: f32) -> __m128 {
let data = [x, y, z, w];
__m128::from_f32(unsafe { vld1q_f32(data.as_ptr()) })
}
#[inline]
pub fn _mm_setr_ps(w: f32, z: f32, y: f32, x: f32) -> __m128 {
let data = [w, z, y, x];
__m128::from_f32(unsafe { vld1q_f32(data.as_ptr()) })
}
#[inline]
pub fn _mm_set_ss(w: f32) -> __m128 {
let data = [w, 0.0, 0.0, 0.0];
__m128::from_f32(unsafe { vld1q_f32(data.as_ptr()) })
}
#[inline]
pub fn _mm_setzero_ps() -> __m128 {
__m128::from_f32(unsafe { vdupq_n_f32(0.0) })
}
#[inline]
pub fn _mm_cvtss_f32(a: __m128) -> f32 {
unsafe { vgetq_lane_f32(a.f32(), 0) }
}
#[inline]
pub unsafe fn _mm_load_ps(p: *const f32) -> __m128 {
__m128::from_f32(vld1q_f32(p))
}
#[inline]
pub unsafe fn _mm_loadu_ps(p: *const f32) -> __m128 {
__m128::from_f32(vld1q_f32(p))
}
#[inline]
pub unsafe fn _mm_load1_ps(p: *const f32) -> __m128 {
__m128::from_f32(vld1q_dup_f32(p))
}
#[inline]
pub unsafe fn _mm_load_ps1(p: *const f32) -> __m128 {
_mm_load1_ps(p)
}
#[inline]
pub unsafe fn _mm_load_ss(p: *const f32) -> __m128 {
__m128::from_f32(vsetq_lane_f32(*p, vdupq_n_f32(0.0), 0))
}
#[inline]
pub unsafe fn _mm_store_ps(p: *mut f32, a: __m128) {
vst1q_f32(p, a.f32());
}
#[inline]
pub unsafe fn _mm_storeu_ps(p: *mut f32, a: __m128) {
vst1q_f32(p, a.f32());
}
#[inline]
pub unsafe fn _mm_store_ss(p: *mut f32, a: __m128) {
*p = _mm_cvtss_f32(a);
}