From 8dd3b4a726e31428e0ae1fac0e8a09831eee324a Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 08:48:49 +0000 Subject: [PATCH 1/8] intrinsic-test: abstract `test_values_array_length` The arithmetic for computing the length of the array containing test values is repeated in a handful of locations and doesn't support scalable vectors - this commit introduces a `test_values_array_length` helper to deduplicate this logic. --- crates/intrinsic-test/src/common/argument.rs | 15 ++------ .../src/common/intrinsic_helpers.rs | 25 +++++------- crates/intrinsic-test/src/common/values.rs | 38 +++++++++++++++++++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 25207a8c45..73a6b6939a 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -1,6 +1,7 @@ use itertools::Itertools; use crate::common::intrinsic_helpers::TypeKind; +use crate::common::values::test_values_array_length; use super::constraint::Constraint; use super::gen_rust::PASSES; @@ -59,7 +60,7 @@ where format!( "{ty}_{load_size}", ty = self.ty.rust_scalar_type().to_uppercase(), - load_size = self.ty.num_lanes() * self.ty.num_vectors() + loads - 1, + load_size = test_values_array_length(&self.ty, loads), ) } @@ -175,16 +176,6 @@ where /// 0x80, 0x3b, 0xff, /// ]; /// ``` - /// - /// `num_lanes * num_vectors + loads - 1` elements are present in the array, which is sufficient - /// for a `loads` number of `num_lanes * num_vectors` windows into the array to be loaded: - /// - /// ```text - /// [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xf0, 0x80, 0x3b, 0xff] - /// ^^^^^^^^^^^^^^^^^^^ first window of `num_lanes * num_vectors` elements (e.g. four elements) - /// ^^^^^^^^^^^^^^^^^^ second window - /// `loads`th window ^^^^^^^^^^^^^^^^^^^^^^ - /// ``` pub fn gen_arg_rust( arg: &Argument, w: &mut impl std::io::Write, @@ -195,7 +186,7 @@ where "static {name}: [{ty}; {load_size}] = {values};\n", name = arg.rust_vals_array_name(), ty = arg.ty.rust_scalar_type(), - load_size = arg.ty.num_lanes() * arg.ty.num_vectors() + loads - 1, + load_size = test_values_array_length(&arg.ty, loads), values = arg.ty.populate_random(loads) ) } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index a894d5c016..c8f57c105f 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -5,6 +5,8 @@ use std::str::FromStr; use itertools::Itertools as _; +use crate::common::values::test_values_array_length; + use super::values::value_for_array; #[derive(Debug, PartialEq, Copy, Clone)] @@ -199,7 +201,7 @@ impl IntrinsicType { } /// Returns the elements used in the test value arrays in `gen_arg_rust`. Uses the same - /// `num_lanes * num_vectors + loads - 1` arithmetic to produce the number of values that + /// `test_values_array_length` to determine the number of values that /// `ArgumentList::gen_arg_rust` expects and `ArgumentList::load_values_rust` needs. /// /// Each value in the array starts as a bit pattern from `common::values::value_from_array` @@ -212,14 +214,12 @@ impl IntrinsicType { bit_len: Some(bit_len @ (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 32 | 64)), kind: kind @ (TypeKind::Int(_) | TypeKind::Poly | TypeKind::Char(_) | TypeKind::Mask), - vec_len, .. } => { format!( "[\n{body}\n]", - body = (0..(self.num_lanes() * vec_len.unwrap_or(1) + loads - 1)).format_with( - ",\n", - |i, fmt| { + body = + (0..test_values_array_length(self, loads)).format_with(",\n", |i, fmt| { let src = value_for_array(*bit_len, i); assert!(src == 0 || src.ilog2() < *bit_len); if *kind == TypeKind::Int(Sign::Signed) && (src >> (*bit_len - 1)) != 0 @@ -232,19 +232,17 @@ impl IntrinsicType { } else { fmt(&format_args!("{src:#x}")) } - } - ) + }) ) } IntrinsicType { kind: TypeKind::Float, bit_len: Some(bit_len @ (16 | 32 | 64)), - vec_len, .. } => { format!( "[\n{body}\n]", - body = (0..(self.num_lanes() * vec_len.unwrap_or(1) + loads - 1)).format_with( + body = (0..test_values_array_length(self, loads)).format_with( ",\n", |i, fmt| fmt(&format_args!( "f{bit_len}::from_bits({src:#x})", @@ -256,15 +254,13 @@ impl IntrinsicType { IntrinsicType { kind: TypeKind::Vector, bit_len: Some(128 | 256 | 512), - vec_len, .. } => { let effective_bit_len = 32; format!( "[\n{body}\n]", - body = (0..(vec_len.unwrap_or(1) * self.num_lanes() + loads - 1)).format_with( - ",\n", - |i, fmt| { + body = + (0..test_values_array_length(self, loads)).format_with(",\n", |i, fmt| { let src = value_for_array(effective_bit_len, i); assert!(src == 0 || src.ilog2() < effective_bit_len); if (src >> (effective_bit_len - 1)) != 0 { @@ -276,8 +272,7 @@ impl IntrinsicType { } else { fmt(&format_args!("{src:#x}")) } - } - ) + }) ) } _ => unimplemented!("populate random: {self:#?}"), diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index 01dc0713f0..35252539ff 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -1,3 +1,41 @@ +use crate::common::intrinsic_helpers::{IntrinsicType, SimdLen}; + +/// Maximum size of a SVE vector +pub const MAX_SVE_BITS: u32 = 2048; + +/// Returns the number of values that need to be in an array of test values such that there can be +/// `num_loads` distinct windows for a given vector of type `ty`. +/// +/// For example, vectors of type `uint32x2x2_t` load four values (`2 x 2`) and so to support +/// `num_loads=10` distinct windows, the total length of the array of test values must be +/// `(2 x 2) + 10 - 1`: +/// +/// ```text +/// [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD] +/// ^^^^^^^^^^^^^^^^^^ first window +/// ^^^^^^^^^^^^^^^^^^ second window +/// 10th window ^^^^^^^^^^^^^^^^^^ +/// ``` +/// +/// For scalable vectors (only SVE is currently supported), assume that the length of the vector is +/// the maximum supported by the architecture. +pub fn test_values_array_length(ty: &IntrinsicType, num_loads: u32) -> u32 { + let IntrinsicType { + simd_len, vec_len, .. + } = ty; + + let simd_len = simd_len.map_or(1, |v| { + if let SimdLen::Fixed(n) = v { + n + } else { + MAX_SVE_BITS / ty.inner_size() + } + }); + let vec_len = vec_len.unwrap_or(1); + + (simd_len * vec_len) + num_loads - 1 +} + /// Returns a bit pattern for a value being output into a array of test values. Bit patterns come /// from one of many constant arrays of test values. The specific constant array used depends on /// the number of bits - `bits` - of the type having test values generated for it. This function From 8423d3dc39d832bdb8f8b0f2f4513350560a1605 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 09:55:05 +0000 Subject: [PATCH 2/8] intrinsic-test: simplify/rename `populate_random` This function is more complex than it needs to be and `populate_random` is an unintuitive name - it doesn't do anything involving randomness. --- crates/intrinsic-test/src/common/argument.rs | 4 +- .../src/common/intrinsic_helpers.rs | 85 ------------------- crates/intrinsic-test/src/common/values.rs | 55 +++++++++++- 3 files changed, 54 insertions(+), 90 deletions(-) diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 73a6b6939a..4df055cb9c 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::values::test_values_array_length; +use crate::common::values::{test_values_array, test_values_array_length}; use super::constraint::Constraint; use super::gen_rust::PASSES; @@ -187,7 +187,7 @@ where name = arg.rust_vals_array_name(), ty = arg.ty.rust_scalar_type(), load_size = test_values_array_length(&arg.ty, loads), - values = arg.ty.populate_random(loads) + values = test_values_array(&arg.ty, loads) ) } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index c8f57c105f..ca5aeba86d 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -3,12 +3,6 @@ use std::fmt; use std::ops::Deref; use std::str::FromStr; -use itertools::Itertools as _; - -use crate::common::values::test_values_array_length; - -use super::values::value_for_array; - #[derive(Debug, PartialEq, Copy, Clone)] pub enum Sign { Signed, @@ -199,85 +193,6 @@ impl IntrinsicType { pub fn is_ptr(&self) -> bool { self.ptr } - - /// Returns the elements used in the test value arrays in `gen_arg_rust`. Uses the same - /// `test_values_array_length` to determine the number of values that - /// `ArgumentList::gen_arg_rust` expects and `ArgumentList::load_values_rust` needs. - /// - /// Each value in the array starts as a bit pattern from `common::values::value_from_array` - /// which is then printed as a hex value in the generated code (and if identified as a negative - /// value, with the appropriate minus and corrected hex pattern). Calls to `fN::from_bits` are - /// generated for floats. - pub fn populate_random(&self, loads: u32) -> String { - match self { - IntrinsicType { - bit_len: Some(bit_len @ (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 32 | 64)), - kind: - kind @ (TypeKind::Int(_) | TypeKind::Poly | TypeKind::Char(_) | TypeKind::Mask), - .. - } => { - format!( - "[\n{body}\n]", - body = - (0..test_values_array_length(self, loads)).format_with(",\n", |i, fmt| { - let src = value_for_array(*bit_len, i); - assert!(src == 0 || src.ilog2() < *bit_len); - if *kind == TypeKind::Int(Sign::Signed) && (src >> (*bit_len - 1)) != 0 - { - // `src` is a two's complement representation of a negative value. - let mask = !0u64 >> (64 - *bit_len); - let ones_compl = src ^ mask; - let twos_compl = ones_compl + 1; - fmt(&format_args!("-{twos_compl:#x}")) - } else { - fmt(&format_args!("{src:#x}")) - } - }) - ) - } - IntrinsicType { - kind: TypeKind::Float, - bit_len: Some(bit_len @ (16 | 32 | 64)), - .. - } => { - format!( - "[\n{body}\n]", - body = (0..test_values_array_length(self, loads)).format_with( - ",\n", - |i, fmt| fmt(&format_args!( - "f{bit_len}::from_bits({src:#x})", - src = value_for_array(*bit_len, i) - )) - ) - ) - } - IntrinsicType { - kind: TypeKind::Vector, - bit_len: Some(128 | 256 | 512), - .. - } => { - let effective_bit_len = 32; - format!( - "[\n{body}\n]", - body = - (0..test_values_array_length(self, loads)).format_with(",\n", |i, fmt| { - let src = value_for_array(effective_bit_len, i); - assert!(src == 0 || src.ilog2() < effective_bit_len); - if (src >> (effective_bit_len - 1)) != 0 { - // `src` is a two's complement representation of a negative value. - let mask = !0u64 >> (64 - effective_bit_len); - let ones_compl = src ^ mask; - let twos_compl = ones_compl + 1; - fmt(&format_args!("-{twos_compl:#x}")) - } else { - fmt(&format_args!("{src:#x}")) - } - }) - ) - } - _ => unimplemented!("populate random: {self:#?}"), - } - } } pub trait IntrinsicTypeDefinition: Deref { diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index 35252539ff..57c1c2c1e2 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -1,8 +1,57 @@ -use crate::common::intrinsic_helpers::{IntrinsicType, SimdLen}; +use itertools::Itertools as _; + +use crate::common::intrinsic_helpers::{IntrinsicType, Sign, SimdLen, TypeKind}; /// Maximum size of a SVE vector pub const MAX_SVE_BITS: u32 = 2048; +/// Returns the elements used in the test value arrays in `gen_arg_rust`. Uses the +/// `test_values_array_length` fn to determine the number of values that +/// `ArgumentList::gen_arg_rust` expects and `ArgumentList::load_values_rust` needs. +/// +/// Each value in the array starts as a bit pattern from `bit_pattern_for_test_values_array` +/// which is then printed as a hex value in the generated code (and if identified as a negative +/// value, with the appropriate minus and corrected hex pattern). Calls to `fN::from_bits` are +/// generated for floats. +pub fn test_values_array(ty: &IntrinsicType, num_loads: u32) -> String { + let (bit_len, kind) = match ty { + IntrinsicType { + kind: TypeKind::Float, + bit_len: Some(bit_len), + .. + } => (*bit_len, TypeKind::Float), + IntrinsicType { + kind: TypeKind::Vector, + .. + } => (32, TypeKind::Vector), + IntrinsicType { + kind, + bit_len: Some(bit_len), + .. + } => (*bit_len, *kind), + _ => unimplemented!(), + }; + + format!( + "[{}]", + (0..test_values_array_length(ty, num_loads)).format_with(",", |i, fmt| { + let src = bit_pattern_for_test_values_array(bit_len, i); + assert!(src == 0 || src.ilog2() < bit_len); + match kind { + TypeKind::Float => fmt(&format_args!("f{bit_len}::from_bits({src:#x})")), + TypeKind::Vector | TypeKind::Int(Sign::Signed) if (src >> (bit_len - 1)) != 0 => { + // `src` is a two's complement representation of a negative value. + let mask = !0u64 >> (64 - bit_len); + let ones_compl = src ^ mask; + let twos_compl = ones_compl + 1; + fmt(&format_args!("-{twos_compl:#x}")) + } + _ => fmt(&format_args!("{src:#x}")), + } + }) + ) +} + /// Returns the number of values that need to be in an array of test values such that there can be /// `num_loads` distinct windows for a given vector of type `ty`. /// @@ -45,7 +94,7 @@ pub fn test_values_array_length(ty: &IntrinsicType, num_loads: u32) -> u32 { /// Each constant array of bit patterns should ideally be at least the length of the largest array /// of test values that will be requested (e.g. 51 for a `poly8x8x4` when `PASSES=20`: /// `(8 * 4) + 20 - 1`), otherwise values will be repeated. -pub fn value_for_array(bits: u32, index: u32) -> u64 { +pub fn bit_pattern_for_test_values_array(bits: u32, index: u32) -> u64 { let index = index as usize; match bits { 1 => VALUES_8[index % 2].into(), @@ -59,7 +108,7 @@ pub fn value_for_array(bits: u32, index: u32) -> u64 { 16 => VALUES_16[index % VALUES_16.len()].into(), 32 => VALUES_32[index % VALUES_32.len()].into(), 64 => VALUES_64[index % VALUES_64.len()], - _ => unimplemented!("value_for_array(bits: {bits}, ..)"), + _ => unimplemented!("bit_pattern_for_test_values_array(bits: {bits}, ..)"), } } From d328c4360555cbec23218fa6656da6121d3246ae Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 09:57:25 +0000 Subject: [PATCH 3/8] intrinsic-test: move/rename `rust_vals_array_name` Move this function to the `values` module alongside the other functions related to generation of the test value arrays and rename with a similar name. --- crates/intrinsic-test/src/common/argument.rs | 21 +++++--------------- crates/intrinsic-test/src/common/gen_rust.rs | 5 +++-- crates/intrinsic-test/src/common/values.rs | 14 ++++++++++++- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 4df055cb9c..ce36a2c666 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::values::{test_values_array, test_values_array_length}; +use crate::common::values::{test_values_array, test_values_array_length, test_values_array_name}; use super::constraint::Constraint; use super::gen_rust::PASSES; @@ -53,17 +53,6 @@ where self.constraint.is_some() } - /// Returns a string with the name of the static variable containing test values for intrinsic - /// arguments of this type. - pub(crate) fn rust_vals_array_name(&self) -> impl std::fmt::Display { - let loads = crate::common::gen_rust::PASSES; - format!( - "{ty}_{load_size}", - ty = self.ty.rust_scalar_type().to_uppercase(), - load_size = test_values_array_length(&self.ty, loads), - ) - } - /// Should this argument be passed by reference in C wrapper function declarations? /// /// SIMD types and `f16` are currently passed by reference. @@ -184,7 +173,7 @@ where writeln!( w, "static {name}: [{ty}; {load_size}] = {values};\n", - name = arg.rust_vals_array_name(), + name = test_values_array_name(&arg.ty, loads), ty = arg.ty.rust_scalar_type(), load_size = test_values_array_length(&arg.ty, loads), values = test_values_array(&arg.ty, loads) @@ -208,7 +197,7 @@ where /// /// Each subsequent argument's first window is started one element further into the array /// then the previous. - pub fn load_values_rust(&self) -> String { + pub fn load_values_rust(&self, loads: u32) -> String { self.iter() .filter(|&arg| !arg.has_constraint()) .enumerate() @@ -217,14 +206,14 @@ where format!( "let {name} = {load}({vals_name}.as_ptr().add((i+{idx}) % {PASSES}) as _);\n", name = arg.generate_name(), - vals_name = arg.rust_vals_array_name(), + vals_name = test_values_array_name(&arg.ty, loads), load = arg.ty.get_load_function(), ) } else { format!( "let {name} = {vals_name}[(i+{idx}) % {PASSES}];\n", name = arg.generate_name(), - vals_name = arg.rust_vals_array_name(), + vals_name = test_values_array_name(&arg.ty, loads), ) } }) diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index 039e78f577..82db3dcdcc 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -6,6 +6,7 @@ use super::intrinsic_helpers::IntrinsicTypeDefinition; use crate::common::argument::ArgumentList; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; +use crate::common::values::test_values_array_name; // The number of times each intrinsic will be called - influences the generation of the // test arrays to minimise repeated testing of the same test values. @@ -134,7 +135,7 @@ pub fn write_lib_rs( for intrinsic in intrinsics { for arg in &intrinsic.arguments.args { if !arg.has_constraint() { - let name = arg.rust_vals_array_name().to_string(); + let name = test_values_array_name(&arg.ty, PASSES); if seen.insert(name) { ArgumentList::gen_arg_rust(arg, w, PASSES)?; @@ -243,7 +244,7 @@ fn generate_rust_test_loop( " }}", " }}", ), - loaded_args = intrinsic.arguments.load_values_rust(), + loaded_args = intrinsic.arguments.load_values_rust(passes), rust_args = intrinsic.arguments.as_call_param_rust(), c_args = intrinsic.arguments.as_c_call_param_rust(), passes = passes, diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index 57c1c2c1e2..f6c4b0a9cd 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -1,10 +1,22 @@ use itertools::Itertools as _; -use crate::common::intrinsic_helpers::{IntrinsicType, Sign, SimdLen, TypeKind}; +use crate::common::intrinsic_helpers::{ + IntrinsicType, IntrinsicTypeDefinition, Sign, SimdLen, TypeKind, +}; /// Maximum size of a SVE vector pub const MAX_SVE_BITS: u32 = 2048; +/// Returns a string with the name of the static variable containing test values for intrinsic +/// arguments of this type. +pub fn test_values_array_name(ty: &T, num_loads: u32) -> String { + format!( + "{ty}_{load_size}", + ty = ty.rust_scalar_type().to_uppercase(), + load_size = test_values_array_length(&ty, num_loads), + ) +} + /// Returns the elements used in the test value arrays in `gen_arg_rust`. Uses the /// `test_values_array_length` fn to determine the number of values that /// `ArgumentList::gen_arg_rust` expects and `ArgumentList::load_values_rust` needs. From ed8ef6dfdbaa01bc0212ae99ca31d27a0cadbbae Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 10:03:47 +0000 Subject: [PATCH 4/8] intrinsic-test: uses `PASSES` consistently `PASSES` is a constant accessible to all of the `common` module but is sometimes used directly and sometimes threaded through functions as an argument - this commit eliminates the inconsistency and just uses the constant everywhere. --- crates/intrinsic-test/src/common/argument.rs | 20 ++++++++------------ crates/intrinsic-test/src/common/gen_rust.rs | 16 ++++++---------- crates/intrinsic-test/src/common/mod.rs | 4 ++++ crates/intrinsic-test/src/common/values.rs | 17 +++++++++-------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index ce36a2c666..8b07224ef7 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -3,8 +3,8 @@ use itertools::Itertools; use crate::common::intrinsic_helpers::TypeKind; use crate::common::values::{test_values_array, test_values_array_length, test_values_array_name}; +use super::PASSES; use super::constraint::Constraint; -use super::gen_rust::PASSES; use super::intrinsic_helpers::IntrinsicTypeDefinition; /// An argument for the intrinsic. @@ -165,18 +165,14 @@ where /// 0x80, 0x3b, 0xff, /// ]; /// ``` - pub fn gen_arg_rust( - arg: &Argument, - w: &mut impl std::io::Write, - loads: u32, - ) -> std::io::Result<()> { + pub fn gen_arg_rust(arg: &Argument, w: &mut impl std::io::Write) -> std::io::Result<()> { writeln!( w, "static {name}: [{ty}; {load_size}] = {values};\n", - name = test_values_array_name(&arg.ty, loads), + name = test_values_array_name(&arg.ty), ty = arg.ty.rust_scalar_type(), - load_size = test_values_array_length(&arg.ty, loads), - values = test_values_array(&arg.ty, loads) + load_size = test_values_array_length(&arg.ty), + values = test_values_array(&arg.ty) ) } @@ -197,7 +193,7 @@ where /// /// Each subsequent argument's first window is started one element further into the array /// then the previous. - pub fn load_values_rust(&self, loads: u32) -> String { + pub fn load_values_rust(&self) -> String { self.iter() .filter(|&arg| !arg.has_constraint()) .enumerate() @@ -206,14 +202,14 @@ where format!( "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, loads), + vals_name = test_values_array_name(&arg.ty), load = arg.ty.get_load_function(), ) } else { format!( "let {name} = {vals_name}[(i+{idx}) % {PASSES}];\n", name = arg.generate_name(), - vals_name = test_values_array_name(&arg.ty, loads), + vals_name = test_values_array_name(&arg.ty), ) } }) diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index 82db3dcdcc..330670306e 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -3,15 +3,12 @@ use std::process::Command; use itertools::Itertools; use super::intrinsic_helpers::IntrinsicTypeDefinition; +use crate::common::PASSES; use crate::common::argument::ArgumentList; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; use crate::common::values::test_values_array_name; -// The number of times each intrinsic will be called - influences the generation of the -// test arrays to minimise repeated testing of the same test values. -pub(crate) const PASSES: u32 = 20; - /// Rust definitions that are included verbatim in the generated source. In particular, defines /// a wrapper around float types that defines `NaN`s to be equal reflexively to enable /// comparison of results that use floats types. @@ -135,10 +132,10 @@ pub fn write_lib_rs( for intrinsic in intrinsics { for arg in &intrinsic.arguments.args { if !arg.has_constraint() { - let name = test_values_array_name(&arg.ty, PASSES); + let name = test_values_array_name(&arg.ty); if seen.insert(name) { - ArgumentList::gen_arg_rust(arg, w, PASSES)?; + ArgumentList::gen_arg_rust(arg, w)?; } } } @@ -163,7 +160,6 @@ pub fn write_lib_rs( fn generate_rust_test_loop( w: &mut impl std::io::Write, intrinsic: &Intrinsic, - passes: u32, ) -> std::io::Result<()> { let intrinsic_name = &intrinsic.name; @@ -244,10 +240,10 @@ fn generate_rust_test_loop( " }}", " }}", ), - loaded_args = intrinsic.arguments.load_values_rust(passes), + loaded_args = intrinsic.arguments.load_values_rust(), rust_args = intrinsic.arguments.as_call_param_rust(), c_args = intrinsic.arguments.as_c_call_param_rust(), - passes = passes, + passes = PASSES, cast_prefix = cast_prefix, cast_suffix = cast_suffix, ) @@ -267,7 +263,7 @@ fn create_rust_test( intrinsic_name = intrinsic.name, )?; - generate_rust_test_loop(w, intrinsic, PASSES)?; + generate_rust_test_loop(w, intrinsic)?; writeln!(w, "}}")?; diff --git a/crates/intrinsic-test/src/common/mod.rs b/crates/intrinsic-test/src/common/mod.rs index 86269bab33..8b6459ffb2 100644 --- a/crates/intrinsic-test/src/common/mod.rs +++ b/crates/intrinsic-test/src/common/mod.rs @@ -23,6 +23,10 @@ mod gen_c; mod gen_rust; mod values; +// The number of times each intrinsic will be called - influences the generation of the +// test arrays to minimise repeated testing of the same test values. +pub(crate) const PASSES: u32 = 20; + /// Architectures must support this trait /// to be successfully tested. pub trait SupportedArchitectureTest { diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index f6c4b0a9cd..b5e9868afe 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -1,7 +1,8 @@ use itertools::Itertools as _; -use crate::common::intrinsic_helpers::{ - IntrinsicType, IntrinsicTypeDefinition, Sign, SimdLen, TypeKind, +use crate::common::{ + PASSES, + intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, SimdLen, TypeKind}, }; /// Maximum size of a SVE vector @@ -9,11 +10,11 @@ pub const MAX_SVE_BITS: u32 = 2048; /// Returns a string with the name of the static variable containing test values for intrinsic /// arguments of this type. -pub fn test_values_array_name(ty: &T, num_loads: u32) -> String { +pub fn test_values_array_name(ty: &T) -> String { format!( "{ty}_{load_size}", ty = ty.rust_scalar_type().to_uppercase(), - load_size = test_values_array_length(&ty, num_loads), + load_size = test_values_array_length(&ty), ) } @@ -25,7 +26,7 @@ pub fn test_values_array_name(ty: &T, num_loads: u32 /// which is then printed as a hex value in the generated code (and if identified as a negative /// value, with the appropriate minus and corrected hex pattern). Calls to `fN::from_bits` are /// generated for floats. -pub fn test_values_array(ty: &IntrinsicType, num_loads: u32) -> String { +pub fn test_values_array(ty: &IntrinsicType) -> String { let (bit_len, kind) = match ty { IntrinsicType { kind: TypeKind::Float, @@ -46,7 +47,7 @@ pub fn test_values_array(ty: &IntrinsicType, num_loads: u32) -> String { format!( "[{}]", - (0..test_values_array_length(ty, num_loads)).format_with(",", |i, fmt| { + (0..test_values_array_length(ty)).format_with(",", |i, fmt| { let src = bit_pattern_for_test_values_array(bit_len, i); assert!(src == 0 || src.ilog2() < bit_len); match kind { @@ -80,7 +81,7 @@ pub fn test_values_array(ty: &IntrinsicType, num_loads: u32) -> String { /// /// For scalable vectors (only SVE is currently supported), assume that the length of the vector is /// the maximum supported by the architecture. -pub fn test_values_array_length(ty: &IntrinsicType, num_loads: u32) -> u32 { +pub fn test_values_array_length(ty: &IntrinsicType) -> u32 { let IntrinsicType { simd_len, vec_len, .. } = ty; @@ -94,7 +95,7 @@ pub fn test_values_array_length(ty: &IntrinsicType, num_loads: u32) -> u32 { }); let vec_len = vec_len.unwrap_or(1); - (simd_len * vec_len) + num_loads - 1 + (simd_len * vec_len) + PASSES - 1 } /// Returns a bit pattern for a value being output into a array of test values. Bit patterns come From 96e2e60306cafd7c6d8056723d389d26d95b025b Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 10:06:16 +0000 Subject: [PATCH 5/8] intrinsic-test: s/VALUES/BIT_PATTERNS Given that these "values" are sometimes re-interpreted as negative numbers, in practice they are bit patterns rather than values. --- crates/intrinsic-test/src/common/values.rs | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index b5e9868afe..61ee40e865 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -110,45 +110,45 @@ pub fn test_values_array_length(ty: &IntrinsicType) -> u32 { pub fn bit_pattern_for_test_values_array(bits: u32, index: u32) -> u64 { let index = index as usize; match bits { - 1 => VALUES_8[index % 2].into(), - 2 => VALUES_8[index % 4].into(), - 3 => VALUES_8[index % 8].into(), - 4 => VALUES_8[index % 16].into(), - 5 => VALUES_5[index % VALUES_5.len()].into(), - 6 => VALUES_6[index % VALUES_6.len()].into(), - 7 => VALUES_7[index % VALUES_7.len()].into(), - 8 => VALUES_8[index % VALUES_8.len()].into(), - 16 => VALUES_16[index % VALUES_16.len()].into(), - 32 => VALUES_32[index % VALUES_32.len()].into(), - 64 => VALUES_64[index % VALUES_64.len()], + 1 => BIT_PATTERNS_8[index % 2].into(), + 2 => BIT_PATTERNS_8[index % 4].into(), + 3 => BIT_PATTERNS_8[index % 8].into(), + 4 => BIT_PATTERNS_8[index % 16].into(), + 5 => BIT_PATTERNS_5[index % BIT_PATTERNS_5.len()].into(), + 6 => BIT_PATTERNS_6[index % BIT_PATTERNS_6.len()].into(), + 7 => BIT_PATTERNS_7[index % BIT_PATTERNS_7.len()].into(), + 8 => BIT_PATTERNS_8[index % BIT_PATTERNS_8.len()].into(), + 16 => BIT_PATTERNS_16[index % BIT_PATTERNS_16.len()].into(), + 32 => BIT_PATTERNS_32[index % BIT_PATTERNS_32.len()].into(), + 64 => BIT_PATTERNS_64[index % BIT_PATTERNS_64.len()], _ => unimplemented!("bit_pattern_for_test_values_array(bits: {bits}, ..)"), } } -pub const VALUES_5: &[u8] = &[ +pub const BIT_PATTERNS_5: &[u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x019, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ]; -pub const VALUES_6: &[u8] = &[ +pub const BIT_PATTERNS_6: &[u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x039, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ]; -pub const VALUES_7: &[u8] = &[ +pub const BIT_PATTERNS_7: &[u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x079, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, ]; -pub const VALUES_8: &[u8] = &[ +pub const BIT_PATTERNS_8: &[u8] = &[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xf0, 0x80, 0x3b, 0xff, ]; -pub const VALUES_16: &[u16] = &[ +pub const BIT_PATTERNS_16: &[u16] = &[ 0x0000, // 0.0 0x0400, // The smallest normal value. 0x37ff, // The value just below 0.5. @@ -173,7 +173,7 @@ pub const VALUES_16: &[u16] = &[ 0xff23, 0xfe00, 0xfd23, 0xfc01, 0x8012, 0x83ff, 0x8001, ]; -pub const VALUES_32: &[u32] = &[ +pub const BIT_PATTERNS_32: &[u32] = &[ // Simple values. 0x00000000, // 0.0 0x00800000, // The smallest normal value. @@ -200,7 +200,7 @@ pub const VALUES_32: &[u32] = &[ 0x80123456, 0x807fffff, 0x80000001, ]; -pub const VALUES_64: &[u64] = &[ +pub const BIT_PATTERNS_64: &[u64] = &[ // Simple values. 0x0000000000000000, // 0.0 0x0010000000000000, // The smallest normal value. From 293317b7c74e9b67d4184cef25345fec63e8bd1a Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 10:22:35 +0000 Subject: [PATCH 6/8] intrinsic-test: add more values When SVE vectors start being tested, the test vectors will have length `$max_sve_bits / $ty_bit_length`, which is longer than most existing vector types, so more values are useful. --- crates/intrinsic-test/src/common/values.rs | 269 ++++++++++++++------- 1 file changed, 182 insertions(+), 87 deletions(-) diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index 61ee40e865..7f7d10656f 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -144,108 +144,203 @@ pub const BIT_PATTERNS_7: &[u8] = &[ ]; pub const BIT_PATTERNS_8: &[u8] = &[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0xf0, 0x80, 0x3b, 0xff, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, + 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, + 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, + 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; +#[rustfmt::skip] pub const BIT_PATTERNS_16: &[u16] = &[ - 0x0000, // 0.0 - 0x0400, // The smallest normal value. - 0x37ff, // The value just below 0.5. - 0x3800, // 0.5 - 0x3801, // The value just above 0.5. - 0x3bff, // The value just below 1.0. - 0x3c00, // 1.0 - 0x3c01, // The value just above 1.0. - 0x3e00, // 1.5 - 0x4900, // 10 - 0x7bff, // The largest finite value. - 0x7c00, // Infinity. - // NaNs. - // - Quiet NaNs - 0x7f23, 0x7e00, // - Signalling NaNs - 0x7d23, 0x7c01, // Subnormals. - // - A recognisable bit pattern. - 0x0012, // - The largest subnormal value. - 0x03ff, // - The smallest subnormal value. - 0x0001, // The same values again, but negated. + // Simple values: + // 0.0 + 0x0000, + // The smallest normal value + 0x0400, + // The value just below 0.5 + 0x37ff, + // 0.5 + 0x3800, + // The value just above 0.5 + 0x3801, + // The value just below 1.0 + 0x3bff, + // 1.0 + 0x3c00, + // The value just above 1.0 + 0x3c01, + // 1.5 + 0x3e00, + // 10 + 0x4900, + // The largest finite value + 0x7bff, + // Infinity. + 0x7c00, + + // NaNs: + // Quiet NaNs + 0x7f23, + 0x7e00, + // Signalling NaNs + 0x7d23, + 0x7c01, + + // Subnormals: + // A recognisable bit pattern + 0x0012, + // The largest subnormal value + 0x03ff, + // The smallest subnormal value + 0x0001, + + // Other values: + // Above values, negated 0x8000, 0x8400, 0xb7ff, 0xb800, 0xb801, 0xbbff, 0xbc00, 0xbc01, 0xbe00, 0xc900, 0xfbff, 0xfc00, 0xff23, 0xfe00, 0xfd23, 0xfc01, 0x8012, 0x83ff, 0x8001, + // Random values + 0xfc00, 0xc000, 0x5140, 0x5800, 0x63d2, 0x5630, 0x3560, 0x9191, 0x4178, 0x6212, 0x67d0, 0x3312, + 0x4cef, 0x4973, 0x3ecc, 0x5166, 0x4d80, 0x6248, 0x46fd, 0x39c4, 0x39c5, 0x4866, 0x6050, 0x498e, + 0x4a0f, + // Previous values in a different order + 0x3555, 0xfc00, 0xc000, 0x9191, 0x5140, 0x5800, 0x8001, 0x83ff, 0x63d2, 0x5630, 0x3560, 0x4178, + 0x7d23, 0x7c01, 0x0012, 0xb800, 0x03ff, 0x0001, 0x7e00, 0x7f23, 0x8000, 0x8400, 0xb7ff, 0xb801, + 0x3312, 0x4cef, 0x4973, 0x39c4, 0x3ecc, 0x5166, 0x67d0, 0x6212, 0x4d80, 0x6248, 0x46fd, 0x39c5, + 0xbc01, 0xbe00, 0xc900, 0xfc01, 0xfbff, 0xfc00, 0xbc00, 0xbbff, 0xff23, 0xfe00, 0xfd23, 0x8012, + 0x37ff, 0x3800, 0x3801, 0x7bff, 0x3bff, 0x3c00, 0x0400, 0x0000, 0x3c01, 0x3e00, 0x4900, 0x7c00, + 0x498e, 0x4a0f, 0x6050, 0x4866, + + // Specific values: + // As close to 1/3 as possible. + 0x3555, ]; +#[rustfmt::skip] pub const BIT_PATTERNS_32: &[u32] = &[ - // Simple values. - 0x00000000, // 0.0 - 0x00800000, // The smallest normal value. - 0x3effffff, // The value just below 0.5. - 0x3f000000, // 0.5 - 0x3f000001, // The value just above 0.5. - 0x3f7fffff, // The value just below 1.0. - 0x3f800000, // 1.0 - 0x3f800001, // The value just above 1.0. - 0x3fc00000, // 1.5 - 0x41200000, // 10 - 0x7f8fffff, // The largest finite value. - 0x7f800000, // Infinity. - // NaNs. - // - Quiet NaNs - 0x7fd23456, 0x7fc00000, // - Signalling NaNs - 0x7f923456, 0x7f800001, // Subnormals. - // - A recognisable bit pattern. - 0x00123456, // - The largest subnormal value. - 0x007fffff, // - The smallest subnormal value. - 0x00000001, // The same values again, but negated. + // Simple values: + // 0.0 + 0x00000000, + // The smallest normal value + 0x00800000, + // The value just below 0.5 + 0x3effffff, + // 0.5 + 0x3f000000, + // The value just above 0.5 + 0x3f000001, + // The value just below 1.0 + 0x3f7fffff, + // 1.0 + 0x3f800000, + // The value just above 1.0 + 0x3f800001, + // 1.5 + 0x3fc00000, + // 10 + 0x41200000, + // The largest finite value + 0x7f8fffff, + // Infinity + 0x7f800000, + + // NaNs: + // Quiet NaNs + 0x7fd23456, + 0x7fc00000, + // Signalling NaNs + 0x7f923456, + 0x7f800001, + + // Subnormals: + // A recognisable bit pattern + 0x00123456, + // The largest subnormal value + 0x007fffff, + // The smallest subnormal value + 0x00000001, + + // Other values: + // Above values, negated 0x80000000, 0x80800000, 0xbeffffff, 0xbf000000, 0xbf000001, 0xbf7fffff, 0xbf800000, 0xbf800001, 0xbfc00000, 0xc1200000, 0xff8fffff, 0xff800000, 0xffd23456, 0xffc00000, 0xff923456, 0xff800001, - 0x80123456, 0x807fffff, 0x80000001, + 0x80123456, 0x807fffff, 0x80000001, 0x80123456, 0x807fffff, 0x80000001, + // Random values + 0x4205cccd, 0x4229178D, 0x42C6A0C5, 0x3B3302F7, 0x3F9DF45E, 0x41DAA3D7, 0x47C3501D, 0xC3889333, + 0xC2C675C3, 0xC69C449A, 0xC341FD71, 0xC502DFD7, 0xBBB43958, 0x3EE24DD3, 0x42B1C28F, 0x42F06666, + 0x45D379C3, 0x44637148, 0x3CBBECAB, 0x4113EDFA, 0x444B22F2, 0x1FD93A96, 0x9921055F, 0xFF626925, + + // Specific values: + // Approximately Pi + 0x40490fdb, + // Approximately 1/3 + 0x3eaaaaab, ]; +#[rustfmt::skip] pub const BIT_PATTERNS_64: &[u64] = &[ - // Simple values. - 0x0000000000000000, // 0.0 - 0x0010000000000000, // The smallest normal value. - 0x3fdfffffffffffff, // The value just below 0.5. - 0x3fe0000000000000, // 0.5 - 0x3fe0000000000001, // The value just above 0.5. - 0x3fefffffffffffff, // The value just below 1.0. - 0x3ff0000000000000, // 1.0 - 0x3ff0000000000001, // The value just above 1.0. - 0x3ff8000000000000, // 1.5 - 0x4024000000000000, // 10 - 0x7fefffffffffffff, // The largest finite value. - 0x7ff0000000000000, // Infinity. - // NaNs. - // - Quiet NaNs - 0x7ff923456789abcd, - 0x7ff8000000000000, - // - Signalling NaNs - 0x7ff123456789abcd, + // Simple values: + // 0.0 + 0x0000000000000000, + // The smallest normal value + 0x0010000000000000, + // The value just below 0.5 + 0x3fdfffffffffffff, + // 0.5 + 0x3fe0000000000000, + // The value just above 0.5 + 0x3fe0000000000001, + // The value just below 1.0 + 0x3fefffffffffffff, + // 1.0 + 0x3ff0000000000000, + // The value just above 1.0 + 0x3ff0000000000001, + // 1.5 + 0x3ff8000000000000, + // 10 + 0x4024000000000000, + // The largest finite value + 0x7fefffffffffffff, + // Infinity 0x7ff0000000000000, - // Subnormals. - // - A recognisable bit pattern. + + // NaNs: + // Quiet NaNs + 0x7ff923456789abcd, 0x7ff8000000000000, + // Signalling NaNs + 0x7ff123456789abcd, 0x7ff0000000000000, + + // Subnormals: + // A recognisable bit pattern 0x000123456789abcd, - // - The largest subnormal value. + // The largest subnormal value 0x000fffffffffffff, - // - The smallest subnormal value. + // The smallest subnormal value 0x0000000000000001, - // The same values again, but negated. - 0x8000000000000000, - 0x8010000000000000, - 0xbfdfffffffffffff, - 0xbfe0000000000000, - 0xbfe0000000000001, - 0xbfefffffffffffff, - 0xbff0000000000000, - 0xbff0000000000001, - 0xbff8000000000000, - 0xc024000000000000, - 0xffefffffffffffff, - 0xfff0000000000000, - 0xfff923456789abcd, - 0xfff8000000000000, - 0xfff123456789abcd, - 0xfff0000000000000, - 0x800123456789abcd, - 0x800fffffffffffff, - 0x8000000000000001, + + // Other values: + // Above values, negated + 0x8000000000000000, 0x8010000000000000, 0xbfdfffffffffffff, 0xbfe0000000000000, + 0xbfe0000000000001, 0xbfefffffffffffff, 0xbff0000000000000, 0xbff0000000000001, + 0xbff8000000000000, 0xc024000000000000, 0xffefffffffffffff, 0xfff0000000000000, + 0xfff923456789abcd, 0xfff8000000000000, 0xfff123456789abcd, 0xfff0000000000000, + 0x800123456789abcd, 0x800fffffffffffff, 0x8000000000000001, + + // Specific values: + // Pi + 0x400921FB54442D18, + // Approximately 1/3 + 0x3fd5555555555555, ]; From d036bf9895844ef20be01de86d474ddd8e90d5f9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 10:31:00 +0000 Subject: [PATCH 7/8] intrinsic-test: remove redundant bit pattern consts This isn't strictly optimal as it means that the 5/6/7 bit cases are less likely to be tested with values at the edges (e.g. `0x7e` for 7 bits). --- crates/intrinsic-test/src/common/values.rs | 28 ++-------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index 7f7d10656f..def040654c 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -110,14 +110,7 @@ pub fn test_values_array_length(ty: &IntrinsicType) -> u32 { pub fn bit_pattern_for_test_values_array(bits: u32, index: u32) -> u64 { let index = index as usize; match bits { - 1 => BIT_PATTERNS_8[index % 2].into(), - 2 => BIT_PATTERNS_8[index % 4].into(), - 3 => BIT_PATTERNS_8[index % 8].into(), - 4 => BIT_PATTERNS_8[index % 16].into(), - 5 => BIT_PATTERNS_5[index % BIT_PATTERNS_5.len()].into(), - 6 => BIT_PATTERNS_6[index % BIT_PATTERNS_6.len()].into(), - 7 => BIT_PATTERNS_7[index % BIT_PATTERNS_7.len()].into(), - 8 => BIT_PATTERNS_8[index % BIT_PATTERNS_8.len()].into(), + bits @ (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8) => BIT_PATTERNS_8[index % (1 << bits)].into(), 16 => BIT_PATTERNS_16[index % BIT_PATTERNS_16.len()].into(), 32 => BIT_PATTERNS_32[index % BIT_PATTERNS_32.len()].into(), 64 => BIT_PATTERNS_64[index % BIT_PATTERNS_64.len()], @@ -125,24 +118,7 @@ pub fn bit_pattern_for_test_values_array(bits: u32, index: u32) -> u64 { } } -pub const BIT_PATTERNS_5: &[u8] = &[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x019, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, - 0x1f, -]; - -pub const BIT_PATTERNS_6: &[u8] = &[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x039, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, -]; - -pub const BIT_PATTERNS_7: &[u8] = &[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x079, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, - 0x7f, -]; - +// Contains every possible 8-bit value in order pub const BIT_PATTERNS_8: &[u8] = &[ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, From b37a96ca516cba1b230306303dbb58a5b26b266c Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 20 May 2026 10:37:50 +0000 Subject: [PATCH 8/8] intrinsic-test: move/rename `gen_arg_rust` This function doesn't really generate an argument at all, it writes a static that is eventually loaded from to become the argument. --- crates/intrinsic-test/src/common/argument.rs | 23 +---------------- crates/intrinsic-test/src/common/gen_rust.rs | 5 ++-- crates/intrinsic-test/src/common/values.rs | 26 +++++++++++++++++++- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 8b07224ef7..eaec5b71c4 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::values::{test_values_array, test_values_array_length, test_values_array_name}; +use crate::common::values::test_values_array_name; use super::PASSES; use super::constraint::Constraint; @@ -155,27 +155,6 @@ where .join("") } - /// Returns a string defining a static variable with test values used for all intrinsics with - /// arguments of `arg`'s type. - /// - /// e.g. - /// ```rust,ignore - /// static U8_20: [u8; 20] = [ - /// 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xf0, - /// 0x80, 0x3b, 0xff, - /// ]; - /// ``` - pub fn gen_arg_rust(arg: &Argument, w: &mut impl std::io::Write) -> std::io::Result<()> { - writeln!( - w, - "static {name}: [{ty}; {load_size}] = {values};\n", - name = test_values_array_name(&arg.ty), - ty = arg.ty.rust_scalar_type(), - load_size = test_values_array_length(&arg.ty), - values = test_values_array(&arg.ty) - ) - } - /// Returns a string defining a local variable for each argument and loading a value into each /// using a load intrinsic. /// diff --git a/crates/intrinsic-test/src/common/gen_rust.rs b/crates/intrinsic-test/src/common/gen_rust.rs index 330670306e..15087de75a 100644 --- a/crates/intrinsic-test/src/common/gen_rust.rs +++ b/crates/intrinsic-test/src/common/gen_rust.rs @@ -4,10 +4,9 @@ use itertools::Itertools; use super::intrinsic_helpers::IntrinsicTypeDefinition; use crate::common::PASSES; -use crate::common::argument::ArgumentList; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::values::test_values_array_name; +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 /// a wrapper around float types that defines `NaN`s to be equal reflexively to enable @@ -135,7 +134,7 @@ pub fn write_lib_rs( let name = test_values_array_name(&arg.ty); if seen.insert(name) { - ArgumentList::gen_arg_rust(arg, w)?; + test_values_array_static(w, &arg.ty)?; } } } diff --git a/crates/intrinsic-test/src/common/values.rs b/crates/intrinsic-test/src/common/values.rs index def040654c..4c3dd078e0 100644 --- a/crates/intrinsic-test/src/common/values.rs +++ b/crates/intrinsic-test/src/common/values.rs @@ -8,6 +8,30 @@ use crate::common::{ /// Maximum size of a SVE vector pub const MAX_SVE_BITS: u32 = 2048; +/// Writes a string defining a static variable with test values used for all intrinsics with +/// arguments of type `ty` to `w`. +/// +/// e.g. +/// ```rust,ignore +/// static U8_20: [u8; 20] = [ +/// 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xf0, +/// 0x80, 0x3b, 0xff, +/// ]; +/// ``` +pub fn test_values_array_static( + w: &mut impl std::io::Write, + ty: &T, +) -> std::io::Result<()> { + writeln!( + w, + "static {name}: [{ty}; {load_size}] = {values};\n", + name = test_values_array_name(ty), + ty = ty.rust_scalar_type(), + load_size = test_values_array_length(&ty), + values = test_values_array(&ty) + ) +} + /// Returns a string with the name of the static variable containing test values for intrinsic /// arguments of this type. pub fn test_values_array_name(ty: &T) -> String { @@ -20,7 +44,7 @@ pub fn test_values_array_name(ty: &T) -> String { /// Returns the elements used in the test value arrays in `gen_arg_rust`. Uses the /// `test_values_array_length` fn to determine the number of values that -/// `ArgumentList::gen_arg_rust` expects and `ArgumentList::load_values_rust` needs. +/// `test_values_array_static` expects and `ArgumentList::load_values_rust` needs. /// /// Each value in the array starts as a bit pattern from `bit_pattern_for_test_values_array` /// which is then printed as a hex value in the generated code (and if identified as a negative