From af9611ccf769a3b30b8b81008f32f13beaac24b4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 1 Jun 2026 12:44:41 +0000 Subject: [PATCH 1/3] intrinsic-test: simplify type printing A small refactoring to make the type printing logic slightly cleaner and with greater code re-use. --- crates/intrinsic-test/src/arm/types.rs | 80 ++++++++++++------- .../src/common/intrinsic_helpers.rs | 25 +++--- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index cd420f1067..12d1c17c8e 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -8,21 +8,32 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { fn c_type(&self) -> String { let prefix = self.kind.c_prefix(); - if let Some(bit_len) = self.bit_len { - match (self.simd_len, self.vec_len) { - (None, None) => format!("{prefix}{bit_len}_t"), - (Some(SimdLen::Fixed(simd)), None) => format!("{prefix}{bit_len}x{simd}_t"), - (Some(SimdLen::Fixed(simd)), Some(vec)) => { - format!("{prefix}{bit_len}x{simd}x{vec}_t") - } - (Some(SimdLen::Scalable), None) => format!("sv{prefix}{bit_len}_t"), - (Some(SimdLen::Scalable), Some(vec)) => { - format!("sv{prefix}{bit_len}x{vec}_t") - } - (None, Some(_)) => todo!("{self:#?}"), // Likely an invalid case + match (self.bit_len, self.simd_len, self.vec_len) { + // e.g. `bool` + (Some(_), None, None) if matches!(self.kind, TypeKind::Bool) => { + format!("{prefix}") } - } else { - todo!("{self:#?}") + // e.g. `float32_t`, `int64_t` + (Some(bit_len), None, None) => format!("{prefix}{bit_len}_t"), + // e.g. `float32x2_t`, `int64x2_t` + (Some(bit_len), Some(SimdLen::Fixed(simd)), None) => { + format!("{prefix}{bit_len}x{simd}_t") + } + // e.g. `float32x2x3_t`, `int64x2x3_t` + (Some(bit_len), Some(SimdLen::Fixed(simd)), Some(vec)) => { + format!("{prefix}{bit_len}x{simd}x{vec}_t") + } + // e.g. `svbool_t` + (Some(_), Some(SimdLen::Scalable), None) if matches!(self.kind, TypeKind::Bool) => { + format!("sv{prefix}_t") + } + // e.g. `svfloat32_t`, `svint64_t` + (Some(bit_len), Some(SimdLen::Scalable), None) => format!("sv{prefix}{bit_len}_t"), + // e.g. `svfloat32x3_t`, `svint64x3_t` + (Some(bit_len), Some(SimdLen::Scalable), Some(vec)) => { + format!("sv{prefix}{bit_len}x{vec}_t") + } + _ => todo!("{self:#?}"), } } @@ -30,21 +41,34 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { let rust_prefix = self.kind.rust_prefix(); let c_prefix = self.kind.c_prefix(); - if let Some(bit_len) = self.bit_len { - match (self.simd_len, self.vec_len) { - (None, None) => format!("{rust_prefix}{bit_len}"), - (Some(SimdLen::Fixed(simd)), None) => format!("{c_prefix}{bit_len}x{simd}_t"), - (Some(SimdLen::Fixed(simd)), Some(vec)) => { - format!("{c_prefix}{bit_len}x{simd}x{vec}_t") - } - (Some(SimdLen::Scalable), None) => format!("sv{c_prefix}{bit_len}_t"), - (Some(SimdLen::Scalable), Some(vec)) => { - format!("sv{c_prefix}{bit_len}x{vec}_t") - } - (None, Some(_)) => todo!("{self:#?}"), // Likely an invalid case + match (self.bit_len, self.simd_len, self.vec_len) { + // e.g. `svpattern` + (None, _, _) => format!("{rust_prefix}"), + // e.g. `bool` + (Some(_), None, None) if matches!(self.kind, TypeKind::Bool) => { + format!("{rust_prefix}") } - } else { - todo!("{self:#?}") + // e.g. `i32` + (Some(bit_len), None, None) => format!("{rust_prefix}{bit_len}"), + // e.g. `int32x2_t` + (Some(bit_len), Some(SimdLen::Fixed(simd)), None) => { + format!("{c_prefix}{bit_len}x{simd}_t") + } + // e.g. `int32x2x3_t` + (Some(bit_len), Some(SimdLen::Fixed(simd)), Some(vec)) => { + format!("{c_prefix}{bit_len}x{simd}x{vec}_t") + } + // e.g. `svbool_t` + (Some(_), Some(SimdLen::Scalable), None) if matches!(self.kind, TypeKind::Bool) => { + format!("sv{c_prefix}_t") + } + // e.g. `svint32_t` + (Some(bit_len), Some(SimdLen::Scalable), None) => format!("sv{c_prefix}{bit_len}_t"), + // e.g. `svint32x3_t` + (Some(bit_len), Some(SimdLen::Scalable), Some(vec)) => { + format!("sv{c_prefix}{bit_len}x{vec}_t") + } + (Some(_), None, Some(_)) => todo!("{self:#?}"), } } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index ca5aeba86d..9773c777b1 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -1,6 +1,6 @@ use std::cmp; use std::fmt; -use std::ops::Deref; +use std::ops::DerefMut; use std::str::FromStr; #[derive(Debug, PartialEq, Copy, Clone)] @@ -90,9 +90,13 @@ impl TypeKind { } } - /// Returns the Rust prefix for this type kind i.e. `i`, `u`, or `f`. + /// Returns the Rust prefix for this type kind (i.e. `i` for `i16`, or `u` for `u16`). For type + /// kinds without any bit length at the end (e.g. `bool`), returns the whole type name. pub fn rust_prefix(&self) -> &str { match self { + Self::Bool => "bool", + Self::SvPattern => "svpattern", + Self::SvPrefetchOp => "svprfop", Self::BFloat => "bf", Self::Float => "f", Self::Int(Sign::Signed) => "i", @@ -101,7 +105,7 @@ impl TypeKind { Self::Char(Sign::Unsigned) => "u", Self::Char(Sign::Signed) => "i", Self::Mask => "u", - _ => unreachable!("Unused type kind: {self:#?}"), + _ => unreachable!("type kind without Rust prefix: {self:#?}"), } } } @@ -195,7 +199,7 @@ impl IntrinsicType { } } -pub trait IntrinsicTypeDefinition: Deref { +pub trait IntrinsicTypeDefinition: Clone + DerefMut { /// Determines the load function for this type. fn get_load_function(&self) -> String; @@ -208,14 +212,9 @@ pub trait IntrinsicTypeDefinition: Deref { /// Gets a string containing the name of the scalar type corresponding to this type if it is a /// vector. fn rust_scalar_type(&self) -> String { - if self.is_simd() { - format!( - "{prefix}{bits}", - prefix = self.kind().rust_prefix(), - bits = self.inner_size() - ) - } else { - self.rust_type() - } + let mut ty = self.clone(); + ty.simd_len = None; + ty.vec_len = None; + ty.rust_type() } } From 63158c22fa6342efcb10c362b64c9a65986e6018 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 1 Jun 2026 12:44:41 +0000 Subject: [PATCH 2/3] intrinsic-test: introduce `get_comparison_function` Introduces a per-architecture abstraction over how intrinsic results are compared, so that later commits can implement Arm-specific comparison logic for SVE. --- crates/intrinsic-test/src/common/gen_rust.rs | 29 +---------- .../src/common/intrinsic_helpers.rs | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index 02f6e40dc0..2ff615c0a1 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -6,7 +6,6 @@ use super::intrinsic_helpers::IntrinsicTypeDefinition; use crate::common::PASSES; use crate::common::cli::{CcArgStyle, ProcessedCli}; use crate::common::intrinsic::Intrinsic; -use crate::common::intrinsic_helpers::TypeKind; use crate::common::values::{test_values_array_name, test_values_array_static}; /// Rust definitions that are included verbatim in the generated source. In particular, defines @@ -199,29 +198,6 @@ fn generate_rust_test_loop( writeln!(w, " ];")?; } - let (cast_prefix, cast_suffix) = if intrinsic.results.is_simd() { - ( - format!( - "std::mem::transmute::<_, [{}; {}]>(", - intrinsic.results.rust_scalar_type().replace("f", "NanEqF"), - intrinsic.results.num_lanes() * intrinsic.results.num_vectors() - ), - ")", - ) - } else if intrinsic.results.kind == TypeKind::Float { - ( - match intrinsic.results.inner_size() { - 16 => format!("NanEqF16("), - 32 => format!("NanEqF32("), - 64 => format!("NanEqF64("), - _ => unimplemented!(), - }, - ")", - ) - } else { - ("".to_string(), "") - }; - write!( w, concatln!( @@ -235,7 +211,7 @@ fn generate_rust_test_loop( " c(__c_return_value.as_mut_ptr(){c_args});", " let __c_return_value = __c_return_value.assume_init();", "", - " assert_eq!({cast_prefix}__rust_return_value{cast_suffix}, {cast_prefix}__c_return_value{cast_suffix}, \"{{id}}\");", + " {comparison}", " }}", " }}", " }}", @@ -244,8 +220,7 @@ fn generate_rust_test_loop( rust_args = intrinsic.arguments.as_call_param_rust(), c_args = intrinsic.arguments.as_c_call_param_rust(), passes = PASSES, - cast_prefix = cast_prefix, - cast_suffix = cast_suffix, + comparison = intrinsic.results.get_comparison_function(), ) } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 9773c777b1..cb62e5db0a 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -203,6 +203,16 @@ pub trait IntrinsicTypeDefinition: Clone + DerefMut { /// Determines the load function for this type. fn get_load_function(&self) -> String; + /// Determines the comparison function for this type. + fn get_comparison_function(&self) -> String { + match self.simd_len { + Some(SimdLen::Scalable) => unimplemented!("architecture-specific"), + Some(SimdLen::Fixed(_)) | None => { + default_fixed_vector_comparison(self, self.num_lanes()) + } + } + } + /// Gets a string containing the typename for this type in C. fn c_type(&self) -> String; @@ -218,3 +228,43 @@ pub trait IntrinsicTypeDefinition: Clone + DerefMut { ty.rust_type() } } + +/// Returns the default comparison between results of an intrinsic - casting the vectors to arrays +/// and using `assert_eq` - using `NanEqF*` where required for floats. +pub(crate) fn default_fixed_vector_comparison( + ty: &Ty, + num_lanes: u32, +) -> String { + let (cast_prefix, cast_suffix) = if ty.is_simd() { + ( + format!( + "std::mem::transmute::<_, [{}; {}]>(", + ty.rust_scalar_type().replace("f", "NanEqF"), + num_lanes * ty.num_vectors() + ), + ")", + ) + } else if ty.kind == TypeKind::Float { + ( + match ty.inner_size() { + 16 => format!("NanEqF16("), + 32 => format!("NanEqF32("), + 64 => format!("NanEqF64("), + _ => unimplemented!(), + }, + ")", + ) + } else { + ("".to_string(), "") + }; + + format!( + r#" +assert_eq!( + {cast_prefix}__rust_return_value{cast_suffix}, + {cast_prefix}__c_return_value{cast_suffix}, + "{{id}}" +); +"#, + ) +} From 2f7cfdc78b2c45f6102420254d345cd72383f001 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 4 Jun 2026 12:48:11 +0000 Subject: [PATCH 3/3] intrinsic-test: rename `get_*_function` fns --- crates/intrinsic-test/src/arm/types.rs | 4 ++-- crates/intrinsic-test/src/common/argument.rs | 2 +- crates/intrinsic-test/src/common/gen_rust.rs | 2 +- crates/intrinsic-test/src/common/intrinsic_helpers.rs | 4 ++-- crates/intrinsic-test/src/x86/types.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 12d1c17c8e..45019cd409 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -73,7 +73,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { } /// Determines the load function for this type. - fn get_load_function(&self) -> String { + fn load_function(&self) -> String { if let IntrinsicType { kind: k, bit_len: Some(bl), @@ -97,7 +97,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { len = vec_len.unwrap_or(1), ) } else { - todo!("get_load_function IntrinsicType: {self:#?}") + todo!("load_function IntrinsicType: {self:#?}") } } } diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index eaec5b71c4..6b186accd1 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -182,7 +182,7 @@ where "let {name} = {load}({vals_name}.as_ptr().add((i+{idx}) % {PASSES}) as _);\n", name = arg.generate_name(), vals_name = test_values_array_name(&arg.ty), - load = arg.ty.get_load_function(), + load = arg.ty.load_function(), ) } else { format!( diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index 2ff615c0a1..9c585a0cb8 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -220,7 +220,7 @@ fn generate_rust_test_loop( rust_args = intrinsic.arguments.as_call_param_rust(), c_args = intrinsic.arguments.as_c_call_param_rust(), passes = PASSES, - comparison = intrinsic.results.get_comparison_function(), + comparison = intrinsic.results.comparison_function(), ) } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index cb62e5db0a..672a598cf0 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -201,10 +201,10 @@ impl IntrinsicType { pub trait IntrinsicTypeDefinition: Clone + DerefMut { /// Determines the load function for this type. - fn get_load_function(&self) -> String; + fn load_function(&self) -> String; /// Determines the comparison function for this type. - fn get_comparison_function(&self) -> String { + fn comparison_function(&self) -> String { match self.simd_len { Some(SimdLen::Scalable) => unimplemented!("architecture-specific"), Some(SimdLen::Fixed(_)) | None => { diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index a0e14c77d6..a1e30a4c46 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -50,7 +50,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { } /// Determines the load function for this type. - fn get_load_function(&self) -> String { + fn load_function(&self) -> String { let type_value = self.param.type_data.clone(); if type_value.len() == 0 { unimplemented!("the value for key 'type' is not present!");