use std::arch::aarch64::*;
pub fn neon_quantize(coeffs_in: &[i16; 64], quant: &[u16; 64], coeffs_out: &mut [i16; 64]) {
unsafe {
neon_quantize_core(coeffs_in.as_ptr(), quant.as_ptr(), coeffs_out.as_mut_ptr());
}
}
#[target_feature(enable = "neon")]
unsafe fn neon_quantize_core(coeffs_ptr: *const i16, quant_ptr: *const u16, out_ptr: *mut i16) {
for i in (0..64).step_by(8) {
let coeffs: int16x8_t = vld1q_s16(coeffs_ptr.add(i));
let quant: uint16x8_t = vld1q_u16(quant_ptr.add(i));
let sign: int16x8_t = vshrq_n_s16::<15>(coeffs);
let abs_coeffs: int16x8_t = vabsq_s16(coeffs);
let abs_coeffs_u: uint16x8_t = vreinterpretq_u16_s16(abs_coeffs);
let half_quant: uint16x8_t = vshrq_n_u16::<1>(quant);
let rounded: uint16x8_t = vaddq_u16(abs_coeffs_u, half_quant);
let rounded_lo: uint32x4_t = vmovl_u16(vget_low_u16(rounded));
let rounded_hi: uint32x4_t = vmovl_u16(vget_high_u16(rounded));
let quant_lo: uint32x4_t = vmovl_u16(vget_low_u16(quant));
let quant_hi: uint32x4_t = vmovl_u16(vget_high_u16(quant));
let mut div_lo: [u32; 4] = [0; 4];
let mut div_hi: [u32; 4] = [0; 4];
let mut r_lo: [u32; 4] = [0; 4];
let mut r_hi: [u32; 4] = [0; 4];
let mut q_lo: [u32; 4] = [0; 4];
let mut q_hi: [u32; 4] = [0; 4];
vst1q_u32(r_lo.as_mut_ptr(), rounded_lo);
vst1q_u32(r_hi.as_mut_ptr(), rounded_hi);
vst1q_u32(q_lo.as_mut_ptr(), quant_lo);
vst1q_u32(q_hi.as_mut_ptr(), quant_hi);
for j in 0..4 {
div_lo[j] = r_lo[j] / q_lo[j];
div_hi[j] = r_hi[j] / q_hi[j];
}
let result_lo: uint32x4_t = vld1q_u32(div_lo.as_ptr());
let result_hi: uint32x4_t = vld1q_u32(div_hi.as_ptr());
let result_u16: uint16x8_t = vcombine_u16(vmovn_u32(result_lo), vmovn_u32(result_hi));
let result_s16: int16x8_t = vreinterpretq_s16_u16(result_u16);
let signed_result: int16x8_t = vsubq_s16(veorq_s16(result_s16, sign), sign);
vst1q_s16(out_ptr.add(i), signed_result);
}
}