about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-07-11 22:10:56 +0200
committerFolkert de Vries <folkert@folkertdev.nl>2025-07-19 02:11:15 +0200
commit3051039b945f77a55e2fbbd1aceabfd147542746 (patch)
tree14a6ba0e5c2ac9d7d2abde0010fb43b9817ca9b8
parent83804bf2ce8198c19144bc89e6e8e0f2c571b449 (diff)
downloadrust-3051039b945f77a55e2fbbd1aceabfd147542746.tar.gz
rust-3051039b945f77a55e2fbbd1aceabfd147542746.zip
generate arrays of type-erased function pointers
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/types.rs19
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/argument.rs8
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs126
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs3
4 files changed, 73 insertions, 83 deletions
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/types.rs b/library/stdarch/crates/intrinsic-test/src/arm/types.rs
index 77f5e8d0e56..c06e9355c44 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/types.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/types.rs
@@ -33,25 +33,6 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType {
         }
     }
 
-    fn rust_type(&self) -> String {
-        let rust_prefix = self.0.kind.rust_prefix();
-        let c_prefix = self.0.kind.c_prefix();
-        if self.0.ptr_constant {
-            self.c_type()
-        } else if let (Some(bit_len), simd_len, vec_len) =
-            (self.0.bit_len, self.0.simd_len, self.0.vec_len)
-        {
-            match (simd_len, vec_len) {
-                (None, None) => format!("{rust_prefix}{bit_len}"),
-                (Some(simd), None) => format!("{c_prefix}{bit_len}x{simd}_t"),
-                (Some(simd), Some(vec)) => format!("{c_prefix}{bit_len}x{simd}x{vec}_t"),
-                (None, Some(_)) => todo!("{:#?}", self), // Likely an invalid case
-            }
-        } else {
-            todo!("{:#?}", self)
-        }
-    }
-
     /// Determines the load function for this type.
     fn get_load_function(&self, language: Language) -> String {
         if let IntrinsicType {
diff --git a/library/stdarch/crates/intrinsic-test/src/common/argument.rs b/library/stdarch/crates/intrinsic-test/src/common/argument.rs
index 9cba8c90d9f..1550cbd97f5 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/argument.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/argument.rs
@@ -114,14 +114,6 @@ where
             .join(", ")
     }
 
-    pub fn as_constraint_parameters_rust(&self) -> String {
-        self.iter()
-            .filter(|a| a.has_constraint())
-            .map(|arg| arg.name.clone())
-            .collect::<Vec<String>>()
-            .join(", ")
-    }
-
     /// Creates a line for each argument that initializes an array for C from which `loads` argument
     /// values can be loaded  as a sliding window.
     /// e.g `const int32x2_t a_vals = {0x3effffff, 0x3effffff, 0x3f7fffff}`, if loads=2.
diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs
index 96b09b09f31..60bb577a80c 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs
@@ -1,7 +1,6 @@
 use itertools::Itertools;
 use std::process::Command;
 
-use super::argument::Argument;
 use super::indentation::Indentation;
 use super::intrinsic::{IntrinsicDefinition, format_f16_return_value};
 use super::intrinsic_helpers::IntrinsicTypeDefinition;
@@ -188,66 +187,87 @@ pub fn generate_rust_test_loop<T: IntrinsicTypeDefinition>(
     w: &mut impl std::io::Write,
     intrinsic: &dyn IntrinsicDefinition<T>,
     indentation: Indentation,
-    additional: &str,
+    specializations: &[Vec<u8>],
     passes: u32,
 ) -> std::io::Result<()> {
-    let constraints = intrinsic.arguments().as_constraint_parameters_rust();
-    let constraints = if !constraints.is_empty() {
-        format!("::<{constraints}>")
-    } else {
-        constraints
-    };
+    let intrinsic_name = intrinsic.name();
+
+    // Each function (and each specialization) has its own type. Erase that type with a cast.
+    let mut coerce = String::from("unsafe fn(");
+    for _ in intrinsic.arguments().iter().filter(|a| !a.has_constraint()) {
+        coerce += "_, ";
+    }
+    coerce += ") -> _";
+
+    match specializations {
+        [] => {
+            writeln!(w, "    let specializations = [(\"\", {intrinsic_name})];")?;
+        }
+        [const_args] if const_args.is_empty() => {
+            writeln!(w, "    let specializations = [(\"\", {intrinsic_name})];")?;
+        }
+        _ => {
+            writeln!(w, "    let specializations = [")?;
+
+            for specialization in specializations {
+                let mut specialization: Vec<_> =
+                    specialization.iter().map(|d| d.to_string()).collect();
+
+                let const_args = specialization.join(",");
+
+                // The identifier is reversed.
+                specialization.reverse();
+                let id = specialization.join("-");
+
+                writeln!(
+                    w,
+                    "        (\"-{id}\", {intrinsic_name}::<{const_args}> as {coerce}),"
+                )?;
+            }
+
+            writeln!(w, "    ];")?;
+        }
+    }
 
     let return_value = format_f16_return_value(intrinsic);
     let indentation2 = indentation.nested();
     let indentation3 = indentation2.nested();
     writeln!(
         w,
-        "{indentation}for i in 0..{passes} {{\n\
-            {indentation2}unsafe {{\n\
-                {loaded_args}\
-                {indentation3}let __return_value = {intrinsic_call}{const}({args});\n\
-                {indentation3}println!(\"Result {additional}-{{}}: {{:?}}\", i + 1, {return_value});\n\
-            {indentation2}}}\n\
-        {indentation}}}",
+        "\
+            for (id, f) in specializations {{\n\
+                for i in 0..{passes} {{\n\
+                    unsafe {{\n\
+                        {loaded_args}\
+                        let __return_value = f({args});\n\
+                        println!(\"Result {{id}}-{{}}: {{:?}}\", i + 1, {return_value});\n\
+                    }}\n\
+                }}\n\
+            }}",
         loaded_args = intrinsic.arguments().load_values_rust(indentation3),
-        intrinsic_call = intrinsic.name(),
-        const = constraints,
         args = intrinsic.arguments().as_call_param_rust(),
     )
 }
 
-fn generate_rust_constraint_blocks<'a, T: IntrinsicTypeDefinition + 'a>(
-    w: &mut impl std::io::Write,
-    intrinsic: &dyn IntrinsicDefinition<T>,
-    indentation: Indentation,
-    constraints: &mut (impl Iterator<Item = &'a Argument<T>> + Clone),
-    name: String,
-) -> std::io::Result<()> {
-    let Some(current) = constraints.next() else {
-        return generate_rust_test_loop(w, intrinsic, indentation, &name, PASSES);
-    };
-
-    let body_indentation = indentation.nested();
-    for i in current.constraint.iter().flat_map(|c| c.to_range()) {
-        let ty = current.ty.rust_type();
-
-        writeln!(w, "{indentation}{{")?;
-
-        writeln!(w, "{body_indentation}const {}: {ty} = {i};", current.name)?;
-
-        generate_rust_constraint_blocks(
-            w,
-            intrinsic,
-            body_indentation,
-            &mut constraints.clone(),
-            format!("{name}-{i}"),
-        )?;
-
-        writeln!(w, "{indentation}}}")?;
+/// Generate the specializations (unique sequences of const-generic arguments) for this intrinsic.
+fn generate_rust_specializations<'a>(
+    constraints: &mut impl Iterator<Item = std::ops::Range<i64>>,
+) -> Vec<Vec<u8>> {
+    let mut specializations = vec![vec![]];
+
+    for constraint in constraints {
+        specializations = constraint
+            .flat_map(|right| {
+                specializations.iter().map(move |left| {
+                    let mut left = left.clone();
+                    left.push(u8::try_from(right).unwrap());
+                    left
+                })
+            })
+            .collect();
     }
 
-    Ok(())
+    specializations
 }
 
 // Top-level function to create complete test program
@@ -265,13 +285,13 @@ pub fn create_rust_test_module<T: IntrinsicTypeDefinition>(
     arguments.gen_arglists_rust(w, indentation.nested(), PASSES)?;
 
     // Define any const generics as `const` items, then generate the actual test loop.
-    generate_rust_constraint_blocks(
-        w,
-        intrinsic,
-        indentation.nested(),
-        &mut arguments.iter().rev().filter(|i| i.has_constraint()),
-        Default::default(),
-    )?;
+    let specializations = generate_rust_specializations(
+        &mut arguments
+            .iter()
+            .filter_map(|i| i.constraint.as_ref().map(|v| v.to_range())),
+    );
+
+    generate_rust_test_loop(w, intrinsic, indentation, &specializations, PASSES)?;
 
     writeln!(w, "}}")?;
 
diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs
index 697f9c8754d..b53047b2d38 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs
@@ -332,7 +332,4 @@ pub trait IntrinsicTypeDefinition: Deref<Target = IntrinsicType> {
 
     /// can be directly defined in `impl` blocks
     fn c_single_vector_type(&self) -> String;
-
-    /// can be defined in `impl` blocks
-    fn rust_type(&self) -> String;
 }