about summary refs log tree commit diff
path: root/library/stdarch/crates/intrinsic-test/src
diff options
context:
space:
mode:
authorMadhav Madhusoodanan <f20200049@pilani.bits-pilani.ac.in>2025-04-16 14:31:42 +0530
committerAmanieu d'Antras <amanieu@gmail.com>2025-05-27 23:27:38 +0000
commit57c357591e22c32865715f4b00bbc66442f0a8d6 (patch)
treee43e1a62f3d58dc8b7aec5b1d48978ff0244233c /library/stdarch/crates/intrinsic-test/src
parenta993b4427cda5a2a5a4d3d34f341c11ee00b3cdd (diff)
downloadrust-57c357591e22c32865715f4b00bbc66442f0a8d6.tar.gz
rust-57c357591e22c32865715f4b00bbc66442f0a8d6.zip
introduced generic types and code refactor
Diffstat (limited to 'library/stdarch/crates/intrinsic-test/src')
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/constraint.rs60
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/functions.rs38
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs115
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs36
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/mod.rs11
-rw-r--r--library/stdarch/crates/intrinsic-test/src/arm/types.rs574
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/argument.rs (renamed from library/stdarch/crates/intrinsic-test/src/arm/argument.rs)167
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/format.rs (renamed from library/stdarch/crates/intrinsic-test/src/arm/format.rs)0
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs91
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/intrinsic_types.rs352
-rw-r--r--library/stdarch/crates/intrinsic-test/src/common/mod.rs4
11 files changed, 808 insertions, 640 deletions
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/constraint.rs b/library/stdarch/crates/intrinsic-test/src/arm/constraint.rs
new file mode 100644
index 00000000000..777cbd0099a
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/arm/constraint.rs
@@ -0,0 +1,60 @@
+use super::json_parser::ArgPrep;
+
+use crate::common::argument::MetadataDefinition;
+use serde::Deserialize;
+use serde_json::Value;
+use std::ops::Range;
+
+#[derive(Debug, PartialEq, Clone, Deserialize)]
+pub enum Constraint {
+    Equal(i64),
+    Range(Range<i64>),
+}
+
+impl Constraint {
+    pub fn to_range(&self) -> Range<i64> {
+        match self {
+            Constraint::Equal(eq) => *eq..*eq + 1,
+            Constraint::Range(range) => range.clone(),
+        }
+    }
+}
+
+impl MetadataDefinition for Constraint {
+    fn from_metadata(metadata: Option<Value>) -> Vec<Box<Self>> {
+        let arg_prep: Option<ArgPrep> = metadata.and_then(|a| {
+            if let Value::Object(_) = a {
+                a.try_into().ok()
+            } else {
+                None
+            }
+        });
+        let constraint: Option<Constraint> = arg_prep.and_then(|a| a.try_into().ok());
+        vec![constraint]
+            .into_iter()
+            .filter_map(|a| a)
+            .map(|a| Box::new(a))
+            .collect()
+    }
+}
+
+/// ARM-specific
+impl TryFrom<ArgPrep> for Constraint {
+    type Error = ();
+
+    fn try_from(prep: ArgPrep) -> Result<Self, Self::Error> {
+        let parsed_ints = match prep {
+            ArgPrep::Immediate { min, max } => Ok((min, max)),
+            _ => Err(()),
+        };
+        if let Ok((min, max)) = parsed_ints {
+            if min == max {
+                Ok(Constraint::Equal(min))
+            } else {
+                Ok(Constraint::Range(min..max + 1))
+            }
+        } else {
+            Err(())
+        }
+    }
+}
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/functions.rs b/library/stdarch/crates/intrinsic-test/src/arm/functions.rs
index a23bac991ff..8158dfd88da 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/functions.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/functions.rs
@@ -1,9 +1,12 @@
-use super::argument::Argument;
 use super::config::{AARCH_CONFIGURATIONS, POLY128_OSTREAM_DEF, build_notices};
-use super::format::Indentation;
-use super::intrinsic::Intrinsic;
+use super::intrinsic::ArmIntrinsicType;
+use crate::arm::constraint::Constraint;
+use crate::common::argument::Argument;
+use crate::common::format::Indentation;
 use crate::common::gen_c::{compile_c, create_c_filenames, generate_c_program};
 use crate::common::gen_rust::{compile_rust, create_rust_filenames, generate_rust_program};
+use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
+use crate::common::intrinsic_types::IntrinsicTypeDefinition;
 use crate::common::write_file;
 use itertools::Itertools;
 use rayon::prelude::*;
