From f44dd5b6940d53cd3646e9bd9e24895d5f92959e Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 14 Jul 2026 04:09:03 +0530 Subject: [PATCH] Simplify scalable vector testing --- crates/intrinsic-test/src/arm/mod.rs | 137 ++++++++++++++----------- crates/intrinsic-test/src/arm/types.rs | 74 +++---------- 2 files changed, 94 insertions(+), 117 deletions(-) diff --git a/crates/intrinsic-test/src/arm/mod.rs b/crates/intrinsic-test/src/arm/mod.rs index 4054d02502..fdea2c6eee 100644 --- a/crates/intrinsic-test/src/arm/mod.rs +++ b/crates/intrinsic-test/src/arm/mod.rs @@ -233,72 +233,91 @@ const fn svprfop_from_i32(value: i32) -> svprfop { } } -macro_rules! debug_print_integral { - ($($name:ident => ($ty:ty, $svptrue_fn:ident, $svcnt_fn:ident, $svst_fn:ident)),*) => { - $( - #[inline] - #[target_feature(enable = "sve")] - #[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] - pub fn $name(v: $ty) -> String { - unsafe { - let __pred = $svptrue_fn(); - let __num_elems = $svcnt_fn() as usize; - let mut __buf = std::vec::Vec::with_capacity(__num_elems); - $svst_fn(__pred, __buf.as_mut_ptr(), v); - __buf.set_len(__num_elems); - format!( - "[{}]", - __buf.iter().map(|el| el.to_string()).collect::>().join(", ") - ) - } - } - )* +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint8_to_slice(a: &svint8_t) -> &[i8] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntb() as usize) } } -debug_print_integral! { - debug_print_f32 => (svfloat32_t, svptrue_b32, svcntw, svst1_f32), - debug_print_f64 => (svfloat64_t, svptrue_b64, svcntd, svst1_f64), - debug_print_s8 => (svint8_t, svptrue_b8, svcntb, svst1_s8), - debug_print_s16 => (svint16_t, svptrue_b16, svcnth, svst1_s16), - debug_print_s32 => (svint32_t, svptrue_b32, svcntw, svst1_s32), - debug_print_s64 => (svint64_t, svptrue_b64, svcntd, svst1_s64), - debug_print_u8 => (svuint8_t, svptrue_b8, svcntb, svst1_u8), - debug_print_u16 => (svuint16_t, svptrue_b16, svcnth, svst1_u16), - debug_print_u32 => (svuint32_t, svptrue_b32, svcntw, svst1_u32), - debug_print_u64 => (svuint64_t, svptrue_b64, svcntd, svst1_u64) +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint8_to_slice(a: &svuint8_t) -> &[u8] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntb() as usize) + } } -macro_rules! debug_print_bool { - ($($name:ident => ($ty:ty, $svst_fn:ident, $svdup_fn:ident)),*) => { - $( - #[inline] - #[target_feature(enable = "sve")] - #[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] - pub fn $name(v: $ty) -> String { - unsafe { - let __num_elems = svcntb() as usize; - let mut __buf = std::vec::Vec::with_capacity(__num_elems); - $svst_fn(v, __buf.as_mut_ptr(), $svdup_fn(1)); - __buf.set_len(__num_elems); - format!( - "[{}]", - __buf.iter() - .map(|el| *el == 1) - .map(|el| el.to_string()) - .collect::>() - .join(", ") - ) - } - } - )* +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint16_to_slice(a: &svint16_t) -> &[i16] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcnth() as usize) } } -debug_print_bool! { - debug_print_b8 => (svbool_t, svst1_u8, svdup_n_u8), - debug_print_b16 => (svbool_t, svst1_u16, svdup_n_u16), - debug_print_b32 => (svbool_t, svst1_u32, svdup_n_u32), - debug_print_b64 => (svbool_t, svst1_u64, svdup_n_u64) +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint16_to_slice(a: &svuint16_t) -> &[u16] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcnth() as usize) + } } + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint32_to_slice(a: &svint32_t) -> &[i32] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntw() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint32_to_slice(a: &svuint32_t) -> &[u32] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntw() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint64_to_slice(a: &svint64_t) -> &[i64] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint64_to_slice(a: &svuint64_t) -> &[u64] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svfloat32_to_slice(a: &svfloat32_t) -> &[NanEqF32] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntw() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svfloat64_to_slice(a: &svfloat64_t) -> &[NanEqF64] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + +#[repr(transparent)] +#[derive(Copy,Clone,PartialEq,Eq)] +struct b8(u8); + +impl std::fmt::Debug for b8 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:08b}", self.0) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svbool_to_slice(a: &svbool_t) -> &[b8] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + "#; diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 7481bb4aeb..cced3bc40c 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -1,5 +1,4 @@ use super::intrinsic::ArmType; -use crate::common::PREDICATE_LOCAL; use crate::common::intrinsic_helpers::{ IntrinsicType, Sign, SimdLen, TypeDefinition, TypeKind, default_fixed_vector_comparison, }; @@ -114,17 +113,6 @@ impl TypeDefinition for ArmType { return default_fixed_vector_comparison(self, num_lanes); } - if self.kind() == TypeKind::Bool { - // There isn't a `svcmpeq` for `svbool_t` and there aren't `svboolxN_t` types, so just - // do an XOR and test it is empty. - return format!( - r#" -let __eq = sveor_b_z({PREDICATE_LOCAL}, __rust_return_value, __c_return_value); -assert!(!svptest_any({PREDICATE_LOCAL}, __eq), "{{}}", id); - "# - ); - } - // Returns `of` when `num_vectors == 1` otherwise returns the appropriate `svget` invocation // for `of`. let get = |num_vectors: u32, idx: u32, from: &'static str| -> String { @@ -139,56 +127,26 @@ assert!(!svptest_any({PREDICATE_LOCAL}, __eq), "{{}}", id); ) }; + let prefix = match self.kind { + TypeKind::Bool => "svbool".to_owned(), + kind => format!("sv{}{}", kind.c_prefix(), self.inner_size()), + }; + let n = self.num_vectors(); (0..n) .format_with("\n", |i, fmt| { - match self.kind() { - TypeKind::Float | TypeKind::BFloat => { - // Floats need special handling because `NaN != NaN` normally - this - // effectively does `(rust == c) || (isnan(rust) && isnan(c))` - fmt(&format_args!( - r#" -let __rust_eq_return_value = {rust_return_value}; -let __c_eq_return_value = {c_return_value}; -let __eq_sans_nan = svcmpeq_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __c_eq_return_value); -let __rust_nan = svcmpuo_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __rust_eq_return_value); -let __c_nan = svcmpuo_{ty}{bl}({PREDICATE_LOCAL}, __c_eq_return_value, __c_eq_return_value); -let __both_nan = svand_b_z({PREDICATE_LOCAL}, __rust_nan, __c_nan); -let __eq = svorr_b_z({PREDICATE_LOCAL}, __eq_sans_nan, __both_nan); -if !svptest_any(__pred, __eq) {{ - let __rust_pretty = debug_print_{ty}{bl}(__rust_eq_return_value); - let __c_pretty = debug_print_{ty}{bl}(__c_eq_return_value); - panic!("{{}}-{i_plus_one}/{n}\nRust: {{__rust_pretty}}\nC: {{__c_pretty}}", id); -}} -"#, - ty = self.rust_intrinsic_name_prefix(), - bl = self.inner_size(), - rust_return_value = get(n, i, "__rust_return_value"), - c_return_value = get(n, i, "__c_return_value"), - i_plus_one = i + 1, // so that the output is "1/2" and "2/2" - )) - } - _ => { - // Most types can just use `svcmpeq` - fmt(&format_args!( - r#" -let __rust_eq_return_value = {rust_return_value}; -let __c_eq_return_value = {c_return_value}; -let __eq = svcmpeq_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __c_eq_return_value); -if !svptest_any(__pred, __eq) {{ - let __rust_pretty = debug_print_{ty}{bl}(__rust_eq_return_value); - let __c_pretty = debug_print_{ty}{bl}(__c_eq_return_value); - panic!("{{}}-{i_plus_one}/{n}\nRust: {{__rust_pretty}}\nC: {{__c_pretty}}", id); -}} + fmt(&format_args!( + r#" +assert_eq!( + {prefix}_to_slice(&{rust_return_value}), + {prefix}_to_slice(&{c_return_value}), + "{{id}}-({i_plus_one}/{n})" +); "#, - ty = self.rust_intrinsic_name_prefix(), - bl = self.inner_size(), - rust_return_value = get(n, i, "__rust_return_value"), - c_return_value = get(n, i, "__c_return_value"), - i_plus_one = i + 1, // so that the output is "1/2" and "2/2" - )) - } - } + rust_return_value = get(n, i, "__rust_return_value"), + c_return_value = get(n, i, "__c_return_value"), + i_plus_one = i + 1, // so that the output is "1/2" and "2/2" + )) }) .to_string() }