#[inline(always)]
pub unsafe fn ptrue_all_s<const PD: u32>() {
const { assert!(PD < 16, "Pd must be 0..15") };
core::arch::asm!(
".word {enc}",
enc = const 0x2598E3E0 | PD,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn ptrue_all_b<const PD: u32>() {
const { assert!(PD < 16, "Pd must be 0..15") };
core::arch::asm!(
".word {enc}",
enc = const 0x2518E3E0 | PD,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn whilelt_s_x0x1<const PD: u32>() {
const { assert!(PD < 16, "Pd must be 0..15") };
core::arch::asm!(
".word {enc}",
enc = const 0x25A11400 | PD,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn ld1w_z_x0<const ZT: u32, const PG: u32>() {
const { assert!(ZT < 32 && PG < 8) };
core::arch::asm!(
".word {enc}",
enc = const 0xA540A000 | (PG << 10) | ZT,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn st1w_z_x0<const ZT: u32, const PG: u32>() {
const { assert!(ZT < 32 && PG < 8) };
core::arch::asm!(
".word {enc}",
enc = const 0xE540E000 | (PG << 10) | ZT,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn fmla_s<const ZDA: u32, const PG: u32, const ZN: u32, const ZM: u32>() {
const { assert!(ZDA < 32 && PG < 8 && ZN < 32 && ZM < 32) };
core::arch::asm!(
".word {enc}",
enc = const 0x65A00000 | (ZM << 16) | (PG << 10) | (ZN << 5) | ZDA,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn dup_z_w0<const ZD: u32>() {
const { assert!(ZD < 32) };
core::arch::asm!(
".word {enc}",
enc = const 0x05203800 | ZD,
options(nostack),
);
}
#[cfg(test)]
mod tests {
use super::super::Stream;
use super::*;
#[test]
fn ssve_load_store_roundtrip() {
if !crate::probe::scan().has_sme {
return;
}
let s = Stream::new().unwrap();
let n = s.svl_lanes_f32();
let src: Vec<f32> = (0..n).map(|i| i as f32 * 0.5).collect();
let mut dst: Vec<f32> = vec![0.0; n];
unsafe {
ptrue_all_s::<0>();
core::arch::asm!(
"mov x0, {src_ptr}",
".word {ld1w}",
"mov x0, {dst_ptr}",
".word {st1w}",
src_ptr = in(reg) src.as_ptr(),
dst_ptr = in(reg) dst.as_mut_ptr(),
ld1w = const 0xA540A000u32, st1w = const 0xE540E000u32, out("x0") _,
options(nostack),
);
}
drop(s);
for (i, (a, b)) in src.iter().zip(dst.iter()).enumerate() {
assert_eq!(a, b, "lane {i} differs");
}
}
#[test]
fn encoders_assemble() {
if !crate::probe::scan().has_sme {
return;
}
let _s = Stream::new().unwrap();
unsafe {
ptrue_all_s::<0>();
ptrue_all_b::<1>();
core::arch::asm!("mov x0, xzr", "mov x1, xzr", out("x0") _, out("x1") _);
whilelt_s_x0x1::<2>();
dup_z_w0::<3>();
fmla_s::<0, 0, 1, 2>();
}
}
}