@@ -14,14 +17,14 @@ const PASSES: u32 = 20;
 
 fn gen_code_c(
     indentation: Indentation,
-    intrinsic: &Intrinsic,
-    constraints: &[&Argument],
+    intrinsic: &Intrinsic<ArmIntrinsicType, Constraint>,
+    constraints: &[&Argument<ArmIntrinsicType, Constraint>],
     name: String,
     target: &str,
 ) -> String {
     if let Some((current, constraints)) = constraints.split_last() {
         let range = current
-            .constraints
+            .metadata
             .iter()
             .map(|c| c.to_range())
             .flat_map(|r| r.into_iter());
@@ -52,11 +55,15 @@ fn gen_code_c(
     }
 }
 
-fn generate_c_program_arm(header_files: &[&str], intrinsic: &Intrinsic, target: &str) -> String {
+fn generate_c_program_arm(
+    header_files: &[&str],
+    intrinsic: &Intrinsic<ArmIntrinsicType, Constraint>,
+    target: &str,
+) -> String {
     let constraints = intrinsic
         .arguments
         .iter()
-        .filter(|i| i.has_constraint())
+        .filter(|&i| i.has_constraint())
         .collect_vec();
 
     let indentation = Indentation::default();
@@ -82,13 +89,13 @@ fn generate_c_program_arm(header_files: &[&str], intrinsic: &Intrinsic, target:
 
 fn gen_code_rust(
     indentation: Indentation,
-    intrinsic: &Intrinsic,
-    constraints: &[&Argument],
+    intrinsic: &Intrinsic<ArmIntrinsicType, Constraint>,
+    constraints: &[&Argument<ArmIntrinsicType, Constraint>],
     name: String,
 ) -> String {
     if let Some((current, constraints)) = constraints.split_last() {
         let range = current
-            .constraints
+            .metadata
             .iter()
             .map(|c| c.to_range())
             .flat_map(|r| r.into_iter());
@@ -118,7 +125,10 @@ fn gen_code_rust(
     }
 }
 
-fn generate_rust_program_arm(intrinsic: &Intrinsic, target: &str) -> String {
+fn generate_rust_program_arm(
+    intrinsic: &Intrinsic<ArmIntrinsicType, Constraint>,
+    target: &str,
+) -> String {
     let constraints = intrinsic
         .arguments
         .iter()
@@ -220,7 +230,7 @@ fn compile_c_arm(
 }
 
 pub fn build_c(
-    intrinsics: &Vec<Intrinsic>,
+    intrinsics: &Vec<Intrinsic<ArmIntrinsicType, Constraint>>,
     compiler: Option<&str>,
     target: &str,
     cxx_toolchain_dir: Option<&str>,
@@ -252,7 +262,7 @@ pub fn build_c(
 }
 
 pub fn build_rust(
-    intrinsics: &[Intrinsic],
+    intrinsics: &[Intrinsic<ArmIntrinsicType, Constraint>],
     toolchain: Option<&str>,
     target: &str,
     linker: Option<&str>,
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs
index b2d242ab736..126e4712f99 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/intrinsic.rs
@@ -1,40 +1,83 @@
-use super::argument::ArgumentList;
-use super::format::Indentation;
-use super::types::{IntrinsicType, TypeKind};
+use super::constraint::Constraint;
+use crate::common::argument::ArgumentList;
+use crate::common::format::Indentation;
+use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
+use crate::common::intrinsic_types::{
+    BaseIntrinsicTypeDefinition, IntrinsicType, IntrinsicTypeDefinition, TypeKind,
+};
+use crate::common::types::Language;
 
-/// An intrinsic
-#[derive(Debug, PartialEq, Clone)]
-pub struct Intrinsic {
-    /// The function name of this intrinsic.
-    pub name: String,
+#[derive(Debug, Clone, PartialEq)]
+pub struct ArmIntrinsicType(pub IntrinsicType);
 
-    /// Any arguments for this intrinsic.
-    pub arguments: ArgumentList,
+impl BaseIntrinsicTypeDefinition for ArmIntrinsicType {
+    fn kind(&self) -> TypeKind {
+        self.0.kind()
+    }
+    fn inner_size(&self) -> u32 {
+        self.0.inner_size()
+    }
+    fn num_lanes(&self) -> u32 {
+        self.0.num_lanes()
+    }
+    fn num_vectors(&self) -> u32 {
+        self.0.num_vectors()
+    }
+    fn is_simd(&self) -> bool {
+        self.0.is_simd()
+    }
+    fn is_ptr(&self) -> bool {
+        self.0.is_ptr()
+    }
+    fn c_scalar_type(&self) -> String {
+        self.0.c_scalar_type()
+    }
+    fn rust_scalar_type(&self) -> String {
+        self.0.rust_scalar_type()
+    }
+    fn c_promotion(&self) -> &str {
+        self.0.c_promotion()
+    }
+    fn populate_random(&self, indentation: Indentation, loads: u32, language: &Language) -> String {
+        self.0.populate_random(indentation, loads, language)
+    }
+    fn is_rust_vals_array_const(&self) -> bool {
+        self.0.is_rust_vals_array_const()
+    }
+    fn as_call_param_c(&self, name: &String) -> String {
+        self.0.as_call_param_c(name)
+    }
+}
 
-    /// The return type of this intrinsic.
-    pub results: IntrinsicType,
+impl IntrinsicDefinition<ArmIntrinsicType, Constraint> for Intrinsic<ArmIntrinsicType, Constraint> {
+    fn arguments(&self) -> ArgumentList<ArmIntrinsicType, Constraint> {
+        self.arguments.clone()
+    }
 
-    /// Whether this intrinsic is only available on A64.
-    pub a64_only: bool,
-}
+    fn results(&self) -> ArmIntrinsicType {
+        self.results.clone()
+    }
+
+    fn name(&self) -> String {
+        self.name.clone()
+    }
 
-impl Intrinsic {
     /// Generates a std::cout for the intrinsics results that will match the
     /// rust debug output format for the return type. The generated line assumes
     /// there is an int i in scope which is the current pass number.
-    pub fn print_result_c(&self, indentation: Indentation, additional: &str) -> String {
-        let lanes = if self.results.num_vectors() > 1 {
-            (0..self.results.num_vectors())
+    fn print_result_c(&self, indentation: Indentation, additional: &str) -> String {
+        let lanes = if self.results().num_vectors() > 1 {
+            (0..self.results().num_vectors())
                 .map(|vector| {
                     format!(
                         r#""{ty}(" << {lanes} << ")""#,
-                        ty = self.results.c_single_vector_type(),
-                        lanes = (0..self.results.num_lanes())
+                        ty = self.results().c_single_vector_type(),
+                        lanes = (0..self.results().num_lanes())
                             .map(move |idx| -> std::string::String {
                                 format!(
                                     "{cast}{lane_fn}(__return_value.val[{vector}], {lane})",
-                                    cast = self.results.c_promotion(),
-                                    lane_fn = self.results.get_lane_function(),
+                                    cast = self.results().c_promotion(),
+                                    lane_fn = self.results().get_lane_function(),
                                     lane = idx,
                                     vector = vector,
                                 )
@@ -45,13 +88,13 @@ impl Intrinsic {
                 })
                 .collect::<Vec<_>>()
                 .join(r#" << ", " << "#)
-        } else if self.results.num_lanes() > 1 {
-            (0..self.results.num_lanes())
+        } else if self.results().num_lanes() > 1 {
+            (0..self.results().num_lanes())
                 .map(|idx| -> std::string::String {
                     format!(
                         "{cast}{lane_fn}(__return_value, {lane})",
-                        cast = self.results.c_promotion(),
-                        lane_fn = self.results.get_lane_function(),
+                        cast = self.results().c_promotion(),
+                        lane_fn = self.results().get_lane_function(),
                         lane = idx
                     )
                 })
@@ -61,22 +104,22 @@ impl Intrinsic {
             format!(
                 "{promote}cast<{cast}>(__return_value)",
                 cast = match self.results.kind() {
-                    TypeKind::Float if self.results.inner_size() == 16 => "float16_t".to_string(),
-                    TypeKind::Float if self.results.inner_size() == 32 => "float".to_string(),
-                    TypeKind::Float if self.results.inner_size() == 64 => "double".to_string(),
-                    TypeKind::Int => format!("int{}_t", self.results.inner_size()),
-                    TypeKind::UInt => format!("uint{}_t", self.results.inner_size()),
-                    TypeKind::Poly => format!("poly{}_t", self.results.inner_size()),
+                    TypeKind::Float if self.results().inner_size() == 16 => "float16_t".to_string(),
+                    TypeKind::Float if self.results().inner_size() == 32 => "float".to_string(),
+                    TypeKind::Float if self.results().inner_size() == 64 => "double".to_string(),
+                    TypeKind::Int => format!("int{}_t", self.results().inner_size()),
+                    TypeKind::UInt => format!("uint{}_t", self.results().inner_size()),
+                    TypeKind::Poly => format!("poly{}_t", self.results().inner_size()),
                     ty => todo!("print_result_c - Unknown type: {:#?}", ty),
                 },
-                promote = self.results.c_promotion(),
+                promote = self.results().c_promotion(),
             )
         };
 
         format!(
             r#"{indentation}std::cout << "Result {additional}-" << i+1 << ": {ty}" << std::fixed << std::setprecision(150) <<  {lanes} << "{close}" << std::endl;"#,
-            ty = if self.results.is_simd() {
-                format!("{}(", self.results.c_type())
+            ty = if self.results().is_simd() {
+                format!("{}(", self.results().c_type())
             } else {
                 String::from("")
             },
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs b/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs
index 001d721fa6b..2f49b84c67f 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs
@@ -1,6 +1,8 @@
-use super::argument::{Argument, ArgumentList};
-use super::intrinsic::Intrinsic;
-use super::types::IntrinsicType;
+use super::constraint::Constraint;
+use super::intrinsic::ArmIntrinsicType;
+use crate::common::argument::{Argument, ArgumentList};
+use crate::common::intrinsic::Intrinsic;
+use crate::common::intrinsic_types::{IntrinsicType, IntrinsicTypeDefinition};
 use serde::Deserialize;
 use serde_json::Value;
 use std::collections::HashMap;
@@ -53,7 +55,7 @@ struct JsonIntrinsic {
 pub fn get_neon_intrinsics(
     filename: &Path,
     target: &String,
-) -> Result<Vec<Intrinsic>, Box<dyn std::error::Error>> {
+) -> Result<Vec<Intrinsic<ArmIntrinsicType, Constraint>>, Box<dyn std::error::Error>> {
     let file = std::fs::File::open(filename)?;
     let reader = std::io::BufReader::new(file);
     let json: Vec<JsonIntrinsic> = serde_json::from_reader(reader).expect("Couldn't parse JSON");
@@ -74,37 +76,39 @@ pub fn get_neon_intrinsics(
 fn json_to_intrinsic(
     mut intr: JsonIntrinsic,
     target: &String,
-) -> Result<Intrinsic, Box<dyn std::error::Error>> {
+) -> Result<Intrinsic<ArmIntrinsicType, Constraint>, Box<dyn std::error::Error>> {
     let name = intr.name.replace(['[', ']'], "");
 
-    let results = IntrinsicType::from_c(&intr.return_type.value, target)?;
+    let results = ArmIntrinsicType::from_c(&intr.return_type.value, target)?;
 
     let args = intr
         .arguments
         .into_iter()
         .enumerate()
         .map(|(i, arg)| {
-            // let arg_name = Argument::type_and_name_from_c(&arg).1;
-            let mut arg = Argument::from_c(i, &arg, target, intr.args_prep.as_mut());
+            let arg_name = Argument::<ArmIntrinsicType, Constraint>::type_and_name_from_c(&arg).1;
+            let metadata = intr.args_prep.as_mut();
+            let metadata = metadata.and_then(|a| a.remove(arg_name));
+            let mut arg =
+                Argument::<ArmIntrinsicType, Constraint>::from_c(i, &arg, target, metadata);
+
             // The JSON doesn't list immediates as const
-            if let IntrinsicType::Type {
+            let IntrinsicType {
                 ref mut constant, ..
-            } = arg.ty
-            {
-                if arg.name.starts_with("imm") {
-                    *constant = true
-                }
+            } = arg.ty.0;
+            if arg.name.starts_with("imm") {
+                *constant = true
             }
             arg
         })
         .collect();
 
-    let arguments = ArgumentList { args };
+    let arguments = ArgumentList::<ArmIntrinsicType, Constraint> { args };
 
     Ok(Intrinsic {
         name,
         arguments,
-        results,
+        results: *results,
         a64_only: intr.architectures == vec!["A64".to_string()],
     })
 }
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
index 8d94250c53b..cef32c3fb61 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs
@@ -1,21 +1,22 @@
-mod argument;
 mod config;
-mod format;
+mod constraint;
 mod functions;
 mod intrinsic;
 mod json_parser;
 mod types;
 
+use crate::arm::constraint::Constraint;
+use crate::arm::intrinsic::ArmIntrinsicType;
 use crate::common::SupportedArchitectureTest;
 use crate::common::compare::compare_outputs;
+use crate::common::intrinsic::Intrinsic;
+use crate::common::intrinsic_types::{BaseIntrinsicTypeDefinition, TypeKind};
 use crate::common::types::ProcessedCli;
 use functions::{build_c, build_rust};
-use intrinsic::Intrinsic;
 use json_parser::get_neon_intrinsics;
-use types::TypeKind;
 
 pub struct ArmArchitectureTest {
-    intrinsics: Vec<Intrinsic>,
+    intrinsics: Vec<Intrinsic<ArmIntrinsicType, Constraint>>,
     cli_options: ProcessedCli,
 }
 
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/types.rs b/library/stdarch/crates/intrinsic-test/src/arm/types.rs
index a579e9699d6..db08c3a52dd 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/types.rs
+++ b/library/stdarch/crates/intrinsic-test/src/arm/types.rs
@@ -1,474 +1,125 @@
-use std::fmt;
-use std::str::FromStr;
-
-use itertools::Itertools as _;
-
-use super::format::Indentation;
+use super::intrinsic::ArmIntrinsicType;
+use crate::common::intrinsic_types::{IntrinsicType, IntrinsicTypeDefinition, TypeKind};
 use crate::common::types::Language;
-use crate::common::values::value_for_array;
-
-#[derive(Debug, PartialEq, Copy, Clone)]
-pub enum TypeKind {
-    BFloat,
-    Float,
-    Int,
-    UInt,
-    Poly,
-    Void,
-}
-
-impl FromStr for TypeKind {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "bfloat" => Ok(Self::BFloat),
-            "float" => Ok(Self::Float),
-            "int" => Ok(Self::Int),
-            "poly" => Ok(Self::Poly),
-            "uint" | "unsigned" => Ok(Self::UInt),
-            "void" => Ok(Self::Void),
-            _ => Err(format!("Impossible to parse argument kind {s}")),
-        }
-    }
-}
-
-impl fmt::Display for TypeKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}",
-            match self {
-                Self::BFloat => "bfloat",
-                Self::Float => "float",
-                Self::Int => "int",
-                Self::UInt => "uint",
-                Self::Poly => "poly",
-                Self::Void => "void",
-            }
-        )
-    }
-}
-
-impl TypeKind {
-    /// Gets the type part of a c typedef for a type that's in the form of {type}{size}_t.
-    pub fn c_prefix(&self) -> &str {
-        match self {
-            Self::Float => "float",
-            Self::Int => "int",
-            Self::UInt => "uint",
-            Self::Poly => "poly",
-            _ => unreachable!("Not used: {:#?}", self),
-        }
-    }
-
-    /// Gets the rust prefix for the type kind i.e. i, u, f.
-    pub fn rust_prefix(&self) -> &str {
-        match self {
-            Self::Float => "f",
-            Self::Int => "i",
-            Self::UInt => "u",
-            Self::Poly => "u",
-            _ => unreachable!("Unused type kind: {:#?}", self),
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub enum IntrinsicType {
-    Ptr {
-        constant: bool,
-        child: Box<IntrinsicType>,
-    },
-    Type {
-        constant: bool,
-        kind: TypeKind,
-        /// The bit length of this type (e.g. 32 for u32).
-        bit_len: Option<u32>,
-
-        /// Length of the SIMD vector (i.e. 4 for uint32x4_t), A value of `None`
-        /// means this is not a simd type. A `None` can be assumed to be 1,
-        /// although in some places a distinction is needed between `u64` and
-        /// `uint64x1_t` this signals that.
-        simd_len: Option<u32>,
-
-        /// The number of rows for SIMD matrices (i.e. 2 for uint8x8x2_t).
-        /// A value of `None` represents a type that does not contain any
-        /// rows encoded in the type (e.g. uint8x8_t).
-        /// A value of `None` can be assumed to be 1 though.
-        vec_len: Option<u32>,
-
-        target: String,
-    },
-}
-
-impl IntrinsicType {
-    /// Get the TypeKind for this type, recursing into pointers.
-    pub fn kind(&self) -> TypeKind {
-        match *self {
-            IntrinsicType::Ptr { ref child, .. } => child.kind(),
-            IntrinsicType::Type { kind, .. } => kind,
-        }
-    }
-
-    /// Get the size of a single element inside this type, recursing into
-    /// pointers, i.e. a pointer to a u16 would be 16 rather than the size
-    /// of a pointer.
-    pub fn inner_size(&self) -> u32 {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.inner_size(),
-            IntrinsicType::Type {
-                bit_len: Some(bl), ..
-            } => *bl,
-            _ => unreachable!(""),
-        }
-    }
-
-    pub fn num_lanes(&self) -> u32 {
-        match *self {
-            IntrinsicType::Ptr { ref child, .. } => child.num_lanes(),
-            IntrinsicType::Type {
-                simd_len: Some(sl), ..
-            } => sl,
-            _ => 1,
-        }
-    }
-
-    pub fn num_vectors(&self) -> u32 {
-        match *self {
-            IntrinsicType::Ptr { ref child, .. } => child.num_vectors(),
-            IntrinsicType::Type {
-                vec_len: Some(vl), ..
-            } => vl,
-            _ => 1,
-        }
-    }
-
-    /// Determine if the type is a simd type, this will treat a type such as
-    /// `uint64x1` as simd.
-    pub fn is_simd(&self) -> bool {
-        match *self {
-            IntrinsicType::Ptr { ref child, .. } => child.is_simd(),
-            IntrinsicType::Type {
-                simd_len: None,
-                vec_len: None,
-                ..
-            } => false,
-            _ => true,
-        }
-    }
-
-    pub fn is_ptr(&self) -> bool {
-        match *self {
-            IntrinsicType::Ptr { .. } => true,
-            IntrinsicType::Type { .. } => false,
-        }
-    }
-
-    /// Move to Argument    
-    pub fn c_scalar_type(&self) -> String {
-        format!(
-            "{prefix}{bits}_t",
-            prefix = self.kind().c_prefix(),
-            bits = self.inner_size()
-        )
-    }
-
-    /// Move to Argument
-    pub fn rust_scalar_type(&self) -> String {
-        format!(
-            "{prefix}{bits}",
-            prefix = self.kind().rust_prefix(),
-            bits = self.inner_size()
-        )
-    }
 
+impl IntrinsicTypeDefinition for ArmIntrinsicType {
     /// Gets a string containing the typename for this type in C format.
-    ///
-    /// ARM-specific
-    pub fn c_type(&self) -> String {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.c_type(),
-            IntrinsicType::Type {
-                constant,
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: None,
-                vec_len: None,
-                ..
-            } => format!(
-                "{}{}{}_t",
-                if *constant { "const " } else { "" },
-                kind.c_prefix(),
-                bit_len
-            ),
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: Some(simd_len),
-                vec_len: None,
-                ..
-            } => format!("{}{bit_len}x{simd_len}_t", kind.c_prefix()),
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: Some(simd_len),
-                vec_len: Some(vec_len),
-                ..
-            } => format!("{}{bit_len}x{simd_len}x{vec_len}_t", kind.c_prefix()),
-            _ => todo!("{:#?}", self),
-        }
-    }
-
-    /// ARM-specific
-    pub fn c_single_vector_type(&self) -> String {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.c_single_vector_type(),
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: Some(simd_len),
-                vec_len: Some(_),
-                ..
-            } => format!("{}{bit_len}x{simd_len}_t", kind.c_prefix()),
-            _ => unreachable!("Shouldn't be called on this type"),
-        }
-    }
-
-    /// ARM-specific
-    pub fn rust_type(&self) -> String {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.c_type(),
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: None,
-                vec_len: None,
-                ..
-            } => format!("{}{bit_len}", kind.rust_prefix()),
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: Some(simd_len),
-                vec_len: None,
-                ..
-            } => format!("{}{bit_len}x{simd_len}_t", kind.c_prefix()),
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(bit_len),
-                simd_len: Some(simd_len),
-                vec_len: Some(vec_len),
-                ..
-            } => format!("{}{bit_len}x{simd_len}x{vec_len}_t", kind.c_prefix()),
-            _ => todo!("{:#?}", self),
-        }
-    }
-
-    /// Gets a cast for this type if needs promotion.
-    /// This is required for 8 bit types due to printing as the 8 bit types use
-    /// a char and when using that in `std::cout` it will print as a character,
-    /// which means value of 0 will be printed as a null byte.
-    ///
-    /// This is also needed for polynomial types because we want them to be
-    /// printed as unsigned integers to match Rust's `Debug` impl.
-    pub fn c_promotion(&self) -> &str {
-        match *self {
-            IntrinsicType::Type {
-                kind,
-                bit_len: Some(8),
-                ..
-            } => match kind {
-                TypeKind::Int => "(int)",
-                TypeKind::UInt => "(unsigned int)",
-                TypeKind::Poly => "(unsigned int)(uint8_t)",
-                _ => "",
-            },
-            IntrinsicType::Type {
-                kind: TypeKind::Poly,
-                bit_len: Some(bit_len),
-                ..
-            } => match bit_len {
-                8 => unreachable!("handled above"),
-                16 => "(uint16_t)",
-                32 => "(uint32_t)",
-                64 => "(uint64_t)",
-                128 => "",
-                _ => panic!("invalid bit_len"),
-            },
-            _ => "",
+    fn c_type(&self) -> String {
+        let prefix = self.0.kind.c_prefix();
+        let const_prefix = if self.0.constant { "const " } 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!("{}{}{}_t", const_prefix, prefix, bit_len),
+                (Some(simd), None) => format!("{}{bit_len}x{simd}_t", prefix),
+                (Some(simd), Some(vec)) => format!("{}{bit_len}x{simd}x{vec}_t", prefix),
+                (None, Some(_)) => todo!("{:#?}", self), // Likely an invalid case
+            }
+        } else {
+            todo!("{:#?}", self)
         }
     }
 
-    /// Generates an initialiser for an array, which can be used to initialise an argument for the
-    /// intrinsic call.
-    ///
-    /// This is determistic based on the pass number.
-    ///
-    /// * `loads`: The number of values that need to be loaded from the argument array
-    /// * e.g for argument type uint32x2, loads=2 results in a string representing 4 32-bit values
-    ///
-    /// Returns a string such as
-    /// * `{0x1, 0x7F, 0xFF}` if `language` is `Language::C`
-    /// * `[0x1 as _, 0x7F as _, 0xFF as _]` if `language` is `Language::Rust`
-    pub fn populate_random(
-        &self,
-        indentation: Indentation,
-        loads: u32,
-        language: &Language,
-    ) -> String {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.populate_random(indentation, loads, language),
-            IntrinsicType::Type {
-                bit_len: Some(bit_len @ (8 | 16 | 32 | 64)),
-                kind: kind @ (TypeKind::Int | TypeKind::UInt | TypeKind::Poly),
-                simd_len,
-                vec_len,
-                ..
-            } => {
-                let (prefix, suffix) = match language {
-                    Language::Rust => ("[", "]"),
-                    Language::C => ("{", "}"),
-                };
-                let body_indentation = indentation.nested();
-                format!(
-                    "{prefix}\n{body}\n{indentation}{suffix}",
-                    body = (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
-                        .format_with(",\n", |i, fmt| {
-                            let src = value_for_array(*bit_len, i);
-                            assert!(src == 0 || src.ilog2() < *bit_len);
-                            if *kind == TypeKind::Int && (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;
-                                if (twos_compl == src) && (language == &Language::C) {
-                                    // `src` is INT*_MIN. C requires `-0x7fffffff - 1` to avoid
-                                    // undefined literal overflow behaviour.
-                                    fmt(&format_args!("{body_indentation}-{ones_compl:#x} - 1"))
-                                } else {
-                                    fmt(&format_args!("{body_indentation}-{twos_compl:#x}"))
-                                }
-                            } else {
-                                fmt(&format_args!("{body_indentation}{src:#x}"))
-                            }
-                        })
-                )
-            }
-            IntrinsicType::Type {
-                kind: TypeKind::Float,
-                bit_len: Some(bit_len @ (16 | 32 | 64)),
-                simd_len,
-                vec_len,
-                ..
-            } => {
-                let (prefix, cast_prefix, cast_suffix, suffix) = match (language, bit_len) {
-                    (&Language::Rust, 16) => ("[", "f16::from_bits(", ")", "]"),
-                    (&Language::Rust, 32) => ("[", "f32::from_bits(", ")", "]"),
-                    (&Language::Rust, 64) => ("[", "f64::from_bits(", ")", "]"),
-                    (&Language::C, 16) => ("{", "cast<float16_t, uint16_t>(", ")", "}"),
-                    (&Language::C, 32) => ("{", "cast<float, uint32_t>(", ")", "}"),
-                    (&Language::C, 64) => ("{", "cast<double, uint64_t>(", ")", "}"),
-                    _ => unreachable!(),
-                };
-                format!(
-                    "{prefix}\n{body}\n{indentation}{suffix}",
-                    body = (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
-                        .format_with(",\n", |i, fmt| fmt(&format_args!(
-                            "{indentation}{cast_prefix}{src:#x}{cast_suffix}",
-                            indentation = indentation.nested(),
-                            src = value_for_array(*bit_len, i)
-                        )))
-                )
+    fn c_single_vector_type(&self) -> String {
+        if let (Some(bit_len), Some(simd_len)) = (self.0.bit_len, self.0.simd_len) {
+            let prefix = self.0.kind.c_prefix();
+            format!("{}{bit_len}x{simd_len}_t", prefix)
+        } else {
+            unreachable!("Shouldn't be called on this type")
+        }
+    }
+
+    fn rust_type(&self) -> String {
+        let rust_prefix = self.0.kind.rust_prefix();
+        let c_prefix = self.0.kind.rust_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!("{}{bit_len}", rust_prefix),
+                (Some(simd), None) => format!("{}{bit_len}x{simd}_t", c_prefix),
+                (Some(simd), Some(vec)) => format!("{}{bit_len}x{simd}x{vec}_t", c_prefix),
+                (None, Some(_)) => todo!("{:#?}", self), // Likely an invalid case
             }
-            _ => unimplemented!("populate random: {:#?}", self),
+        } else {
+            todo!("{:#?}", self)
         }
     }
 
     /// Determines the load function for this type.
-    ///
-    /// ARM-specific
     fn get_load_function(&self, language: Language) -> String {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.get_load_function(language),
-            IntrinsicType::Type {
-                kind: k,
-                bit_len: Some(bl),
-                simd_len,
-                vec_len,
-                target,
-                ..
-            } => {
-                let quad = if simd_len.unwrap_or(1) * bl > 64 {
-                    "q"
-                } else {
-                    ""
-                };
+        if let IntrinsicType {
+            kind: k,
+            bit_len: Some(bl),
+            simd_len,
+            vec_len,
+            target,
+            ..
+        } = &self.0
+        {
+            let quad = if simd_len.unwrap_or(1) * bl > 64 {
+                "q"
+            } else {
+                ""
+            };
 
-                let choose_workaround = language == Language::C && target.contains("v7");
-                format!(
-                    "vld{len}{quad}_{type}{size}",
-                    type = match k {
-                        TypeKind::UInt => "u",
-                        TypeKind::Int => "s",
-                        TypeKind::Float => "f",
-                        // The ACLE doesn't support 64-bit polynomial loads on Armv7
-                        // if armv7 and bl == 64, use "s", else "p"
-                        TypeKind::Poly => if choose_workaround && *bl == 64 {"s"} else {"p"},
-                        x => todo!("get_load_function TypeKind: {:#?}", x),
-                    },
-                    size = bl,
-                    quad = quad,
-                    len = vec_len.unwrap_or(1),
-                )
-            }
-            _ => todo!("get_load_function IntrinsicType: {:#?}", self),
+            let choose_workaround = language == Language::C && target.contains("v7");
+            format!(
+                "vld{len}{quad}_{type}{size}",
+                type = match k {
+                    TypeKind::UInt => "u",
+                    TypeKind::Int => "s",
+                    TypeKind::Float => "f",
+                    // The ACLE doesn't support 64-bit polynomial loads on Armv7
+                    // if armv7 and bl == 64, use "s", else "p"
+                    TypeKind::Poly => if choose_workaround && *bl == 64 {"s"} else {"p"},
+                    x => todo!("get_load_function TypeKind: {:#?}", x),
+                },
+                size = bl,
+                quad = quad,
+                len = vec_len.unwrap_or(1),
+            )
+        } else {
+            todo!("get_load_function IntrinsicType: {:#?}", self)
         }
     }
 
-    pub fn get_load_function_c(&self) -> String {
-        self.get_load_function(Language::C)
-    }
-
-    pub fn get_load_function_rust(&self) -> String {
-        self.get_load_function(Language::Rust)
-    }
-
     /// Determines the get lane function for this type.
-    ///
-    /// ARM-specific
-    pub fn get_lane_function(&self) -> String {
-        match self {
-            IntrinsicType::Ptr { child, .. } => child.get_lane_function(),
-            IntrinsicType::Type {
-                kind: k,
-                bit_len: Some(bl),
-                simd_len,
-                ..
-            } => {
-                let quad = if (simd_len.unwrap_or(1) * bl) > 64 {
-                    "q"
-                } else {
-                    ""
-                };
-                format!(
-                    "vget{quad}_lane_{type}{size}",
-                    type = match k {
-                        TypeKind::UInt => "u",
-                        TypeKind::Int => "s",
-                        TypeKind::Float => "f",
-                        TypeKind::Poly => "p",
-                        x => todo!("get_load_function TypeKind: {:#?}", x),
-                    },
-                    size = bl,
-                    quad = quad,
-                )
-            }
-            _ => todo!("get_lane_function IntrinsicType: {:#?}", self),
+    fn get_lane_function(&self) -> String {
+        if let IntrinsicType {
+            kind: k,
+            bit_len: Some(bl),
+            simd_len,
+            ..
+        } = &self.0
+        {
+            let quad = if (simd_len.unwrap_or(1) * bl) > 64 {
+                "q"
+            } else {
+                ""
+            };
+            format!(
+                "vget{quad}_lane_{type}{size}",
+                type = match k {
+                    TypeKind::UInt => "u",
+                    TypeKind::Int => "s",
+                    TypeKind::Float => "f",
+                    TypeKind::Poly => "p",
+                    x => todo!("get_load_function TypeKind: {:#?}", x),
+                },
+                size = bl,
+                quad = quad,
+            )
+        } else {
+            todo!("get_lane_function IntrinsicType: {:#?}", self)
         }
     }
 
-    /// ARM-specific
-    pub fn from_c(s: &str, target: &String) -> Result<IntrinsicType, String> {
+    fn from_c(s: &str, target: &String) -> Result<Box<Self>, String> {
         const CONST_STR: &str = "const";
         if let Some(s) = s.strip_suffix('*') {
             let (s, constant) = match s.trim().strip_suffix(CONST_STR) {
@@ -476,9 +127,12 @@ impl IntrinsicType {
                 None => (s, false),
             };
             let s = s.trim_end();
-            Ok(IntrinsicType::Ptr {
-                constant,
-                child: Box::new(IntrinsicType::from_c(s, target)?),
+            let temp_return = ArmIntrinsicType::from_c(s, target);
+            temp_return.and_then(|mut op| {
+                let edited = op.as_mut();
+                edited.0.ptr = true;
+                edited.0.ptr_constant = constant;
+                Ok(op)
             })
         } else {
             // [const ]TYPE[{bitlen}[x{simdlen}[x{vec_len}]]][_t]
@@ -507,28 +161,32 @@ impl IntrinsicType {
                     ),
                     None => None,
                 };
-                Ok(IntrinsicType::Type {
+                Ok(Box::new(ArmIntrinsicType(IntrinsicType {
+                    ptr: false,
+                    ptr_constant: false,
                     constant,
                     kind: arg_kind,
                     bit_len: Some(bit_len),
                     simd_len,
                     vec_len,
                     target: target.to_string(),
-                })
+                })))
             } else {
                 let kind = start.parse::<TypeKind>()?;
                 let bit_len = match kind {
                     TypeKind::Int => Some(32),
                     _ => None,
                 };
-                Ok(IntrinsicType::Type {
+                Ok(Box::new(ArmIntrinsicType(IntrinsicType {
+                    ptr: false,
+                    ptr_constant: false,
                     constant,
                     kind: start.parse::<TypeKind>()?,
                     bit_len,
                     simd_len: None,
                     vec_len: None,
                     target: target.to_string(),
-                })
+                })))
             }
         }
     }
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/argument.rs b/library/stdarch/crates/intrinsic-test/src/common/argument.rs
index 24fe8c9a93a..08d6ca15239 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/argument.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/argument.rs
@@ -1,67 +1,35 @@
-use super::format::Indentation;
-use super::json_parser::ArgPrep;
-use super::types::{IntrinsicType, TypeKind};
+use crate::common::format::Indentation;
+use crate::common::intrinsic_types::IntrinsicTypeDefinition;
 use crate::common::types::Language;
-use serde::Deserialize;
 use serde_json::Value;
-use std::collections::HashMap;
-use std::ops::Range;
 
 /// An argument for the intrinsic.
 #[derive(Debug, PartialEq, Clone)]
-pub struct Argument {
+pub struct Argument<T: IntrinsicTypeDefinition, M: MetadataDefinition> {
     /// The argument's index in the intrinsic function call.
     pub pos: usize,
     /// The argument name.
     pub name: String,
     /// The type of the argument.
-    pub ty: IntrinsicType,
+    pub ty: T,
     /// Any constraints that are on this argument
-    pub constraints: Vec<Constraint>,
+    pub metadata: Vec<M>,
 }
 
-#[derive(Debug, PartialEq, Clone, Deserialize)]
-pub enum Constraint {
-    Equal(i64),
-    Range(Range<i64>),
+pub trait MetadataDefinition {
+    fn from_metadata(metadata: Option<Value>) -> Vec<Box<Self>>;
 }
 
-/// ARM-specific
-impl TryFrom<ArgPrep> for Constraint {
-    type Error = ();
-
-    fn try_from(prep: ArgPrep) -> Result<Self, Self::Error> {
-        let parsed_ints = match prep {
-            ArgPrep::Immediate { min, max } => Ok((min, max)),
-            _ => Err(()),
-        };
-        if let Ok((min, max)) = parsed_ints {
-            if min == max {
-                Ok(Constraint::Equal(min))
-            } else {
-                Ok(Constraint::Range(min..max + 1))
-            }
-        } else {
-            Err(())
-        }
-    }
-}
-
-impl Constraint {
-    pub fn to_range(&self) -> Range<i64> {
-        match self {
-            Constraint::Equal(eq) => *eq..*eq + 1,
-            Constraint::Range(range) => range.clone(),
-        }
-    }
-}
-
-impl Argument {
-    fn to_c_type(&self) -> String {
+impl<T, M> Argument<T, M>
+where
+    T: IntrinsicTypeDefinition,
+    M: MetadataDefinition,
+{
+    pub fn to_c_type(&self) -> String {
         self.ty.c_type()
     }
 
-    fn is_simd(&self) -> bool {
+    pub fn is_simd(&self) -> bool {
         self.ty.is_simd()
     }
 
@@ -70,7 +38,7 @@ impl Argument {
     }
 
     pub fn has_constraint(&self) -> bool {
-        !self.constraints.is_empty()
+        !self.metadata.is_empty()
     }
 
     pub fn type_and_name_from_c(arg: &str) -> (&str, &str) {
@@ -81,86 +49,65 @@ impl Argument {
         (arg[..split_index + 1].trim_end(), &arg[split_index + 1..])
     }
 
-    // ARM-specific
+    /// The binding keyword (e.g. "const" or "let") for the array of possible test inputs.
+    fn rust_vals_array_binding(&self) -> impl std::fmt::Display {
+        if self.ty.is_rust_vals_array_const() {
+            "const"
+        } else {
+            "let"
+        }
+    }
+
+    /// The name (e.g. "A_VALS" or "a_vals") for the array of possible test inputs.
+    fn rust_vals_array_name(&self) -> impl std::fmt::Display {
+        if self.ty.is_rust_vals_array_const() {
+            format!("{}_VALS", self.name.to_uppercase())
+        } else {
+            format!("{}_vals", self.name.to_lowercase())
+        }
+    }
+
     pub fn from_c(
         pos: usize,
         arg: &str,
         target: &String,
-        metadata: Option<&mut HashMap<String, Value>>,
-    ) -> Argument {
+        metadata: Option<Value>,
+    ) -> Argument<T, M> {
         let (ty, var_name) = Self::type_and_name_from_c(arg);
 
-        let ty = IntrinsicType::from_c(ty, target)
-            .unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'"));
+        let ty =
+            T::from_c(ty, target).unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'"));
 
-        let arg_name = Argument::type_and_name_from_c(&arg).1;
-        let arg = metadata.and_then(|a| a.remove(arg_name));
-        let arg_prep: Option<ArgPrep> = arg.and_then(|a| {
-            if let Value::Object(_) = a {
-                a.try_into().ok()
-            } else {
-                None
-            }
-        });
-        let constraint = arg_prep.and_then(|a| a.try_into().ok());
+        let metadata: Vec<M> = M::from_metadata(metadata).into_iter().map(|b| *b).collect();
 
         Argument {
             pos,
             name: String::from(var_name),
-            ty,
-            constraints: constraint.map_or(vec![], |r| vec![r]),
+            ty: *ty,
+            metadata,
         }
     }
 
-    fn is_rust_vals_array_const(&self) -> bool {
-        use TypeKind::*;
-        match self.ty {
-            // Floats have to be loaded at runtime for stable NaN conversion.
-            IntrinsicType::Type { kind: Float, .. } => false,
-            IntrinsicType::Type {
-                kind: Int | UInt | Poly,
-                ..
-            } => true,
-            _ => unimplemented!(),
-        }
-    }
-
-    /// The binding keyword (e.g. "const" or "let") for the array of possible test inputs.
-    pub fn rust_vals_array_binding(&self) -> impl std::fmt::Display {
-        if self.is_rust_vals_array_const() {
-            "const"
-        } else {
-            "let"
-        }
-    }
-
-    /// The name (e.g. "A_VALS" or "a_vals") for the array of possible test inputs.
-    pub fn rust_vals_array_name(&self) -> impl std::fmt::Display {
-        if self.is_rust_vals_array_const() {
-            format!("{}_VALS", self.name.to_uppercase())
-        } else {
-            format!("{}_vals", self.name.to_lowercase())
-        }
+    fn as_call_param_c(&self) -> String {
+        self.ty.as_call_param_c(&self.name)
     }
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct ArgumentList {
-    pub args: Vec<Argument>,
+pub struct ArgumentList<T: IntrinsicTypeDefinition, M: MetadataDefinition> {
+    pub args: Vec<Argument<T, M>>,
 }
 
-impl ArgumentList {
+impl<T, M> ArgumentList<T, M>
+where
+    T: IntrinsicTypeDefinition,
+    M: MetadataDefinition,
+{
     /// Converts the argument list into the call parameters for a C function call.
     /// e.g. this would generate something like `a, &b, c`
     pub fn as_call_param_c(&self) -> String {
-        self.args
-            .iter()
-            .map(|arg| match arg.ty {
-                IntrinsicType::Ptr { .. } => {
-                    format!("&{}", arg.name)
-                }
-                IntrinsicType::Type { .. } => arg.name.clone(),
-            })
+        self.iter()
+            .map(|arg| arg.as_call_param_c())
             .collect::<Vec<String>>()
             .join(", ")
     }
@@ -168,8 +115,7 @@ impl ArgumentList {
     /// Converts the argument list into the call parameters for a Rust function.
     /// e.g. this would generate something like `a, b, c`
     pub fn as_call_param_rust(&self) -> String {
-        self.args
-            .iter()
+        self.iter()
             .filter(|a| !a.has_constraint())
             .map(|arg| arg.name.clone())
             .collect::<Vec<String>>()
@@ -177,8 +123,7 @@ impl ArgumentList {
     }
 
     pub fn as_constraint_parameters_rust(&self) -> String {
-        self.args
-            .iter()
+        self.iter()
             .filter(|a| a.has_constraint())
             .map(|arg| arg.name.clone())
             .collect::<Vec<String>>()
@@ -241,7 +186,7 @@ impl ArgumentList {
                         ty = arg.to_c_type(),
                         name = arg.name,
                         load = if arg.is_simd() {
-                            arg.ty.get_load_function_c()
+                            arg.ty.get_load_function(Language::C)
                         } else {
                             "*".to_string()
                         }
@@ -263,7 +208,7 @@ impl ArgumentList {
                         name = arg.name,
                         vals_name = arg.rust_vals_array_name(),
                         load = if arg.is_simd() {
-                            arg.ty.get_load_function_rust()
+                            arg.ty.get_load_function(Language::Rust)
                         } else {
                             "*".to_string()
                         },
@@ -273,7 +218,7 @@ impl ArgumentList {
             .collect()
     }
 
-    pub fn iter(&self) -> std::slice::Iter<'_, Argument> {
+    pub fn iter(&self) -> std::slice::Iter<'_, Argument<T, M>> {
         self.args.iter()
     }
 }
diff --git a/library/stdarch/crates/intrinsic-test/src/arm/format.rs b/library/stdarch/crates/intrinsic-test/src/common/format.rs
index 9ee331d7f7a..9ee331d7f7a 100644
--- a/library/stdarch/crates/intrinsic-test/src/arm/format.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/format.rs
diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs
new file mode 100644
index 00000000000..e2124897f3d
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs
@@ -0,0 +1,91 @@
+use crate::common::argument::ArgumentList;
+use crate::common::format::Indentation;
+use crate::common::intrinsic_types::IntrinsicTypeDefinition;
+
+use super::argument::MetadataDefinition;
+
+/// An intrinsic
+#[derive(Debug, PartialEq, Clone)]
+pub struct Intrinsic<T: IntrinsicTypeDefinition, M: MetadataDefinition> {
+    /// The function name of this intrinsic.
+    pub name: String,
+
+    /// Any arguments for this intrinsic.
+    pub arguments: ArgumentList<T, M>,
+
+    /// The return type of this intrinsic.
+    pub results: T,
+
+    /// Whether this intrinsic is only available on A64.
+    pub a64_only: bool,
+}
+
+pub trait IntrinsicDefinition<T, M>
+where
+    T: IntrinsicTypeDefinition,
+    M: MetadataDefinition,
+{
+    fn arguments(&self) -> ArgumentList<T, M>;
+
+    fn results(&self) -> T;
+
+    fn name(&self) -> String;
+
+    /// Generates a std::cout for the intrinsics results that will match the
+    /// rust debug output format for the return type. The generated line assumes
+    /// there is an int i in scope which is the current pass number.
+    fn print_result_c(&self, _indentation: Indentation, _additional: &str) -> String {
+        unimplemented!("Architectures need to implement print_result_c!")
+    }
+
+    fn generate_loop_c(
+        &self,
+        indentation: Indentation,
+        additional: &str,
+        passes: u32,
+        _target: &str,
+    ) -> String {
+        let body_indentation = indentation.nested();
+        format!(
+            "{indentation}for (int i=0; i<{passes}; i++) {{\n\
+                {loaded_args}\
+                {body_indentation}auto __return_value = {intrinsic_call}({args});\n\
+                {print_result}\n\
+            {indentation}}}",
+            loaded_args = self.arguments().load_values_c(body_indentation),
+            intrinsic_call = self.name(),
+            args = self.arguments().as_call_param_c(),
+            print_result = self.print_result_c(body_indentation, additional)
+        )
+    }
+
+    fn generate_loop_rust(
+        &self,
+        indentation: Indentation,
+        additional: &str,
+        passes: u32,
+    ) -> String {
+        let constraints = self.arguments().as_constraint_parameters_rust();
+        let constraints = if !constraints.is_empty() {
+            format!("::<{constraints}>")
+        } else {
+            constraints
+        };
+
+        let indentation2 = indentation.nested();
+        let indentation3 = indentation2.nested();
+        format!(
+            "{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}-{{}}: {{:.150?}}\", i + 1, __return_value);\n\
+                {indentation2}}}\n\
+            {indentation}}}",
+            loaded_args = self.arguments().load_values_rust(indentation3),
+            intrinsic_call = self.name(),
+            const = constraints,
+            args = self.arguments().as_call_param_rust(),
+        )
+    }
+}
diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_types.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_types.rs
new file mode 100644
index 00000000000..9a08ec066c1
--- /dev/null
+++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_types.rs
@@ -0,0 +1,352 @@
+use std::fmt;
+use std::str::FromStr;
+
+use itertools::Itertools as _;
+
+use crate::common::format::Indentation;
+use crate::common::types::Language;
+use crate::common::values::value_for_array;
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum TypeKind {
+    BFloat,
+    Float,
+    Int,
+    UInt,
+    Poly,
+    Void,
+}
+
+impl FromStr for TypeKind {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "bfloat" => Ok(Self::BFloat),
+            "float" => Ok(Self::Float),
+            "int" => Ok(Self::Int),
+            "poly" => Ok(Self::Poly),
+            "uint" | "unsigned" => Ok(Self::UInt),
+            "void" => Ok(Self::Void),
+            _ => Err(format!("Impossible to parse argument kind {s}")),
+        }
+    }
+}
+
+impl fmt::Display for TypeKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                Self::BFloat => "bfloat",
+                Self::Float => "float",
+                Self::Int => "int",
+                Self::UInt => "uint",
+                Self::Poly => "poly",
+                Self::Void => "void",
+            }
+        )
+    }
+}
+
+impl TypeKind {
+    /// Gets the type part of a c typedef for a type that's in the form of {type}{size}_t.
+    pub fn c_prefix(&self) -> &str {
+        match self {
+            Self::Float => "float",
+            Self::Int => "int",
+            Self::UInt => "uint",
+            Self::Poly => "poly",
+            _ => unreachable!("Not used: {:#?}", self),
+        }
+    }
+
+    /// Gets the rust prefix for the type kind i.e. i, u, f.
+    pub fn rust_prefix(&self) -> &str {
+        match self {
+            Self::Float => "f",
+            Self::Int => "i",
+            Self::UInt => "u",
+            Self::Poly => "u",
+            _ => unreachable!("Unused type kind: {:#?}", self),
+        }
+    }
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct IntrinsicType {
+    pub constant: bool,
+
+    /// whether this object is a const pointer
+    pub ptr_constant: bool,
+
+    pub ptr: bool,
+
+    pub kind: TypeKind,
+    /// The bit length of this type (e.g. 32 for u32).
+    pub bit_len: Option<u32>,
+
+    /// Length of the SIMD vector (i.e. 4 for uint32x4_t), A value of `None`
+    /// means this is not a simd type. A `None` can be assumed to be 1,
+    /// although in some places a distinction is needed between `u64` and
+    /// `uint64x1_t` this signals that.
+    pub simd_len: Option<u32>,
+
+    /// The number of rows for SIMD matrices (i.e. 2 for uint8x8x2_t).
+    /// A value of `None` represents a type that does not contain any
+    /// rows encoded in the type (e.g. uint8x8_t).
+    /// A value of `None` can be assumed to be 1 though.
+    pub vec_len: Option<u32>,
+
+    pub target: String,
+}
+
+pub trait BaseIntrinsicTypeDefinition {
+    /// Get the TypeKind for this type, recursing into pointers.
+    fn kind(&self) -> TypeKind;
+
+    /// Get the size of a single element inside this type, recursing into
+    /// pointers, i.e. a pointer to a u16 would be 16 rather than the size
+    /// of a pointer.
+    fn inner_size(&self) -> u32;
+
+    fn num_lanes(&self) -> u32;
+
+    fn num_vectors(&self) -> u32;
+
+    /// Determine if the type is a simd type, this will treat a type such as
+    /// `uint64x1` as simd.
+    fn is_simd(&self) -> bool;
+
+    fn is_ptr(&self) -> bool;
+
+    fn c_scalar_type(&self) -> String;
+
+    fn rust_scalar_type(&self) -> String;
+
+    /// Gets a cast for this type if needs promotion.
+    /// This is required for 8 bit types due to printing as the 8 bit types use
+    /// a char and when using that in `std::cout` it will print as a character,
+    /// which means value of 0 will be printed as a null byte.
+    ///
+    /// This is also needed for polynomial types because we want them to be
+    /// printed as unsigned integers to match Rust's `Debug` impl.
+    fn c_promotion(&self) -> &str;
+
+    /// Generates an initialiser for an array, which can be used to initialise an argument for the
+    /// intrinsic call.
+    ///
+    /// This is determistic based on the pass number.
+    ///
+    /// * `loads`: The number of values that need to be loaded from the argument array
+    /// * e.g for argument type uint32x2, loads=2 results in a string representing 4 32-bit values
+    ///
+    /// Returns a string such as
+    /// * `{0x1, 0x7F, 0xFF}` if `language` is `Language::C`
+    /// * `[0x1 as _, 0x7F as _, 0xFF as _]` if `language` is `Language::Rust`
+    fn populate_random(&self, indentation: Indentation, loads: u32, language: &Language) -> String;
+
+    fn is_rust_vals_array_const(&self) -> bool;
+
+    fn as_call_param_c(&self, name: &String) -> String;
+}
+
+impl BaseIntrinsicTypeDefinition for IntrinsicType {
+    fn kind(&self) -> TypeKind {
+        self.kind
+    }
+
+    fn inner_size(&self) -> u32 {
+        if let Some(bl) = self.bit_len {
+            bl
+        } else {
+            unreachable!("")
+        }
+    }
+
+    fn num_lanes(&self) -> u32 {
+        if let Some(sl) = self.simd_len { sl } else { 1 }
+    }
+
+    fn num_vectors(&self) -> u32 {
+        if let Some(vl) = self.vec_len { vl } else { 1 }
+    }
+
+    fn is_simd(&self) -> bool {
+        self.simd_len.is_some() || self.vec_len.is_some()
+    }
+
+    fn is_ptr(&self) -> bool {
+        self.ptr
+    }
+
+    fn c_scalar_type(&self) -> String {
+        format!(
+            "{prefix}{bits}_t",
+            prefix = self.kind().c_prefix(),
+            bits = self.inner_size()
+        )
+    }
+
+    fn rust_scalar_type(&self) -> String {
+        format!(
+            "{prefix}{bits}",
+            prefix = self.kind().rust_prefix(),
+            bits = self.inner_size()
+        )
+    }
+
+    fn c_promotion(&self) -> &str {
+        match *self {
+            IntrinsicType {
+                kind,
+                bit_len: Some(8),
+                ..
+            } => match kind {
+                TypeKind::Int => "(int)",
+                TypeKind::UInt => "(unsigned int)",
+                TypeKind::Poly => "(unsigned int)(uint8_t)",
+                _ => "",
+            },
+            IntrinsicType {
+                kind: TypeKind::Poly,
+                bit_len: Some(bit_len),
+                ..
+            } => match bit_len {
+                8 => unreachable!("handled above"),
+                16 => "(uint16_t)",
+                32 => "(uint32_t)",
+                64 => "(uint64_t)",
+                128 => "",
+                _ => panic!("invalid bit_len"),
+            },
+            _ => "",
+        }
+    }
+
+    fn populate_random(&self, indentation: Indentation, loads: u32, language: &Language) -> String {
+        match self {
+            IntrinsicType {
+                bit_len: Some(bit_len @ (8 | 16 | 32 | 64)),
+                kind: kind @ (TypeKind::Int | TypeKind::UInt | TypeKind::Poly),
+                simd_len,
+                vec_len,
+                ..
+            } => {
+                let (prefix, suffix) = match language {
+                    Language::Rust => ("[", "]"),
+                    Language::C => ("{", "}"),
+                };
+                let body_indentation = indentation.nested();
+                format!(
+                    "{prefix}\n{body}\n{indentation}{suffix}",
+                    body = (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
+                        .format_with(",\n", |i, fmt| {
+                            let src = value_for_array(*bit_len, i);
+                            assert!(src == 0 || src.ilog2() < *bit_len);
+                            if *kind == TypeKind::Int && (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;
+                                if (twos_compl == src) && (language == &Language::C) {
+                                    // `src` is INT*_MIN. C requires `-0x7fffffff - 1` to avoid
+                                    // undefined literal overflow behaviour.
+                                    fmt(&format_args!("{body_indentation}-{ones_compl:#x} - 1"))
+                                } else {
+                                    fmt(&format_args!("{body_indentation}-{twos_compl:#x}"))
+                                }
+                            } else {
+                                fmt(&format_args!("{body_indentation}{src:#x}"))
+                            }
+                        })
+                )
+            }
+            IntrinsicType {
+                kind: TypeKind::Float,
+                bit_len: Some(bit_len @ (16 | 32 | 64)),
+                simd_len,
+                vec_len,
+                ..
+            } => {
+                let (prefix, cast_prefix, cast_suffix, suffix) = match (language, bit_len) {
+                    (&Language::Rust, 16) => ("[", "f16::from_bits(", ")", "]"),
+                    (&Language::Rust, 32) => ("[", "f32::from_bits(", ")", "]"),
+                    (&Language::Rust, 64) => ("[", "f64::from_bits(", ")", "]"),
+                    (&Language::C, 16) => ("{", "cast<float16_t, uint16_t>(", ")", "}"),
+                    (&Language::C, 32) => ("{", "cast<float, uint32_t>(", ")", "}"),
+                    (&Language::C, 64) => ("{", "cast<double, uint64_t>(", ")", "}"),
+                    _ => unreachable!(),
+                };
+                format!(
+                    "{prefix}\n{body}\n{indentation}{suffix}",
+                    body = (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
+                        .format_with(",\n", |i, fmt| fmt(&format_args!(
+                            "{indentation}{cast_prefix}{src:#x}{cast_suffix}",
+                            indentation = indentation.nested(),
+                            src = value_for_array(*bit_len, i)
+                        )))
+                )
+            }
+            _ => unimplemented!("populate random: {:#?}", self),
+        }
+    }
+
+    fn is_rust_vals_array_const(&self) -> bool {
+        match self {
+            // Floats have to be loaded at runtime for stable NaN conversion.
+            IntrinsicType {
+                kind: TypeKind::Float,
+                ..
+            } => false,
+            IntrinsicType {
+                kind: TypeKind::Int | TypeKind::UInt | TypeKind::Poly,
+                ..
+            } => true,
+            _ => unimplemented!(),
+        }
+    }
+
+    fn as_call_param_c(&self, name: &String) -> String {
+        if self.ptr {
+            format!("&{}", name)
+        } else {
+            name.clone()
+        }
+    }
+}
+
+pub trait IntrinsicTypeDefinition: BaseIntrinsicTypeDefinition {
+    /// Determines the load function for this type.
+    /// can be implemented in an `impl` block
+    fn get_load_function(&self, _language: Language) -> String {
+        unimplemented!("Different architectures must implement get_load_function!")
+    }
+
+    /// can be implemented in an `impl` block
+    fn get_lane_function(&self) -> String {
+        unimplemented!("Different architectures must implement get_lane_function!")
+    }
+
+    /// can be implemented in an `impl` block
+    fn from_c(_s: &str, _target: &String) -> Result<Box<Self>, String> {
+        unimplemented!("Different architectures must implement from_c!")
+    }
+
+    /// Gets a string containing the typename for this type in C format.
+    /// can be directly defined in `impl` blocks
+    fn c_type(&self) -> String {
+        unimplemented!("Different architectures must implement c_type!")
+    }
+
+    /// can be directly defined in `impl` blocks
+    fn c_single_vector_type(&self) -> String {
+        unimplemented!("Different architectures must implement c_single_vector_type!")
+    }
+
+    /// can be defined in `impl` blocks
+    fn rust_type(&self) -> String {
+        unimplemented!("Different architectures must implement rust_type!")
+    }
+}
diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs
index 1c9f8027760..7db1166c7d2 100644
--- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs
+++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs
@@ -2,9 +2,13 @@ use crate::common::types::ProcessedCli;
 use std::fs::File;
 use std::io::Write;
 
+pub mod argument;
 pub mod compare;
+pub mod format;
 pub mod gen_c;
 pub mod gen_rust;
+pub mod intrinsic;
+pub mod intrinsic_types;
 pub mod types;
 pub mod values;