#[allow(unused_imports)]
use crate::simd::simd_max_f32;
#[inline]
pub fn simd_argmax_f32(x: &[f32]) -> (usize, f32) {
if x.is_empty() {
return (0, f32::NEG_INFINITY);
}
#[cfg(target_arch = "aarch64")]
{
unsafe { neon_argmax_f32(x) }
}
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
{
unsafe { wasm32_simd128_argmax_f32(x) }
}
#[cfg(not(any(
target_arch = "aarch64",
all(target_arch = "wasm32", target_feature = "simd128")
)))]
{
let max_val = simd_max_f32(x);
let idx = x.iter().position(|&v| v == max_val).unwrap_or(0);
(idx, max_val)
}
}
#[cfg(target_arch = "aarch64")]
#[inline]
unsafe fn neon_argmax_f32(x: &[f32]) -> (usize, f32) {
use core::arch::aarch64::{
vaddq_u32, vbslq_u32, vcgtq_f32, vdupq_n_u32, vld1q_f32, vld1q_u32, vmaxq_f32, vst1q_f32,
vst1q_u32,
};
unsafe {
let n = x.len();
if n < 4 {
let mut bi = 0usize;
let mut bv = *x.get_unchecked(0);
for i in 1..n {
let v = *x.get_unchecked(i);
if v > bv {
bv = v;
bi = i;
}
}
return (bi, bv);
}
let base: [u32; 4] = [0, 1, 2, 3];
let four = vdupq_n_u32(4);
let mut vmax = vld1q_f32(x.as_ptr());
let mut vidx = vld1q_u32(base.as_ptr());
let mut cur = vaddq_u32(vidx, four); let chunks = n / 4;
let mut i = 4;
for _ in 1..chunks {
let v = vld1q_f32(x.as_ptr().add(i));
let mask = vcgtq_f32(v, vmax); vmax = vmaxq_f32(vmax, v);
vidx = vbslq_u32(mask, cur, vidx); cur = vaddq_u32(cur, four);
i += 4;
}
let mut vals = [0f32; 4];
let mut idxs = [0u32; 4];
vst1q_f32(vals.as_mut_ptr(), vmax);
vst1q_u32(idxs.as_mut_ptr(), vidx);
let mut bv = vals[0];
let mut bi = idxs[0] as usize;
for l in 1..4 {
let vi = idxs[l] as usize;
if vals[l] > bv || (vals[l] == bv && vi < bi) {
bv = vals[l];
bi = vi;
}
}
while i < n {
let v = *x.get_unchecked(i);
if v > bv {
bv = v;
bi = i;
}
i += 1;
}
(bi, bv)
}
}
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
#[inline]
unsafe fn wasm32_simd128_argmax_f32(x: &[f32]) -> (usize, f32) {
use core::arch::wasm32::{
f32x4_extract_lane, f32x4_gt, f32x4_max, i32x4_add, i32x4_extract_lane, i32x4_splat,
v128_bitselect, v128_load,
};
unsafe {
let n = x.len();
if n < 4 {
let mut bi = 0usize;
let mut bv = *x.get_unchecked(0);
for i in 1..n {
let v = *x.get_unchecked(i);
if v > bv {
bv = v;
bi = i;
}
}
return (bi, bv);
}
let base: [i32; 4] = [0, 1, 2, 3];
let four = i32x4_splat(4);
let mut vmax = v128_load(x.as_ptr().cast());
let mut vidx = v128_load(base.as_ptr().cast());
let mut cur = i32x4_add(vidx, four);
let chunks = n / 4;
let mut i = 4;
for _ in 1..chunks {
let v = v128_load(x.as_ptr().add(i).cast());
let mask = f32x4_gt(v, vmax); vmax = f32x4_max(vmax, v);
vidx = v128_bitselect(cur, vidx, mask);
cur = i32x4_add(cur, four);
i += 4;
}
let v0 = f32x4_extract_lane::<0>(vmax);
let v1 = f32x4_extract_lane::<1>(vmax);
let v2 = f32x4_extract_lane::<2>(vmax);
let v3 = f32x4_extract_lane::<3>(vmax);
let i0 = i32x4_extract_lane::<0>(vidx) as usize;
let i1 = i32x4_extract_lane::<1>(vidx) as usize;
let i2 = i32x4_extract_lane::<2>(vidx) as usize;
let i3 = i32x4_extract_lane::<3>(vidx) as usize;
let mut bv = v0;
let mut bi = i0;
for (v, idx) in [(v1, i1), (v2, i2), (v3, i3)] {
if v > bv || (v == bv && idx < bi) {
bv = v;
bi = idx;
}
}
while i < n {
let v = *x.get_unchecked(i);
if v > bv {
bv = v;
bi = i;
}
i += 1;
}
(bi, bv)
}
}