Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 78 additions & 59 deletions crates/intrinsic-test/src/arm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<_>>().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::<Vec<_>>()
.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)
}
}

"#;
74 changes: 16 additions & 58 deletions crates/intrinsic-test/src/arm/types.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
}
Expand Down