From 4a3d05fc5c737f6c0ba2bb1cbc6e256aa102b6ee Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Fri, 30 May 2025 17:12:49 +0530 Subject: [PATCH 01/17] fix: updated function definition of "from_c" in IntrinsicTypeDefinition trait to make the same dyn-compatible. --- crates/intrinsic-test/src/arm/json_parser.rs | 2 +- crates/intrinsic-test/src/arm/types.rs | 19 +++++++++---------- crates/intrinsic-test/src/common/argument.rs | 2 +- .../src/common/intrinsic_helpers.rs | 4 +++- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/intrinsic-test/src/arm/json_parser.rs b/crates/intrinsic-test/src/arm/json_parser.rs index 0ac47484b0..58d366c86a 100644 --- a/crates/intrinsic-test/src/arm/json_parser.rs +++ b/crates/intrinsic-test/src/arm/json_parser.rs @@ -110,7 +110,7 @@ fn json_to_intrinsic( Ok(Intrinsic { name, arguments, - results: *results, + results: results, arch_tags: intr.architectures, }) } diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 9f3d6302f4..f039ba7bcf 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -121,7 +121,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { } } - fn from_c(s: &str, target: &str) -> Result, String> { + fn from_c(s: &str, target: &String) -> Result { const CONST_STR: &str = "const"; if let Some(s) = s.strip_suffix('*') { let (s, constant) = match s.trim().strip_suffix(CONST_STR) { @@ -130,11 +130,10 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { }; let s = s.trim_end(); let temp_return = ArmIntrinsicType::from_c(s, target); - temp_return.map(|mut op| { - let edited = op.as_mut(); - edited.0.ptr = true; - edited.0.ptr_constant = constant; - op + temp_return.and_then(|mut op| { + op.0.ptr = true; + op.0.ptr_constant = constant; + Ok(op) }) } else { // [const ]TYPE[{bitlen}[x{simdlen}[x{vec_len}]]][_t] @@ -163,7 +162,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { ), None => None, }; - Ok(Box::new(ArmIntrinsicType(IntrinsicType { + Ok(ArmIntrinsicType(IntrinsicType { ptr: false, ptr_constant: false, constant, @@ -172,14 +171,14 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { simd_len, vec_len, target: target.to_string(), - }))) + })) } else { let kind = start.parse::()?; let bit_len = match kind { TypeKind::Int => Some(32), _ => None, }; - Ok(Box::new(ArmIntrinsicType(IntrinsicType { + Ok(ArmIntrinsicType(IntrinsicType { ptr: false, ptr_constant: false, constant, @@ -188,7 +187,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { simd_len: None, vec_len: None, target: target.to_string(), - }))) + })) } } } diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 443ccb919f..e0c9365191 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -76,7 +76,7 @@ where Argument { pos, name: String::from(var_name), - ty: *ty, + ty: ty, constraint, } } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 3d200b1946..1f0797102a 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -282,7 +282,9 @@ pub trait IntrinsicTypeDefinition: Deref { fn get_lane_function(&self) -> String; /// can be implemented in an `impl` block - fn from_c(_s: &str, _target: &str) -> Result, String>; + fn from_c(_s: &str, _target: &String) -> Result + where + Self: Sized; /// Gets a string containing the typename for this type in C format. /// can be directly defined in `impl` blocks From 38fd826b8a7491ecf1c1b37192008acbc08e8021 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Fri, 30 May 2025 17:14:58 +0530 Subject: [PATCH 02/17] Feat: started the skeleton for x86 module, added XML intrinsic parsing capabilities --- crates/intrinsic-test/Cargo.toml | 2 + crates/intrinsic-test/src/main.rs | 4 + crates/intrinsic-test/src/x86/intrinsic.rs | 37 +++++++ crates/intrinsic-test/src/x86/mod.rs | 38 +++++++ crates/intrinsic-test/src/x86/types.rs | 32 ++++++ crates/intrinsic-test/src/x86/xml_parser.rs | 104 ++++++++++++++++++++ 6 files changed, 217 insertions(+) create mode 100644 crates/intrinsic-test/src/x86/intrinsic.rs create mode 100644 crates/intrinsic-test/src/x86/mod.rs create mode 100644 crates/intrinsic-test/src/x86/types.rs create mode 100644 crates/intrinsic-test/src/x86/xml_parser.rs diff --git a/crates/intrinsic-test/Cargo.toml b/crates/intrinsic-test/Cargo.toml index 06051abc8d..905e47c1d5 100644 --- a/crates/intrinsic-test/Cargo.toml +++ b/crates/intrinsic-test/Cargo.toml @@ -22,3 +22,5 @@ pretty_env_logger = "0.5.0" rayon = "1.5.0" diff = "0.1.12" itertools = "0.14.0" +quick-xml = { version = "0.37.5", features = ["serialize", "overlapped-lists"] } +serde-xml-rs = "0.8.0" \ No newline at end of file diff --git a/crates/intrinsic-test/src/main.rs b/crates/intrinsic-test/src/main.rs index 054138a0db..c11332b1f4 100644 --- a/crates/intrinsic-test/src/main.rs +++ b/crates/intrinsic-test/src/main.rs @@ -3,10 +3,12 @@ extern crate log; mod arm; mod common; +mod x86; use arm::ArmArchitectureTest; use common::SupportedArchitectureTest; use common::cli::{Cli, ProcessedCli}; +use x86::X86ArchitectureTest; fn main() { pretty_env_logger::init(); @@ -21,6 +23,8 @@ fn main() { Some(ArmArchitectureTest::create(processed_cli_options)) } + "x86_64-unknown-linux-gnu" => Some(X86ArchitectureTest::create(processed_cli_options)), + _ => None, }; diff --git a/crates/intrinsic-test/src/x86/intrinsic.rs b/crates/intrinsic-test/src/x86/intrinsic.rs new file mode 100644 index 0000000000..e4a2e7f463 --- /dev/null +++ b/crates/intrinsic-test/src/x86/intrinsic.rs @@ -0,0 +1,37 @@ +use crate::common::argument::ArgumentList; +use crate::common::indentation::Indentation; +use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; +use crate::common::intrinsic_helpers::IntrinsicType; +use std::ops::Deref; + +#[derive(Debug, Clone, PartialEq)] +pub struct X86IntrinsicType(pub IntrinsicType); + +impl Deref for X86IntrinsicType { + type Target = IntrinsicType; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl IntrinsicDefinition for Intrinsic { + fn arguments(&self) -> ArgumentList { + self.arguments.clone() + } + + fn results(&self) -> X86IntrinsicType { + self.results.clone() + } + + fn name(&self) -> String { + self.name.clone() + } + + /// 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 { + todo!("print_result_c in Intrinsic needs to be implemented!"); + } +} diff --git a/crates/intrinsic-test/src/x86/mod.rs b/crates/intrinsic-test/src/x86/mod.rs new file mode 100644 index 0000000000..a435887f64 --- /dev/null +++ b/crates/intrinsic-test/src/x86/mod.rs @@ -0,0 +1,38 @@ +mod intrinsic; +mod types; +mod xml_parser; + +use crate::common::SupportedArchitectureTest; +use crate::common::cli::ProcessedCli; +use crate::common::intrinsic::Intrinsic; +use intrinsic::X86IntrinsicType; +use xml_parser::get_xml_intrinsics; + +pub struct X86ArchitectureTest { + intrinsics: Vec>, + cli_options: ProcessedCli, +} + +impl SupportedArchitectureTest for X86ArchitectureTest { + fn create(cli_options: ProcessedCli) -> Box { + let intrinsics = get_xml_intrinsics(&cli_options.filename, &cli_options.target) + .expect("Error parsing input file"); + + Box::new(Self { + intrinsics: intrinsics, + cli_options: cli_options, + }) + } + + fn build_c_file(&self) -> bool { + todo!("build_c_file in X86ArchitectureTest is not implemented") + } + + fn build_rust_file(&self) -> bool { + todo!("build_rust_file in X86ArchitectureTest is not implemented") + } + + fn compare_outputs(&self) -> bool { + todo!("compare_outputs in X86ArchitectureTest is not implemented") + } +} diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs new file mode 100644 index 0000000000..e38a2b1777 --- /dev/null +++ b/crates/intrinsic-test/src/x86/types.rs @@ -0,0 +1,32 @@ +use super::intrinsic::X86IntrinsicType; +use crate::common::cli::Language; +use crate::common::intrinsic_helpers::IntrinsicTypeDefinition; + +impl IntrinsicTypeDefinition for X86IntrinsicType { + /// Gets a string containing the typename for this type in C format. + fn c_type(&self) -> String { + todo!("c_type for X86IntrinsicType needs to be implemented!"); + } + + fn c_single_vector_type(&self) -> String { + todo!("c_single_vector_type for X86IntrinsicType needs to be implemented!"); + } + + fn rust_type(&self) -> String { + todo!("rust_type for X86IntrinsicType needs to be implemented!"); + } + + /// Determines the load function for this type. + fn get_load_function(&self, language: Language) -> String { + todo!("get_load_function for X86IntrinsicType needs to be implemented!"); + } + + /// Determines the get lane function for this type. + fn get_lane_function(&self) -> String { + todo!("get_lane_function for X86IntrinsicType needs to be implemented!"); + } + + fn from_c(s: &str, target: &String) -> Result { + todo!("from_c for X86IntrinsicType needs to be implemented!"); + } +} diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs new file mode 100644 index 0000000000..0ca9b7c55b --- /dev/null +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -0,0 +1,104 @@ +use crate::common::{ + argument::Argument, intrinsic::Intrinsic, intrinsic_helpers::IntrinsicTypeDefinition, +}; +use serde::{Deserialize, Deserializer}; +use std::path::Path; + +use super::intrinsic::X86IntrinsicType; + +// Custom deserializer function to convert "TRUE"/"FALSE" strings to boolean +fn string_to_bool<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + match s.as_str() { + "TRUE" => Ok(true), + "FALSE" => Ok(false), + _ => Ok(false), // Default to false for any other value + } +} + +#[derive(Deserialize)] +struct Data { + #[serde(rename = "intrinsic", default)] + intrinsics: Vec, +} + +#[derive(Deserialize)] +struct XMLIntrinsic { + #[serde(rename = "return")] + return_data: Return, + #[serde(rename = "@name")] + name: String, + #[serde(rename = "@tech")] + tech: String, + #[serde(rename = "CPUID", default)] + cpuid: Vec, + #[serde(rename = "parameter", default)] + parameters: Vec, + #[serde(rename = "@sequence", default, deserialize_with = "string_to_bool")] + generates_sequence: bool, + #[serde(default)] + instruction: Vec, +} + +#[derive(Deserialize)] +struct Parameter { + #[serde(rename = "@type")] + type_data: String, + #[serde(rename = "@etype", default)] + etype: String, +} + +#[derive(Deserialize)] +struct Return { + #[serde(rename = "@type", default)] + type_data: String, +} + +#[derive(Deserialize, Debug)] +struct Instruction { + #[serde(rename = "@name")] + name: String, +} + +pub fn get_xml_intrinsics( + filename: &Path, + target: &String, +) -> Result>, Box> { + let file = std::fs::File::open(filename)?; + let reader = std::io::BufReader::new(file); + let data: Data = + quick_xml::de::from_reader(reader).expect("failed to deserialize the source XML file"); + + // println!("{} intrinsics found", data.intrinsics.len()); + let parsed_intrinsics: Vec> = data + .intrinsics + .into_iter() + .filter_map(|intr| { + Some(xml_to_intrinsic(intr, target).expect("Couldn't parse XML properly!")) + }) + .collect(); + + Ok(parsed_intrinsics) +} + +pub fn xml_to_intrinsic( + mut intr: XMLIntrinsic, + target: &String, +) -> Result, Box> { + let name = intr.name; + let results = X86IntrinsicType::from_c(&intr.return_data.type_data, target)?; + + let arguments: Vec<_> = intr + .parameters + .into_iter() + .enumerate() + .map(|(i, arg)| { + // let arg_name = Argument::::type_and_name_from_c(&arg).1; + }) + .collect(); + + todo!("xml_to_intrinsic needs to collect the arguments properly!"); +} From a7866431126ffe0ad1813d1d2add8ecaf476b54e Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Tue, 3 Jun 2025 11:39:16 +0530 Subject: [PATCH 03/17] feat: added functionality to convert XML description of intrinsics to intrinsic-test's X86IntrinsicType struct --- crates/intrinsic-test/src/common/argument.rs | 9 ++++ crates/intrinsic-test/src/x86/xml_parser.rs | 50 ++++++++++++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index e0c9365191..639e7579ea 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -20,6 +20,15 @@ impl Argument where T: IntrinsicTypeDefinition, { + pub fn new(pos: usize, name: String, ty: T, constraint: Option) -> Self { + Argument { + pos, + name, + ty, + constraint, + } + } + pub fn to_c_type(&self) -> String { self.ty.c_type() } diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 0ca9b7c55b..1649c174a1 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -1,6 +1,7 @@ -use crate::common::{ - argument::Argument, intrinsic::Intrinsic, intrinsic_helpers::IntrinsicTypeDefinition, -}; +use crate::common::argument::{Argument, ArgumentList}; +use crate::common::intrinsic::Intrinsic; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition}; + use serde::{Deserialize, Deserializer}; use std::path::Path; @@ -19,6 +20,15 @@ where } } +// Custom deserializer function to convert strings to u16 +fn string_to_u16<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + return Ok(s.as_str().parse::().unwrap_or(0u16)); +} + #[derive(Deserialize)] struct Data { #[serde(rename = "intrinsic", default)] @@ -49,6 +59,10 @@ struct Parameter { type_data: String, #[serde(rename = "@etype", default)] etype: String, + #[serde(rename = "@memwidth", default, deserialize_with = "string_to_u16")] + memwidth: u16, + #[serde(rename = "@varname", default)] + var_name: String, } #[derive(Deserialize)] @@ -84,21 +98,39 @@ pub fn get_xml_intrinsics( Ok(parsed_intrinsics) } -pub fn xml_to_intrinsic( - mut intr: XMLIntrinsic, +fn xml_to_intrinsic( + intr: XMLIntrinsic, target: &String, ) -> Result, Box> { let name = intr.name; let results = X86IntrinsicType::from_c(&intr.return_data.type_data, target)?; - let arguments: Vec<_> = intr + let args: Vec<_> = intr .parameters .into_iter() .enumerate() - .map(|(i, arg)| { - // let arg_name = Argument::::type_and_name_from_c(&arg).1; + .map(|(i, param)| { + let constraint = None; + let ty = X86IntrinsicType::from_c(param.type_data.as_str(), target) + .unwrap_or_else(|_| panic!("Failed to parse argument '{i}'")); + + let mut arg = Argument::::new(i, param.var_name, ty, constraint); + let IntrinsicType { + ref mut constant, .. + } = arg.ty.0; + if param.etype == "IMM" { + *constant = true + } + arg }) .collect(); - todo!("xml_to_intrinsic needs to collect the arguments properly!"); + let arguments = ArgumentList:: { args }; + + Ok(Intrinsic { + name, + arguments, + results: results, + arch_tags: intr.cpuid, + }) } From 7b8e08c2b1dc3d542f9f162ea0d0adeee9092d45 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Sun, 8 Jun 2025 12:36:50 +0530 Subject: [PATCH 04/17] feat: added the simple set of argument types for X86 intrinsics --- crates/intrinsic-test/src/arm/intrinsic.rs | 4 +- crates/intrinsic-test/src/arm/types.rs | 10 ++-- crates/intrinsic-test/src/common/argument.rs | 4 +- .../src/common/intrinsic_helpers.rs | 54 +++++++++++++------ crates/intrinsic-test/src/x86/xml_parser.rs | 47 +++++++++------- 5 files changed, 75 insertions(+), 44 deletions(-) diff --git a/crates/intrinsic-test/src/arm/intrinsic.rs b/crates/intrinsic-test/src/arm/intrinsic.rs index 773dabf4d7..043ea9a218 100644 --- a/crates/intrinsic-test/src/arm/intrinsic.rs +++ b/crates/intrinsic-test/src/arm/intrinsic.rs @@ -73,8 +73,8 @@ impl IntrinsicDefinition for Intrinsic { 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::Int(true) => format!("int{}_t", self.results().inner_size()), + TypeKind::Int(false) => format!("uint{}_t", self.results().inner_size()), TypeKind::Poly => format!("poly{}_t", self.results().inner_size()), ty => todo!("print_result_c - Unknown type: {:#?}", ty), }, diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index f039ba7bcf..5e607c9629 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -73,8 +73,8 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { format!( "vld{len}{quad}_{type}{size}", type = match k { - TypeKind::UInt => "u", - TypeKind::Int => "s", + TypeKind::Int(false) => "u", + TypeKind::Int(true) => "s", TypeKind::Float => "f", // The ACLE doesn't support 64-bit polynomial loads on Armv7 // if armv7 and bl == 64, use "s", else "p" @@ -107,8 +107,8 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { format!( "vget{quad}_lane_{type}{size}", type = match k { - TypeKind::UInt => "u", - TypeKind::Int => "s", + TypeKind::Int(false) => "u", + TypeKind::Int(true) => "s", TypeKind::Float => "f", TypeKind::Poly => "p", x => todo!("get_load_function TypeKind: {:#?}", x), @@ -175,7 +175,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { } else { let kind = start.parse::()?; let bit_len = match kind { - TypeKind::Int => Some(32), + TypeKind::Int(_) => Some(32), _ => None, }; Ok(ArmIntrinsicType(IntrinsicType { diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index 639e7579ea..f448575864 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -79,8 +79,8 @@ where ) -> Argument { let (ty, var_name) = Self::type_and_name_from_c(arg); - let ty = - T::from_c(ty, target).unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); + let ty = T::from_c(ty, &target.to_string()) + .unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); Argument { pos, diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 1f0797102a..1d049a5d8f 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -12,8 +12,12 @@ use super::values::value_for_array; pub enum TypeKind { BFloat, Float, - Int, - UInt, + Double, + + // if signed, then the inner value is true + Int(bool), + Char(bool), + Short(bool), Poly, Void, } @@ -25,9 +29,10 @@ impl FromStr for TypeKind { match s { "bfloat" => Ok(Self::BFloat), "float" => Ok(Self::Float), - "int" => Ok(Self::Int), + "int" => Ok(Self::Int(true)), "poly" => Ok(Self::Poly), - "uint" | "unsigned" => Ok(Self::UInt), + "char" => Ok(Self::Char(true)), + "uint" | "unsigned" => Ok(Self::Int(false)), "void" => Ok(Self::Void), _ => Err(format!("Impossible to parse argument kind {s}")), } @@ -42,10 +47,15 @@ impl fmt::Display for TypeKind { match self { Self::BFloat => "bfloat", Self::Float => "float", - Self::Int => "int", - Self::UInt => "uint", + Self::Double => "double", + Self::Int(true) => "int", + Self::Int(false) => "uint", Self::Poly => "poly", Self::Void => "void", + Self::Char(true) => "char", + Self::Char(false) => "unsigned char", + Self::Short(true) => "short", + Self::Short(false) => "unsigned short", } ) } @@ -56,9 +66,11 @@ impl TypeKind { pub fn c_prefix(&self) -> &str { match self { Self::Float => "float", - Self::Int => "int", - Self::UInt => "uint", + Self::Int(true) => "int", + Self::Int(false) => "uint", Self::Poly => "poly", + Self::Char(true) => "char", + Self::Char(false) => "unsigned char", _ => unreachable!("Not used: {:#?}", self), } } @@ -67,8 +79,8 @@ impl TypeKind { pub fn rust_prefix(&self) -> &str { match self { Self::Float => "f", - Self::Int => "i", - Self::UInt => "u", + Self::Int(true) => "i", + Self::Int(false) => "u", Self::Poly => "u", _ => unreachable!("Unused type kind: {:#?}", self), } @@ -132,6 +144,18 @@ impl IntrinsicType { self.ptr } + pub fn set_bit_len(&mut self, value: Option) { + self.bit_len = value; + } + + pub fn set_simd_len(&mut self, value: Option) { + self.simd_len = value; + } + + pub fn set_vec_len(&mut self, value: Option) { + self.vec_len = value; + } + pub fn c_scalar_type(&self) -> String { format!( "{prefix}{bits}_t", @@ -155,8 +179,8 @@ impl IntrinsicType { bit_len: Some(8), .. } => match kind { - TypeKind::Int => "(int)", - TypeKind::UInt => "(unsigned int)", + TypeKind::Int(true) => "(int)", + TypeKind::Int(false) => "(unsigned int)", TypeKind::Poly => "(unsigned int)(uint8_t)", _ => "", }, @@ -185,7 +209,7 @@ impl IntrinsicType { match self { IntrinsicType { bit_len: Some(bit_len @ (8 | 16 | 32 | 64)), - kind: kind @ (TypeKind::Int | TypeKind::UInt | TypeKind::Poly), + kind: kind @ (TypeKind::Int(_) | TypeKind::Poly), simd_len, vec_len, .. @@ -201,7 +225,7 @@ impl IntrinsicType { .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 { + if *kind == TypeKind::Int(true) && (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; @@ -257,7 +281,7 @@ impl IntrinsicType { .. } => false, IntrinsicType { - kind: TypeKind::Int | TypeKind::UInt | TypeKind::Poly, + kind: TypeKind::Int(_) | TypeKind::Poly, .. } => true, _ => unimplemented!(), diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 1649c174a1..48715a6d44 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -105,26 +105,33 @@ fn xml_to_intrinsic( let name = intr.name; let results = X86IntrinsicType::from_c(&intr.return_data.type_data, target)?; - let args: Vec<_> = intr - .parameters - .into_iter() - .enumerate() - .map(|(i, param)| { - let constraint = None; - let ty = X86IntrinsicType::from_c(param.type_data.as_str(), target) - .unwrap_or_else(|_| panic!("Failed to parse argument '{i}'")); - - let mut arg = Argument::::new(i, param.var_name, ty, constraint); - let IntrinsicType { - ref mut constant, .. - } = arg.ty.0; - if param.etype == "IMM" { - *constant = true - } - arg - }) - .collect(); - + let args_check = intr.parameters.into_iter().enumerate().map(|(i, param)| { + let constraint = None; + let ty = X86IntrinsicType::from_c(param.type_data.as_str(), target); + + if let Err(_) = ty { + return None; + } + let mut ty_bit_len = param.etype.clone(); + ty_bit_len.retain(|c| c.is_numeric()); + let ty_bit_len = str::parse::(ty_bit_len.as_str()).ok(); + let mut ty = ty.unwrap(); + ty.set_bit_len(ty_bit_len); + let mut arg = Argument::::new(i, param.var_name, ty, constraint); + let IntrinsicType { + ref mut constant, .. + } = arg.ty.0; + if param.etype == "IMM" { + *constant = true + } + Some(arg) + }); + + let args = args_check.collect::>(); + if args.iter().any(|elem| elem.is_none()) { + return Err(Box::from("intrinsic isn't fully supported in this test!")); + } + let args = args.into_iter().map(|e| e.unwrap()).collect::>(); let arguments = ArgumentList:: { args }; Ok(Intrinsic { From e95bd9b6fa75a7ba3ec8fe9d300f7d2f6dc9dd80 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Sun, 8 Jun 2025 21:30:49 +0530 Subject: [PATCH 05/17] feat: added X86IntrinsicType parsing from string. --- .../src/common/intrinsic_helpers.rs | 13 ++--- crates/intrinsic-test/src/x86/intrinsic.rs | 9 +++- crates/intrinsic-test/src/x86/mod.rs | 25 +++++++++- crates/intrinsic-test/src/x86/types.rs | 50 ++++++++++++++++++- crates/intrinsic-test/src/x86/xml_parser.rs | 3 +- 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 1d049a5d8f..b8f38dd5c5 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -29,7 +29,9 @@ impl FromStr for TypeKind { match s { "bfloat" => Ok(Self::BFloat), "float" => Ok(Self::Float), - "int" => Ok(Self::Int(true)), + "double" => Ok(Self::Double), + "int" | "long" => Ok(Self::Int(true)), + "short" => Ok(Self::Short(true)), "poly" => Ok(Self::Poly), "char" => Ok(Self::Char(true)), "uint" | "unsigned" => Ok(Self::Int(false)), @@ -70,7 +72,6 @@ impl TypeKind { Self::Int(false) => "uint", Self::Poly => "poly", Self::Char(true) => "char", - Self::Char(false) => "unsigned char", _ => unreachable!("Not used: {:#?}", self), } } @@ -143,15 +144,15 @@ impl IntrinsicType { pub fn is_ptr(&self) -> bool { self.ptr } - + pub fn set_bit_len(&mut self, value: Option) { self.bit_len = value; } - + pub fn set_simd_len(&mut self, value: Option) { self.simd_len = value; } - + pub fn set_vec_len(&mut self, value: Option) { self.vec_len = value; } @@ -209,7 +210,7 @@ impl IntrinsicType { match self { IntrinsicType { bit_len: Some(bit_len @ (8 | 16 | 32 | 64)), - kind: kind @ (TypeKind::Int(_) | TypeKind::Poly), + kind: kind @ (TypeKind::Int(_) | TypeKind::Poly | TypeKind::Char(_)), simd_len, vec_len, .. diff --git a/crates/intrinsic-test/src/x86/intrinsic.rs b/crates/intrinsic-test/src/x86/intrinsic.rs index e4a2e7f463..b86b82feaa 100644 --- a/crates/intrinsic-test/src/x86/intrinsic.rs +++ b/crates/intrinsic-test/src/x86/intrinsic.rs @@ -2,7 +2,7 @@ use crate::common::argument::ArgumentList; use crate::common::indentation::Indentation; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::intrinsic_helpers::IntrinsicType; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; #[derive(Debug, Clone, PartialEq)] pub struct X86IntrinsicType(pub IntrinsicType); @@ -15,6 +15,13 @@ impl Deref for X86IntrinsicType { } } +impl DerefMut for X86IntrinsicType { + // type Target = IntrinsicType; + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl IntrinsicDefinition for Intrinsic { fn arguments(&self) -> ArgumentList { self.arguments.clone() diff --git a/crates/intrinsic-test/src/x86/mod.rs b/crates/intrinsic-test/src/x86/mod.rs index a435887f64..26c824e60f 100644 --- a/crates/intrinsic-test/src/x86/mod.rs +++ b/crates/intrinsic-test/src/x86/mod.rs @@ -1,12 +1,15 @@ mod intrinsic; mod types; mod xml_parser; +mod config; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; -use crate::common::intrinsic::Intrinsic; +use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; +use crate::common::write_file::{write_c_testfiles, write_rust_testfiles}; use intrinsic::X86IntrinsicType; use xml_parser::get_xml_intrinsics; +use config::build_notices; pub struct X86ArchitectureTest { intrinsics: Vec>, @@ -25,7 +28,25 @@ impl SupportedArchitectureTest for X86ArchitectureTest { } fn build_c_file(&self) -> bool { - todo!("build_c_file in X86ArchitectureTest is not implemented") + let compiler = self.cli_options.cpp_compiler.as_deref(); + let target = &self.cli_options.target; + let cxx_toolchain_dir = self.cli_options.cxx_toolchain_dir.as_deref(); + let c_target = "x86_64"; + + let intrinsics_name_list = write_c_testfiles( + &self + .intrinsics + .iter() + .map(|i| i as &dyn IntrinsicDefinition<_>) + .collect::>(), + target, + c_target, + &["immintrin.h"], + &build_notices("// "), + &[], + ); + + true } fn build_rust_file(&self) -> bool { diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index e38a2b1777..9392723118 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -1,6 +1,8 @@ +use std::str::FromStr; + use super::intrinsic::X86IntrinsicType; use crate::common::cli::Language; -use crate::common::intrinsic_helpers::IntrinsicTypeDefinition; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; impl IntrinsicTypeDefinition for X86IntrinsicType { /// Gets a string containing the typename for this type in C format. @@ -27,6 +29,50 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { } fn from_c(s: &str, target: &String) -> Result { - todo!("from_c for X86IntrinsicType needs to be implemented!"); + let mut s_copy = s.to_string(); + s_copy = s_copy + .replace("*", "") + .replace("constexpr", "") + .replace("const", "") + .replace("literal", ""); + + let s_split = s_copy.split(" ") + .filter_map(|s|if s.len() == 0 {None} else {Some(s)}) + .last(); + + // TODO: add more intrinsics by modifying + // functionality below this line. + // Currently all the intrinsics that have an "_" + // is ignored. + if let Some(_) = s.matches("_").next() { + return Err(String::from("This functionality needs to be implemented")); + }; + + // TODO: make the unwrapping safe + let kind = TypeKind::from_str(s_split.unwrap()).expect("Unable to parse type!"); + let mut ptr_constant = false; + let mut constant = false; + let mut ptr = false; + + if let Some(_) = s.matches("const*").next() { + ptr_constant = true; + }; + if let Some(_) = s.matches("const").next() { + constant = true; + }; + if let Some(_) = s.matches("*").next() { + ptr = true; + }; + + Ok(X86IntrinsicType(IntrinsicType { + ptr, + ptr_constant, + constant, + kind, + bit_len: None, + simd_len: None, + vec_len: None, + target: target.to_string(), + })) } } diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 48715a6d44..80225d641c 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -91,7 +91,8 @@ pub fn get_xml_intrinsics( .intrinsics .into_iter() .filter_map(|intr| { - Some(xml_to_intrinsic(intr, target).expect("Couldn't parse XML properly!")) + // Some(xml_to_intrinsic(intr, target).expect("Couldn't parse XML properly!")) + xml_to_intrinsic(intr, target).ok() }) .collect(); From 241f3094459addaae51f008d76e25a75489a6897 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Sun, 8 Jun 2025 22:23:38 +0530 Subject: [PATCH 06/17] fix: removing Box<> types from IntrinsicType in "from_c" definition for IntrinsicType impl --- crates/intrinsic-test/src/arm/json_parser.rs | 2 +- crates/intrinsic-test/src/x86/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/intrinsic-test/src/arm/json_parser.rs b/crates/intrinsic-test/src/arm/json_parser.rs index 58d366c86a..bde2da0820 100644 --- a/crates/intrinsic-test/src/arm/json_parser.rs +++ b/crates/intrinsic-test/src/arm/json_parser.rs @@ -79,7 +79,7 @@ fn json_to_intrinsic( ) -> Result, Box> { let name = intr.name.replace(['[', ']'], ""); - let results = ArmIntrinsicType::from_c(&intr.return_type.value, target)?; + let results = ArmIntrinsicType::from_c(&intr.return_type.value, &target.to_string())?; let args = intr .arguments diff --git a/crates/intrinsic-test/src/x86/mod.rs b/crates/intrinsic-test/src/x86/mod.rs index 26c824e60f..2c2ecfb4cf 100644 --- a/crates/intrinsic-test/src/x86/mod.rs +++ b/crates/intrinsic-test/src/x86/mod.rs @@ -1,15 +1,15 @@ +mod config; mod intrinsic; mod types; mod xml_parser; -mod config; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::write_file::{write_c_testfiles, write_rust_testfiles}; +use config::build_notices; use intrinsic::X86IntrinsicType; use xml_parser::get_xml_intrinsics; -use config::build_notices; pub struct X86ArchitectureTest { intrinsics: Vec>, From c77800a4967a90fd643480beb3b6b89dd26ad884 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Sun, 8 Jun 2025 23:00:01 +0530 Subject: [PATCH 07/17] feat: implemented c_type for X86IntrinsicType --- .../src/common/intrinsic_helpers.rs | 7 ++-- crates/intrinsic-test/src/x86/types.rs | 33 ++++++++++++++----- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index b8f38dd5c5..9a36535d36 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -72,6 +72,7 @@ impl TypeKind { Self::Int(false) => "uint", Self::Poly => "poly", Self::Char(true) => "char", + Self::Double => "double", _ => unreachable!("Not used: {:#?}", self), } } @@ -144,15 +145,15 @@ impl IntrinsicType { pub fn is_ptr(&self) -> bool { self.ptr } - + pub fn set_bit_len(&mut self, value: Option) { self.bit_len = value; } - + pub fn set_simd_len(&mut self, value: Option) { self.simd_len = value; } - + pub fn set_vec_len(&mut self, value: Option) { self.vec_len = value; } diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index 9392723118..147441c1a1 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -7,7 +7,21 @@ use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, T impl IntrinsicTypeDefinition for X86IntrinsicType { /// Gets a string containing the typename for this type in C format. fn c_type(&self) -> String { - todo!("c_type for X86IntrinsicType needs to be implemented!"); + let part_0 = if self.constant { "const" } else { "" }; + let part_1 = match self.kind { + TypeKind::Int(false) => "unsigned int", + TypeKind::Char(false) => "unsigned char", + TypeKind::Short(false) => "unsigned short", + TypeKind::Short(true) => "short", + _ => self.kind.c_prefix(), + }; + let part_2 = if self.ptr { + if self.ptr_constant { "* const" } else { "*" } + } else { + "" + }; + + String::from(vec![part_0, part_1, part_2].join(" ").trim()) } fn c_single_vector_type(&self) -> String { @@ -35,25 +49,26 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { .replace("constexpr", "") .replace("const", "") .replace("literal", ""); - - let s_split = s_copy.split(" ") - .filter_map(|s|if s.len() == 0 {None} else {Some(s)}) + + let s_split = s_copy + .split(" ") + .filter_map(|s| if s.len() == 0 { None } else { Some(s) }) .last(); - - // TODO: add more intrinsics by modifying + + // TODO: add more intrinsics by modifying // functionality below this line. // Currently all the intrinsics that have an "_" // is ignored. if let Some(_) = s.matches("_").next() { return Err(String::from("This functionality needs to be implemented")); }; - + // TODO: make the unwrapping safe let kind = TypeKind::from_str(s_split.unwrap()).expect("Unable to parse type!"); let mut ptr_constant = false; let mut constant = false; let mut ptr = false; - + if let Some(_) = s.matches("const*").next() { ptr_constant = true; }; @@ -63,7 +78,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { if let Some(_) = s.matches("*").next() { ptr = true; }; - + Ok(X86IntrinsicType(IntrinsicType { ptr, ptr_constant, From 287b83c73bc138e8d3a83b8d3b3965b403b2df5f Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Fri, 13 Jun 2025 13:04:06 +0530 Subject: [PATCH 08/17] Sharpening the parsing logic: 1. filtered any intrinsic arguments where the only parameter is of type "void" 2. Better parsing for intrinsic return type 3. Filtering intrinsics that are difficult to test (void returns) 4. Reduced the variants in TypeKind (which differed only in bit_len) --- .../src/common/intrinsic_helpers.rs | 44 ++++--- crates/intrinsic-test/src/x86/intrinsic.rs | 68 ++++++++++- crates/intrinsic-test/src/x86/mod.rs | 18 ++- crates/intrinsic-test/src/x86/types.rs | 108 +++++++++++++----- crates/intrinsic-test/src/x86/xml_parser.rs | 78 ++++--------- 5 files changed, 217 insertions(+), 99 deletions(-) diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 9a36535d36..8149f953d1 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -12,12 +12,10 @@ use super::values::value_for_array; pub enum TypeKind { BFloat, Float, - Double, // if signed, then the inner value is true Int(bool), Char(bool), - Short(bool), Poly, Void, } @@ -29,9 +27,8 @@ impl FromStr for TypeKind { match s { "bfloat" => Ok(Self::BFloat), "float" => Ok(Self::Float), - "double" => Ok(Self::Double), - "int" | "long" => Ok(Self::Int(true)), - "short" => Ok(Self::Short(true)), + "double" => Ok(Self::Float), + "int" | "long" | "short" => Ok(Self::Int(true)), "poly" => Ok(Self::Poly), "char" => Ok(Self::Char(true)), "uint" | "unsigned" => Ok(Self::Int(false)), @@ -49,15 +46,12 @@ impl fmt::Display for TypeKind { match self { Self::BFloat => "bfloat", Self::Float => "float", - Self::Double => "double", Self::Int(true) => "int", Self::Int(false) => "uint", Self::Poly => "poly", Self::Void => "void", Self::Char(true) => "char", Self::Char(false) => "unsigned char", - Self::Short(true) => "short", - Self::Short(false) => "unsigned short", } ) } @@ -72,7 +66,6 @@ impl TypeKind { Self::Int(false) => "uint", Self::Poly => "poly", Self::Char(true) => "char", - Self::Double => "double", _ => unreachable!("Not used: {:#?}", self), } } @@ -126,7 +119,7 @@ impl IntrinsicType { if let Some(bl) = self.bit_len { bl } else { - unreachable!("") + unreachable!("{}", self.kind) } } @@ -159,11 +152,17 @@ impl IntrinsicType { } pub fn c_scalar_type(&self) -> String { - format!( - "{prefix}{bits}_t", - prefix = self.kind().c_prefix(), - bits = self.inner_size() - ) + match self { + IntrinsicType { + kind: TypeKind::Char(_), + .. + } => String::from("char"), + _ => format!( + "{prefix}{bits}_t", + prefix = self.kind().c_prefix(), + bits = self.inner_size() + ), + } } pub fn rust_scalar_type(&self) -> String { @@ -198,6 +197,21 @@ impl IntrinsicType { 128 => "", _ => panic!("invalid bit_len"), }, + IntrinsicType { + kind: TypeKind::Float, + bit_len: Some(bit_len), + .. + } => match bit_len { + 16 => "(float16_t)", + 32 => "(float)", + 64 => "(double)", + 128 => "", + _ => panic!("invalid bit_len"), + }, + IntrinsicType { + kind: TypeKind::Char(_), + .. + } => "(char)", _ => "", } } diff --git a/crates/intrinsic-test/src/x86/intrinsic.rs b/crates/intrinsic-test/src/x86/intrinsic.rs index b86b82feaa..2faeff3fa9 100644 --- a/crates/intrinsic-test/src/x86/intrinsic.rs +++ b/crates/intrinsic-test/src/x86/intrinsic.rs @@ -1,7 +1,7 @@ use crate::common::argument::ArgumentList; use crate::common::indentation::Indentation; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; -use crate::common::intrinsic_helpers::IntrinsicType; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; use std::ops::{Deref, DerefMut}; #[derive(Debug, Clone, PartialEq)] @@ -38,7 +38,69 @@ impl IntrinsicDefinition for 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. - fn print_result_c(&self, _indentation: Indentation, _additional: &str) -> String { - todo!("print_result_c in Intrinsic needs to be implemented!"); + 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()) + .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(), + lane = idx, + vector = vector, + ) + }) + .collect::>() + .join(r#" << ", " << "#) + ) + }) + .collect::>() + .join(r#" << ", " << "#) + } 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(), + lane = idx + ) + }) + .collect::>() + .join(r#" << ", " << "#) + } else { + format!( + "{promote}cast<{cast}>(__return_value)", + cast = match self.results.kind() { + TypeKind::Void => "void".to_string(), + TypeKind::Float if self.results().inner_size() == 64 => "double".to_string(), + TypeKind::Float if self.results().inner_size() == 32 => "float".to_string(), + // TypeKind::Float if self.results().inner_size() == 16 => "float16_t".to_string(), + // TypeKind::Int(true) if self.results().inner_size() == 64 => "long".to_string(), + // TypeKind::Int(false) if self.results().inner_size() == 64 => "unsigned long".to_string(), + // TypeKind::Int(true) if self.results().inner_size() == 32 => "int".to_string(), + // TypeKind::Int(false) if self.results().inner_size() == 32 => "unsigned int".to_string(), + // TypeKind::Int(true) if self.results().inner_size() == 16 => "short".to_string(), + // TypeKind::Int(false) if self.results().inner_size() == 16 => "unsigned short".to_string(), + _ => self.results.c_scalar_type(), + }, + 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()) + } else { + String::from("") + }, + close = if self.results.is_simd() { ")" } else { "" }, + ) } } diff --git a/crates/intrinsic-test/src/x86/mod.rs b/crates/intrinsic-test/src/x86/mod.rs index 2c2ecfb4cf..bf509984cc 100644 --- a/crates/intrinsic-test/src/x86/mod.rs +++ b/crates/intrinsic-test/src/x86/mod.rs @@ -6,6 +6,7 @@ mod xml_parser; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; +use crate::common::intrinsic_helpers::TypeKind; use crate::common::write_file::{write_c_testfiles, write_rust_testfiles}; use config::build_notices; use intrinsic::X86IntrinsicType; @@ -18,9 +19,24 @@ pub struct X86ArchitectureTest { impl SupportedArchitectureTest for X86ArchitectureTest { fn create(cli_options: ProcessedCli) -> Box { - let intrinsics = get_xml_intrinsics(&cli_options.filename, &cli_options.target) + let mut intrinsics = get_xml_intrinsics(&cli_options.filename, &cli_options.target) .expect("Error parsing input file"); + intrinsics.sort_by(|a, b| a.name.cmp(&b.name)); + let intrinsics = intrinsics + .into_iter() + // Not sure how we would compare intrinsic that returns void. + .filter(|i| i.results.kind() != TypeKind::Void) + .filter(|i| i.results.kind() != TypeKind::BFloat) + .filter(|i| i.arguments().args.len() > 0) + .filter(|i| !i.arguments.iter().any(|a| a.ty.kind() == TypeKind::BFloat)) + // Skip pointers for now, we would probably need to look at the return + // type to work out how many elements we need to point to. + .filter(|i| !i.arguments.iter().any(|a| a.is_ptr())) + .filter(|i| !i.arguments.iter().any(|a| a.ty.inner_size() == 128)) + .filter(|i| !cli_options.skip.contains(&i.name)) + .collect::>(); + Box::new(Self { intrinsics: intrinsics, cli_options: cli_options, diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index 147441c1a1..de8c22d589 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -1,5 +1,7 @@ use std::str::FromStr; +use itertools::Itertools; + use super::intrinsic::X86IntrinsicType; use crate::common::cli::Language; use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; @@ -11,15 +13,9 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { let part_1 = match self.kind { TypeKind::Int(false) => "unsigned int", TypeKind::Char(false) => "unsigned char", - TypeKind::Short(false) => "unsigned short", - TypeKind::Short(true) => "short", _ => self.kind.c_prefix(), }; - let part_2 = if self.ptr { - if self.ptr_constant { "* const" } else { "*" } - } else { - "" - }; + let part_2 = if self.ptr { "*" } else { "" }; String::from(vec![part_0, part_1, part_2].join(" ").trim()) } @@ -46,6 +42,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { let mut s_copy = s.to_string(); s_copy = s_copy .replace("*", "") + .replace("_", "") .replace("constexpr", "") .replace("const", "") .replace("literal", ""); @@ -55,30 +52,25 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { .filter_map(|s| if s.len() == 0 { None } else { Some(s) }) .last(); - // TODO: add more intrinsics by modifying - // functionality below this line. - // Currently all the intrinsics that have an "_" - // is ignored. - if let Some(_) = s.matches("_").next() { - return Err(String::from("This functionality needs to be implemented")); - }; + let s_split = s_split.map(|s| s.chars().filter(|c| !c.is_numeric()).join("")); // TODO: make the unwrapping safe - let kind = TypeKind::from_str(s_split.unwrap()).expect("Unable to parse type!"); - let mut ptr_constant = false; - let mut constant = false; - let mut ptr = false; + let kind = TypeKind::from_str(s_split.unwrap().trim()).unwrap_or(TypeKind::Void); - if let Some(_) = s.matches("const*").next() { - ptr_constant = true; - }; - if let Some(_) = s.matches("const").next() { - constant = true; - }; - if let Some(_) = s.matches("*").next() { - ptr = true; + let kind = if s.find("unsigned").is_some() { + match kind { + TypeKind::Int(_) => TypeKind::Int(false), + TypeKind::Char(_) => TypeKind::Char(false), + a => a, + } + } else { + kind }; + let ptr_constant = false; + let constant = s.matches("const").next().is_some(); + let ptr = s.matches("*").next().is_some(); + Ok(X86IntrinsicType(IntrinsicType { ptr, ptr_constant, @@ -91,3 +83,67 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { })) } } + +impl X86IntrinsicType { + pub fn from_param(param: &Parameter) -> Result { + match Self::from_c(param.type_data.as_str()) { + Err(message) => Err(message), + Ok(mut ret) => { + // First correct the type of the parameter using param.etype. + // The assumption is that the parameter of type void may have param.type + // as "__m128i", "__mmask8" and the like. + ret.set_metadata("etype".to_string(), param.etype.clone()); + if !param.etype.is_empty() { + match TypeKind::from_str(param.etype.as_str()) { + Ok(value) => { + ret.kind = value; + } + Err(_) => {} + }; + } + + // check for param.etype. + // extract the numeric part and set as bit-len + // If param.etype is not present, guess the default bit-len + + let mut etype_processed = param.etype.clone(); + etype_processed.retain(|c| c.is_numeric()); + + match str::parse::(etype_processed.as_str()) { + Ok(value) => ret.bit_len = Some(value), + Err(_) => { + ret.bit_len = match ret.kind() { + TypeKind::Char(_) => Some(8), + TypeKind::BFloat => Some(16), + TypeKind::Int(_) => Some(32), + TypeKind::Float => Some(32), + _ => None, + }; + } + } + + // then check the param.type and extract numeric part if there are double + // underscores. divide this number with bit-len and set this as simd-len. + + let mut type_processed = param.etype.clone(); + type_processed.retain(|c| c.is_numeric()); + + ret.vec_len = match str::parse::(etype_processed.as_str()) { + // If bit_len is None, vec_len will be None. + // Else vec_len will be (num_bits / bit_len). + Ok(num_bits) => ret.bit_len.and(Some(num_bits / ret.bit_len.unwrap())), + Err(_) => None, + }; + + // if param.etype == IMM, then it is a constant. + // else it stays unchanged. + ret.constant |= param.etype == "IMM"; + + Ok(ret) + } + } + // Tile types won't currently reach here, since the intrinsic that involve them + // often return "null" type. Such intrinsics are not tested in `intrinsic-test` + // currently and are filtered out at `mod.rs`. + } +} diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 80225d641c..9ebdf887c6 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -1,25 +1,12 @@ use crate::common::argument::{Argument, ArgumentList}; use crate::common::intrinsic::Intrinsic; -use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition}; +use crate::common::intrinsic_helpers::TypeKind; use serde::{Deserialize, Deserializer}; use std::path::Path; use super::intrinsic::X86IntrinsicType; -// Custom deserializer function to convert "TRUE"/"FALSE" strings to boolean -fn string_to_bool<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s = String::deserialize(deserializer)?; - match s.as_str() { - "TRUE" => Ok(true), - "FALSE" => Ok(false), - _ => Ok(false), // Default to false for any other value - } -} - // Custom deserializer function to convert strings to u16 fn string_to_u16<'de, D>(deserializer: D) -> Result where @@ -38,7 +25,7 @@ struct Data { #[derive(Deserialize)] struct XMLIntrinsic { #[serde(rename = "return")] - return_data: Return, + return_data: Parameter, #[serde(rename = "@name")] name: String, #[serde(rename = "@tech")] @@ -47,10 +34,6 @@ struct XMLIntrinsic { cpuid: Vec, #[serde(rename = "parameter", default)] parameters: Vec, - #[serde(rename = "@sequence", default, deserialize_with = "string_to_bool")] - generates_sequence: bool, - #[serde(default)] - instruction: Vec, } #[derive(Deserialize)] @@ -65,18 +48,6 @@ struct Parameter { var_name: String, } -#[derive(Deserialize)] -struct Return { - #[serde(rename = "@type", default)] - type_data: String, -} - -#[derive(Deserialize, Debug)] -struct Instruction { - #[serde(rename = "@name")] - name: String, -} - pub fn get_xml_intrinsics( filename: &Path, target: &String, @@ -86,7 +57,6 @@ pub fn get_xml_intrinsics( let data: Data = quick_xml::de::from_reader(reader).expect("failed to deserialize the source XML file"); - // println!("{} intrinsics found", data.intrinsics.len()); let parsed_intrinsics: Vec> = data .intrinsics .into_iter() @@ -104,41 +74,41 @@ fn xml_to_intrinsic( target: &String, ) -> Result, Box> { let name = intr.name; - let results = X86IntrinsicType::from_c(&intr.return_data.type_data, target)?; - + let result = X86IntrinsicType::from_param(&intr.return_data); let args_check = intr.parameters.into_iter().enumerate().map(|(i, param)| { - let constraint = None; - let ty = X86IntrinsicType::from_c(param.type_data.as_str(), target); - - if let Err(_) = ty { - return None; - } - let mut ty_bit_len = param.etype.clone(); - ty_bit_len.retain(|c| c.is_numeric()); - let ty_bit_len = str::parse::(ty_bit_len.as_str()).ok(); - let mut ty = ty.unwrap(); - ty.set_bit_len(ty_bit_len); - let mut arg = Argument::::new(i, param.var_name, ty, constraint); - let IntrinsicType { - ref mut constant, .. - } = arg.ty.0; - if param.etype == "IMM" { - *constant = true + let ty = X86IntrinsicType::from_param(¶m); + if ty.is_err() { + None + } else { + let constraint = None; + let arg = Argument::::new( + i, + param.var_name.clone(), + ty.unwrap(), + constraint, + ); + Some(arg) } - Some(arg) }); let args = args_check.collect::>(); if args.iter().any(|elem| elem.is_none()) { return Err(Box::from("intrinsic isn't fully supported in this test!")); } - let args = args.into_iter().map(|e| e.unwrap()).collect::>(); + let args = args + .into_iter() + .map(|e| e.unwrap()) + .filter(|arg| arg.ty.ptr || arg.ty.kind != TypeKind::Void) + .collect::>(); let arguments = ArgumentList:: { args }; + if let Err(message) = result { + return Err(Box::from(message)); + } Ok(Intrinsic { name, arguments, - results: results, + results: result.unwrap(), arch_tags: intr.cpuid, }) } From 6ee8e574a87dfec518b494e2c4fdedca397ece91 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 16 Jun 2025 12:40:10 +0530 Subject: [PATCH 09/17] feat: demote "target" to a 2nd class variable, since it is only rarely necessary. Further notes: 1. IntrinsicType.target -> IntrinsicType.metadata 2. Maintaining a HashMap to support arbitrary data storage for other arch 3. Create a dedicated "from_param" associated function for X86IntrinsicType --- crates/intrinsic-test/src/arm/intrinsic.rs | 8 ++++++- crates/intrinsic-test/src/arm/json_parser.rs | 8 ++++--- crates/intrinsic-test/src/arm/types.rs | 22 ++++++++++++------- crates/intrinsic-test/src/common/argument.rs | 10 ++------- crates/intrinsic-test/src/common/gen_c.rs | 3 +-- .../src/common/intrinsic_helpers.rs | 22 +++++++++++++------ crates/intrinsic-test/src/x86/intrinsic.rs | 1 - crates/intrinsic-test/src/x86/mod.rs | 4 ++-- crates/intrinsic-test/src/x86/types.rs | 5 +++-- crates/intrinsic-test/src/x86/xml_parser.rs | 4 +--- 10 files changed, 50 insertions(+), 37 deletions(-) diff --git a/crates/intrinsic-test/src/arm/intrinsic.rs b/crates/intrinsic-test/src/arm/intrinsic.rs index 043ea9a218..8ec558ac11 100644 --- a/crates/intrinsic-test/src/arm/intrinsic.rs +++ b/crates/intrinsic-test/src/arm/intrinsic.rs @@ -2,7 +2,7 @@ use crate::common::argument::ArgumentList; use crate::common::indentation::Indentation; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; #[derive(Debug, Clone, PartialEq)] pub struct ArmIntrinsicType(pub IntrinsicType); @@ -15,6 +15,12 @@ impl Deref for ArmIntrinsicType { } } +impl DerefMut for ArmIntrinsicType { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl IntrinsicDefinition for Intrinsic { fn arguments(&self) -> ArgumentList { self.arguments.clone() diff --git a/crates/intrinsic-test/src/arm/json_parser.rs b/crates/intrinsic-test/src/arm/json_parser.rs index bde2da0820..856f2e6ec2 100644 --- a/crates/intrinsic-test/src/arm/json_parser.rs +++ b/crates/intrinsic-test/src/arm/json_parser.rs @@ -79,8 +79,8 @@ fn json_to_intrinsic( ) -> Result, Box> { let name = intr.name.replace(['[', ']'], ""); - let results = ArmIntrinsicType::from_c(&intr.return_type.value, &target.to_string())?; - + let mut results = ArmIntrinsicType::from_c(&intr.return_type.value)?; + results.set_metadata("target".to_string(), target.to_string()); let args = intr .arguments .into_iter() @@ -92,7 +92,9 @@ fn json_to_intrinsic( let arg_prep: Option = metadata.and_then(|a| a.try_into().ok()); let constraint: Option = arg_prep.and_then(|a| a.try_into().ok()); - let mut arg = Argument::::from_c(i, &arg, target, constraint); + let mut arg = Argument::::from_c(i, &arg, constraint); + arg.ty + .set_metadata("target".to_string(), target.to_string()); // The JSON doesn't list immediates as const let IntrinsicType { diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 5e607c9629..0fce7196f1 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use super::intrinsic::ArmIntrinsicType; use crate::common::cli::Language; use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; @@ -59,7 +61,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { bit_len: Some(bl), simd_len, vec_len, - target, + metadata, .. } = &self.0 { @@ -69,7 +71,11 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { "" }; - let choose_workaround = language == Language::C && target.contains("v7"); + let choose_workaround = language == Language::C + && metadata + .get("target") + .filter(|value| value.contains("v7")) + .is_some(); format!( "vld{len}{quad}_{type}{size}", type = match k { @@ -121,7 +127,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { } } - fn from_c(s: &str, target: &String) -> Result { + fn from_c(s: &str) -> Result { const CONST_STR: &str = "const"; if let Some(s) = s.strip_suffix('*') { let (s, constant) = match s.trim().strip_suffix(CONST_STR) { @@ -129,10 +135,10 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { None => (s, false), }; let s = s.trim_end(); - let temp_return = ArmIntrinsicType::from_c(s, target); + let temp_return = ArmIntrinsicType::from_c(s); temp_return.and_then(|mut op| { - op.0.ptr = true; - op.0.ptr_constant = constant; + op.ptr = true; + op.ptr_constant = constant; Ok(op) }) } else { @@ -170,7 +176,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { bit_len: Some(bit_len), simd_len, vec_len, - target: target.to_string(), + metadata: HashMap::new(), })) } else { let kind = start.parse::()?; @@ -186,7 +192,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { bit_len, simd_len: None, vec_len: None, - target: target.to_string(), + metadata: HashMap::new(), })) } } diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index f448575864..f7f46f8925 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -71,16 +71,10 @@ where } } - pub fn from_c( - pos: usize, - arg: &str, - target: &str, - constraint: Option, - ) -> Argument { + pub fn from_c(pos: usize, arg: &str, constraint: Option) -> Argument { let (ty, var_name) = Self::type_and_name_from_c(arg); - let ty = T::from_c(ty, &target.to_string()) - .unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); + let ty = T::from_c(ty).unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); Argument { pos, diff --git a/crates/intrinsic-test/src/common/gen_c.rs b/crates/intrinsic-test/src/common/gen_c.rs index 84c28cc4bf..5ea56f6ea5 100644 --- a/crates/intrinsic-test/src/common/gen_c.rs +++ b/crates/intrinsic-test/src/common/gen_c.rs @@ -105,7 +105,6 @@ pub fn generate_c_test_loop( indentation: Indentation, additional: &str, passes: u32, - _target: &str, ) -> String { let body_indentation = indentation.nested(); format!( @@ -157,7 +156,7 @@ pub fn generate_c_constraint_blocks( }) .join("\n") } else { - generate_c_test_loop(intrinsic, indentation, &name, PASSES, target) + generate_c_test_loop(intrinsic, indentation, &name, PASSES) } } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 8149f953d1..7741a5e957 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::fmt; use std::ops::Deref; use std::str::FromStr; @@ -18,6 +19,7 @@ pub enum TypeKind { Char(bool), Poly, Void, + Mask, } impl FromStr for TypeKind { @@ -25,14 +27,14 @@ impl FromStr for TypeKind { fn from_str(s: &str) -> Result { match s { - "bfloat" => Ok(Self::BFloat), - "float" => Ok(Self::Float), - "double" => Ok(Self::Float), - "int" | "long" | "short" => Ok(Self::Int(true)), + "bfloat" | "BF16" => Ok(Self::BFloat), + "float" | "double" | "FP16" | "FP32" | "FP64" => Ok(Self::Float), + "int" | "long" | "short" | "SI8" | "SI16" | "SI32" | "SI64" => Ok(Self::Int(true)), "poly" => Ok(Self::Poly), "char" => Ok(Self::Char(true)), - "uint" | "unsigned" => Ok(Self::Int(false)), + "uint" | "unsigned" | "UI8" | "UI16" | "UI32" | "UI64" => Ok(Self::Int(false)), "void" => Ok(Self::Void), + "MASK" => Ok(Self::Mask), _ => Err(format!("Impossible to parse argument kind {s}")), } } @@ -52,6 +54,7 @@ impl fmt::Display for TypeKind { Self::Void => "void", Self::Char(true) => "char", Self::Char(false) => "unsigned char", + Self::Mask => "mask", } ) } @@ -107,7 +110,8 @@ pub struct IntrinsicType { /// A value of `None` can be assumed to be 1 though. pub vec_len: Option, - pub target: String, + // pub target: String, + pub metadata: HashMap, } impl IntrinsicType { @@ -151,6 +155,10 @@ impl IntrinsicType { self.vec_len = value; } + pub fn set_metadata(&mut self, key: String, value: String) { + self.metadata.insert(key, value); + } + pub fn c_scalar_type(&self) -> String { match self { IntrinsicType { @@ -322,7 +330,7 @@ pub trait IntrinsicTypeDefinition: Deref { fn get_lane_function(&self) -> String; /// can be implemented in an `impl` block - fn from_c(_s: &str, _target: &String) -> Result + fn from_c(_s: &str) -> Result where Self: Sized; diff --git a/crates/intrinsic-test/src/x86/intrinsic.rs b/crates/intrinsic-test/src/x86/intrinsic.rs index 2faeff3fa9..d02a42933a 100644 --- a/crates/intrinsic-test/src/x86/intrinsic.rs +++ b/crates/intrinsic-test/src/x86/intrinsic.rs @@ -16,7 +16,6 @@ impl Deref for X86IntrinsicType { } impl DerefMut for X86IntrinsicType { - // type Target = IntrinsicType; fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } diff --git a/crates/intrinsic-test/src/x86/mod.rs b/crates/intrinsic-test/src/x86/mod.rs index bf509984cc..13e2165d4f 100644 --- a/crates/intrinsic-test/src/x86/mod.rs +++ b/crates/intrinsic-test/src/x86/mod.rs @@ -19,8 +19,8 @@ pub struct X86ArchitectureTest { impl SupportedArchitectureTest for X86ArchitectureTest { fn create(cli_options: ProcessedCli) -> Box { - let mut intrinsics = get_xml_intrinsics(&cli_options.filename, &cli_options.target) - .expect("Error parsing input file"); + let mut intrinsics = + get_xml_intrinsics(&cli_options.filename).expect("Error parsing input file"); intrinsics.sort_by(|a, b| a.name.cmp(&b.name)); let intrinsics = intrinsics diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index de8c22d589..3e4df6d37c 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::str::FromStr; use itertools::Itertools; @@ -38,7 +39,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { todo!("get_lane_function for X86IntrinsicType needs to be implemented!"); } - fn from_c(s: &str, target: &String) -> Result { + fn from_c(s: &str) -> Result { let mut s_copy = s.to_string(); s_copy = s_copy .replace("*", "") @@ -79,7 +80,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { bit_len: None, simd_len: None, vec_len: None, - target: target.to_string(), + metadata: HashMap::new(), })) } } diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 9ebdf887c6..78c840ead9 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -50,7 +50,6 @@ struct Parameter { pub fn get_xml_intrinsics( filename: &Path, - target: &String, ) -> Result>, Box> { let file = std::fs::File::open(filename)?; let reader = std::io::BufReader::new(file); @@ -62,7 +61,7 @@ pub fn get_xml_intrinsics( .into_iter() .filter_map(|intr| { // Some(xml_to_intrinsic(intr, target).expect("Couldn't parse XML properly!")) - xml_to_intrinsic(intr, target).ok() + xml_to_intrinsic(intr).ok() }) .collect(); @@ -71,7 +70,6 @@ pub fn get_xml_intrinsics( fn xml_to_intrinsic( intr: XMLIntrinsic, - target: &String, ) -> Result, Box> { let name = intr.name; let result = X86IntrinsicType::from_param(&intr.return_data); From 16bd12cfd71e933cbc0e91b185dfed065c10bbaf Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 16 Jun 2025 12:56:33 +0530 Subject: [PATCH 10/17] Add x86/config.rs to intrinsic-test --- crates/intrinsic-test/src/x86/config.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 crates/intrinsic-test/src/x86/config.rs diff --git a/crates/intrinsic-test/src/x86/config.rs b/crates/intrinsic-test/src/x86/config.rs new file mode 100644 index 0000000000..c3eeb14f29 --- /dev/null +++ b/crates/intrinsic-test/src/x86/config.rs @@ -0,0 +1,9 @@ +pub fn build_notices(line_prefix: &str) -> String { + format!( + "\ +{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the +{line_prefix}test are derived from a JSON specification, published under the same license as the +{line_prefix}`intrinsic-test` crate.\n +" + ) +} From e827a0466cc8149761e8b0f5b04e5c68715cd8ed Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 16 Jun 2025 13:44:01 +0530 Subject: [PATCH 11/17] Fix: unused variables. --- .../src/common/intrinsic_helpers.rs | 14 +++-------- crates/intrinsic-test/src/x86/mod.rs | 9 +++---- crates/intrinsic-test/src/x86/types.rs | 2 +- crates/intrinsic-test/src/x86/xml_parser.rs | 24 +++++++++---------- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index 7741a5e957..e830d2258a 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -143,17 +143,9 @@ impl IntrinsicType { self.ptr } - pub fn set_bit_len(&mut self, value: Option) { - self.bit_len = value; - } - - pub fn set_simd_len(&mut self, value: Option) { - self.simd_len = value; - } - - pub fn set_vec_len(&mut self, value: Option) { - self.vec_len = value; - } + // pub fn set_bit_len(&mut self, value: Option) { + // self.bit_len = value; + // } pub fn set_metadata(&mut self, key: String, value: String) { self.metadata.insert(key, value); diff --git a/crates/intrinsic-test/src/x86/mod.rs b/crates/intrinsic-test/src/x86/mod.rs index 13e2165d4f..65100af989 100644 --- a/crates/intrinsic-test/src/x86/mod.rs +++ b/crates/intrinsic-test/src/x86/mod.rs @@ -7,7 +7,7 @@ use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; use crate::common::intrinsic_helpers::TypeKind; -use crate::common::write_file::{write_c_testfiles, write_rust_testfiles}; +use crate::common::write_file::write_c_testfiles; use config::build_notices; use intrinsic::X86IntrinsicType; use xml_parser::get_xml_intrinsics; @@ -44,12 +44,13 @@ impl SupportedArchitectureTest for X86ArchitectureTest { } fn build_c_file(&self) -> bool { - let compiler = self.cli_options.cpp_compiler.as_deref(); + // let compiler = self.cli_options.cpp_compiler.as_deref(); let target = &self.cli_options.target; - let cxx_toolchain_dir = self.cli_options.cxx_toolchain_dir.as_deref(); + // let cxx_toolchain_dir = self.cli_options.cxx_toolchain_dir.as_deref(); let c_target = "x86_64"; - let intrinsics_name_list = write_c_testfiles( + /* let intrinsics_name_list = */ + write_c_testfiles( &self .intrinsics .iter() diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index 3e4df6d37c..c8a0c1f38b 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -30,7 +30,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { } /// Determines the load function for this type. - fn get_load_function(&self, language: Language) -> String { + fn get_load_function(&self, _language: Language) -> String { todo!("get_load_function for X86IntrinsicType needs to be implemented!"); } diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 78c840ead9..ac55087d67 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -2,19 +2,19 @@ use crate::common::argument::{Argument, ArgumentList}; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; -use serde::{Deserialize, Deserializer}; +use serde::Deserialize; use std::path::Path; use super::intrinsic::X86IntrinsicType; // Custom deserializer function to convert strings to u16 -fn string_to_u16<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s = String::deserialize(deserializer)?; - return Ok(s.as_str().parse::().unwrap_or(0u16)); -} +// fn string_to_u16<'de, D>(deserializer: D) -> Result +// where +// D: Deserializer<'de>, +// { +// let s = String::deserialize(deserializer)?; +// return Ok(s.as_str().parse::().unwrap_or(0u16)); +// } #[derive(Deserialize)] struct Data { @@ -28,8 +28,8 @@ struct XMLIntrinsic { return_data: Parameter, #[serde(rename = "@name")] name: String, - #[serde(rename = "@tech")] - tech: String, + // #[serde(rename = "@tech")] + // tech: String, #[serde(rename = "CPUID", default)] cpuid: Vec, #[serde(rename = "parameter", default)] @@ -42,8 +42,8 @@ struct Parameter { type_data: String, #[serde(rename = "@etype", default)] etype: String, - #[serde(rename = "@memwidth", default, deserialize_with = "string_to_u16")] - memwidth: u16, + // #[serde(rename = "@memwidth", default, deserialize_with = "string_to_u16")] + // memwidth: u16, #[serde(rename = "@varname", default)] var_name: String, } From 2784b450fc2fef88c0ab13689e6435bb6b39b998 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Tue, 17 Jun 2025 12:01:40 +0530 Subject: [PATCH 12/17] feat: fetching c_type representation from IntrinsicType's hashmap directly instead of constructing it. Further details: 1. moved "type_and_name_from_c" from Argument to Argument 2. removed "from_c" in Argument --- crates/intrinsic-test/src/arm/argument.rs | 12 +++++++++ crates/intrinsic-test/src/arm/json_parser.rs | 14 ++++++---- crates/intrinsic-test/src/arm/mod.rs | 1 + crates/intrinsic-test/src/arm/types.rs | 27 ++++++++------------ crates/intrinsic-test/src/common/argument.rs | 21 --------------- crates/intrinsic-test/src/x86/types.rs | 20 +++++++-------- 6 files changed, 41 insertions(+), 54 deletions(-) create mode 100644 crates/intrinsic-test/src/arm/argument.rs diff --git a/crates/intrinsic-test/src/arm/argument.rs b/crates/intrinsic-test/src/arm/argument.rs new file mode 100644 index 0000000000..db5501e5d2 --- /dev/null +++ b/crates/intrinsic-test/src/arm/argument.rs @@ -0,0 +1,12 @@ +use crate::arm::intrinsic::ArmIntrinsicType; +use crate::common::argument::Argument; + +impl Argument { + pub fn type_and_name_from_c(arg: &str) -> (&str, &str) { + let split_index = arg + .rfind([' ', '*']) + .expect("Couldn't split type and argname"); + + (arg[..split_index + 1].trim_end(), &arg[split_index + 1..]) + } +} diff --git a/crates/intrinsic-test/src/arm/json_parser.rs b/crates/intrinsic-test/src/arm/json_parser.rs index 856f2e6ec2..8b1a52535c 100644 --- a/crates/intrinsic-test/src/arm/json_parser.rs +++ b/crates/intrinsic-test/src/arm/json_parser.rs @@ -86,13 +86,17 @@ fn json_to_intrinsic( .into_iter() .enumerate() .map(|(i, arg)| { - let arg_name = Argument::::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 arg_prep: Option = metadata.and_then(|a| a.try_into().ok()); + let (type_name, arg_name) = Argument::::type_and_name_from_c(&arg); + let ty = ArmIntrinsicType::from_c(type_name) + .unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); + + let arg_prep = intr.args_prep.as_mut(); + let arg_prep = arg_prep.and_then(|a| a.remove(arg_name)); + let arg_prep: Option = arg_prep.and_then(|a| a.try_into().ok()); let constraint: Option = arg_prep.and_then(|a| a.try_into().ok()); - let mut arg = Argument::::from_c(i, &arg, constraint); + let mut arg = + Argument::::new(i, arg_name.to_string(), ty, constraint); arg.ty .set_metadata("target".to_string(), target.to_string()); diff --git a/crates/intrinsic-test/src/arm/mod.rs b/crates/intrinsic-test/src/arm/mod.rs index 6aaa49ff97..dfabc8e094 100644 --- a/crates/intrinsic-test/src/arm/mod.rs +++ b/crates/intrinsic-test/src/arm/mod.rs @@ -1,3 +1,4 @@ +mod argument; mod compile; mod config; mod intrinsic; diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 0fce7196f1..6182c44fce 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -6,22 +6,13 @@ use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, T impl IntrinsicTypeDefinition for ArmIntrinsicType { /// Gets a string containing the typename for this type in C format. + /// This assumes that the metadata hashmap contains this value at the + /// "type" key 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!("{const_prefix}{prefix}{bit_len}_t"), - (Some(simd), None) => format!("{prefix}{bit_len}x{simd}_t"), - (Some(simd), Some(vec)) => format!("{prefix}{bit_len}x{simd}x{vec}_t"), - (None, Some(_)) => todo!("{:#?}", self), // Likely an invalid case - } - } else { - todo!("{:#?}", self) - } + self.metadata + .get("type") + .expect("Failed to extract the C typename in Aarch!") + .to_string() } fn c_single_vector_type(&self) -> String { @@ -129,6 +120,8 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { fn from_c(s: &str) -> Result { const CONST_STR: &str = "const"; + let mut metadata: HashMap = HashMap::new(); + metadata.insert("type".to_string(), s.to_string()); if let Some(s) = s.strip_suffix('*') { let (s, constant) = match s.trim().strip_suffix(CONST_STR) { Some(stripped) => (stripped, true), @@ -176,7 +169,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { bit_len: Some(bit_len), simd_len, vec_len, - metadata: HashMap::new(), + metadata, })) } else { let kind = start.parse::()?; @@ -192,7 +185,7 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { bit_len, simd_len: None, vec_len: None, - metadata: HashMap::new(), + metadata, })) } } diff --git a/crates/intrinsic-test/src/common/argument.rs b/crates/intrinsic-test/src/common/argument.rs index f7f46f8925..b7e48eb3f4 100644 --- a/crates/intrinsic-test/src/common/argument.rs +++ b/crates/intrinsic-test/src/common/argument.rs @@ -45,14 +45,6 @@ where self.constraint.is_some() } - pub fn type_and_name_from_c(arg: &str) -> (&str, &str) { - let split_index = arg - .rfind([' ', '*']) - .expect("Couldn't split type and argname"); - - (arg[..split_index + 1].trim_end(), &arg[split_index + 1..]) - } - /// 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() { @@ -71,19 +63,6 @@ where } } - pub fn from_c(pos: usize, arg: &str, constraint: Option) -> Argument { - let (ty, var_name) = Self::type_and_name_from_c(arg); - - let ty = T::from_c(ty).unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); - - Argument { - pos, - name: String::from(var_name), - ty: ty, - constraint, - } - } - fn as_call_param_c(&self) -> String { self.ty.as_call_param_c(&self.name) } diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index c8a0c1f38b..d5678bf866 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -8,17 +8,13 @@ use crate::common::cli::Language; use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; impl IntrinsicTypeDefinition for X86IntrinsicType { - /// Gets a string containing the typename for this type in C format. + /// Gets a string containing the type in C format. + /// This function assumes that this value is present in the metadata hashmap. fn c_type(&self) -> String { - let part_0 = if self.constant { "const" } else { "" }; - let part_1 = match self.kind { - TypeKind::Int(false) => "unsigned int", - TypeKind::Char(false) => "unsigned char", - _ => self.kind.c_prefix(), - }; - let part_2 = if self.ptr { "*" } else { "" }; - - String::from(vec![part_0, part_1, part_2].join(" ").trim()) + self.metadata + .get("type") + .expect("Failed to extract the C typename in X86!") + .to_string() } fn c_single_vector_type(&self) -> String { @@ -41,6 +37,8 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { fn from_c(s: &str) -> Result { let mut s_copy = s.to_string(); + let mut metadata: HashMap = HashMap::new(); + metadata.insert("type".to_string(), s.to_string()); s_copy = s_copy .replace("*", "") .replace("_", "") @@ -80,7 +78,7 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { bit_len: None, simd_len: None, vec_len: None, - metadata: HashMap::new(), + metadata, })) } } From d0f2d7838be2c29854d62ecaabaa04493fd67082 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Thu, 19 Jun 2025 12:02:03 +0530 Subject: [PATCH 13/17] feat: changed from TypeKind::Int(bool) to TypeKind::Int(Sign) for more clarity --- crates/intrinsic-test/src/arm/intrinsic.rs | 7 +-- crates/intrinsic-test/src/arm/types.rs | 14 +++--- .../src/common/intrinsic_helpers.rs | 43 +++++++++++-------- crates/intrinsic-test/src/x86/config.rs | 2 +- crates/intrinsic-test/src/x86/types.rs | 7 +-- crates/intrinsic-test/src/x86/xml_parser.rs | 10 ++--- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/crates/intrinsic-test/src/arm/intrinsic.rs b/crates/intrinsic-test/src/arm/intrinsic.rs index 8ec558ac11..16572b2c03 100644 --- a/crates/intrinsic-test/src/arm/intrinsic.rs +++ b/crates/intrinsic-test/src/arm/intrinsic.rs @@ -1,7 +1,7 @@ use crate::common::argument::ArgumentList; use crate::common::indentation::Indentation; use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; -use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, TypeKind}; use std::ops::{Deref, DerefMut}; #[derive(Debug, Clone, PartialEq)] @@ -79,8 +79,9 @@ impl IntrinsicDefinition for Intrinsic { 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(true) => format!("int{}_t", self.results().inner_size()), - TypeKind::Int(false) => format!("uint{}_t", self.results().inner_size()), + TypeKind::Int(Sign::Signed) => format!("int{}_t", self.results().inner_size()), + TypeKind::Int(Sign::Unsigned) => + format!("uint{}_t", self.results().inner_size()), TypeKind::Poly => format!("poly{}_t", self.results().inner_size()), ty => todo!("print_result_c - Unknown type: {:#?}", ty), }, diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 6182c44fce..28f6310060 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use super::intrinsic::ArmIntrinsicType; use crate::common::cli::Language; -use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, TypeKind}; impl IntrinsicTypeDefinition for ArmIntrinsicType { /// Gets a string containing the typename for this type in C format. @@ -70,8 +70,8 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { format!( "vld{len}{quad}_{type}{size}", type = match k { - TypeKind::Int(false) => "u", - TypeKind::Int(true) => "s", + TypeKind::Int(Sign::Unsigned) => "u", + TypeKind::Int(Sign::Signed) => "s", TypeKind::Float => "f", // The ACLE doesn't support 64-bit polynomial loads on Armv7 // if armv7 and bl == 64, use "s", else "p" @@ -104,8 +104,8 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { format!( "vget{quad}_lane_{type}{size}", type = match k { - TypeKind::Int(false) => "u", - TypeKind::Int(true) => "s", + TypeKind::Int(Sign::Unsigned) => "u", + TypeKind::Int(Sign::Signed) => "s", TypeKind::Float => "f", TypeKind::Poly => "p", x => todo!("get_load_function TypeKind: {:#?}", x), @@ -129,6 +129,10 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { }; let s = s.trim_end(); let temp_return = ArmIntrinsicType::from_c(s); + + // We are not adding the metadata hashmap here, since + // it is the return of a recursive call and the + // inner call would handle it. temp_return.and_then(|mut op| { op.ptr = true; op.ptr_constant = constant; diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index e830d2258a..ffb1a1c6bd 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -9,14 +9,20 @@ use super::cli::Language; use super::indentation::Indentation; use super::values::value_for_array; +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum Sign { + Signed, + Unsigned, +} + #[derive(Debug, PartialEq, Copy, Clone)] pub enum TypeKind { BFloat, Float, // if signed, then the inner value is true - Int(bool), - Char(bool), + Int(Sign), + Char(Sign), Poly, Void, Mask, @@ -29,10 +35,12 @@ impl FromStr for TypeKind { match s { "bfloat" | "BF16" => Ok(Self::BFloat), "float" | "double" | "FP16" | "FP32" | "FP64" => Ok(Self::Float), - "int" | "long" | "short" | "SI8" | "SI16" | "SI32" | "SI64" => Ok(Self::Int(true)), + "int" | "long" | "short" | "SI8" | "SI16" | "SI32" | "SI64" => { + Ok(Self::Int(Sign::Signed)) + } "poly" => Ok(Self::Poly), - "char" => Ok(Self::Char(true)), - "uint" | "unsigned" | "UI8" | "UI16" | "UI32" | "UI64" => Ok(Self::Int(false)), + "char" => Ok(Self::Char(Sign::Signed)), + "uint" | "unsigned" | "UI8" | "UI16" | "UI32" | "UI64" => Ok(Self::Int(Sign::Unsigned)), "void" => Ok(Self::Void), "MASK" => Ok(Self::Mask), _ => Err(format!("Impossible to parse argument kind {s}")), @@ -48,12 +56,12 @@ impl fmt::Display for TypeKind { match self { Self::BFloat => "bfloat", Self::Float => "float", - Self::Int(true) => "int", - Self::Int(false) => "uint", + Self::Int(Sign::Signed) => "int", + Self::Int(Sign::Unsigned) => "uint", Self::Poly => "poly", Self::Void => "void", - Self::Char(true) => "char", - Self::Char(false) => "unsigned char", + Self::Char(Sign::Signed) => "char", + Self::Char(Sign::Unsigned) => "unsigned char", Self::Mask => "mask", } ) @@ -65,10 +73,10 @@ impl TypeKind { pub fn c_prefix(&self) -> &str { match self { Self::Float => "float", - Self::Int(true) => "int", - Self::Int(false) => "uint", + Self::Int(Sign::Signed) => "int", + Self::Int(Sign::Unsigned) => "uint", Self::Poly => "poly", - Self::Char(true) => "char", + Self::Char(Sign::Signed) => "char", _ => unreachable!("Not used: {:#?}", self), } } @@ -77,8 +85,8 @@ impl TypeKind { pub fn rust_prefix(&self) -> &str { match self { Self::Float => "f", - Self::Int(true) => "i", - Self::Int(false) => "u", + Self::Int(Sign::Signed) => "i", + Self::Int(Sign::Unsigned) => "u", Self::Poly => "u", _ => unreachable!("Unused type kind: {:#?}", self), } @@ -180,8 +188,8 @@ impl IntrinsicType { bit_len: Some(8), .. } => match kind { - TypeKind::Int(true) => "(int)", - TypeKind::Int(false) => "(unsigned int)", + TypeKind::Int(Sign::Signed) => "(int)", + TypeKind::Int(Sign::Unsigned) => "(unsigned int)", TypeKind::Poly => "(unsigned int)(uint8_t)", _ => "", }, @@ -241,7 +249,8 @@ impl IntrinsicType { .format_with(",\n", |i, fmt| { let src = value_for_array(*bit_len, i); assert!(src == 0 || src.ilog2() < *bit_len); - if *kind == TypeKind::Int(true) && (src >> (*bit_len - 1)) != 0 { + 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; diff --git a/crates/intrinsic-test/src/x86/config.rs b/crates/intrinsic-test/src/x86/config.rs index c3eeb14f29..c7613e515a 100644 --- a/crates/intrinsic-test/src/x86/config.rs +++ b/crates/intrinsic-test/src/x86/config.rs @@ -2,7 +2,7 @@ pub fn build_notices(line_prefix: &str) -> String { format!( "\ {line_prefix}This is a transient test file, not intended for distribution. Some aspects of the -{line_prefix}test are derived from a JSON specification, published under the same license as the +{line_prefix}test are derived from an XML specification, published under the same license as the {line_prefix}`intrinsic-test` crate.\n " ) diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index d5678bf866..88d5f1097f 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -5,7 +5,8 @@ use itertools::Itertools; use super::intrinsic::X86IntrinsicType; use crate::common::cli::Language; -use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, TypeKind}; +use crate::x86::xml_parser::Parameter; impl IntrinsicTypeDefinition for X86IntrinsicType { /// Gets a string containing the type in C format. @@ -58,8 +59,8 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { let kind = if s.find("unsigned").is_some() { match kind { - TypeKind::Int(_) => TypeKind::Int(false), - TypeKind::Char(_) => TypeKind::Char(false), + TypeKind::Int(_) => TypeKind::Int(Sign::Unsigned), + TypeKind::Char(_) => TypeKind::Char(Sign::Unsigned), a => a, } } else { diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index ac55087d67..4ccd00f815 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -37,15 +37,15 @@ struct XMLIntrinsic { } #[derive(Deserialize)] -struct Parameter { +pub struct Parameter { #[serde(rename = "@type")] - type_data: String, + pub type_data: String, #[serde(rename = "@etype", default)] - etype: String, + pub etype: String, // #[serde(rename = "@memwidth", default, deserialize_with = "string_to_u16")] - // memwidth: u16, + // pub memwidth: u16, #[serde(rename = "@varname", default)] - var_name: String, + pub var_name: String, } pub fn get_xml_intrinsics( From 758d7ec36856af3956bde216d9b4038ba61b4d71 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Tue, 24 Jun 2025 11:29:24 +0530 Subject: [PATCH 14/17] Feat: setup load function for x86 intrinsics --- crates/intrinsic-test/src/x86/types.rs | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index 88d5f1097f..c825c29dbd 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -28,7 +28,32 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { /// Determines the load function for this type. fn get_load_function(&self, _language: Language) -> String { - todo!("get_load_function for X86IntrinsicType needs to be implemented!"); + if let Some(type_value) = self.metadata.get("type") { + if type_value.starts_with("__mmask") { + // no need of loads, since they work directly + // with hex constants + String::from("*") + } else if type_value.starts_with("__m") { + // the structure is like the follows: + // if "type" starts with __m{h/i/}, + // then use either _mm_set1_epi64, + // _mm256_set1_epi64 or _mm512_set1_epi64 + let type_val_filtered = type_value + .chars() + .filter(|c| c.is_numeric()) + .join("") + .replace("128", ""); + format!("_mm{type_val_filtered}_set1_epi64") + } else { + // if it is a pointer, then rely on type conversion + // If it is not any of the above type (__int, __bfloat16, unsigned short, etc) + // then typecast it. + format!("({type_value})") + } + // Look for edge cases (constexpr, literal, etc) + } else { + unimplemented!("the value for key 'type' is not present!"); + } } /// Determines the get lane function for this type. From 6e190b2d64b4d1c05eb6dcf14d0b1910ae8d7b2d Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Tue, 24 Jun 2025 12:49:05 +0530 Subject: [PATCH 15/17] feat: implemented c_single_vector_type and fixed logical errors in from_param of X86IntrinsicType --- crates/intrinsic-test/src/x86/types.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index c825c29dbd..05a8c05c8a 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::str::FromStr; use itertools::Itertools; +use regex::Regex; use super::intrinsic::X86IntrinsicType; use crate::common::cli::Language; @@ -19,7 +20,12 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { } fn c_single_vector_type(&self) -> String { - todo!("c_single_vector_type for X86IntrinsicType needs to be implemented!"); + // matches __m128, __m256 and similar types + let re = Regex::new(r"\__m\d+\").unwrap(); + match self.metadata.get("type") { + Some(type_data) if re.is_match(type_data) => type_data.to_string(), + _ => unreachable!("Shouldn't be called on this type"), + } } fn rust_type(&self) -> String { @@ -150,10 +156,10 @@ impl X86IntrinsicType { // then check the param.type and extract numeric part if there are double // underscores. divide this number with bit-len and set this as simd-len. - let mut type_processed = param.etype.clone(); + let mut type_processed = param.type_data.clone(); type_processed.retain(|c| c.is_numeric()); - ret.vec_len = match str::parse::(etype_processed.as_str()) { + ret.vec_len = match str::parse::(type_processed.as_str()) { // If bit_len is None, vec_len will be None. // Else vec_len will be (num_bits / bit_len). Ok(num_bits) => ret.bit_len.and(Some(num_bits / ret.bit_len.unwrap())), From e947072ed55eb70827ce0b8c561a233f9b5ddca3 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Fri, 4 Jul 2025 13:16:29 +0530 Subject: [PATCH 16/17] feat: added vector types to support intrinsics that does not represent a vector register as an array of fundamental types --- crates/intrinsic-test/src/arm/types.rs | 3 +++ crates/intrinsic-test/src/common/intrinsic_helpers.rs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/crates/intrinsic-test/src/arm/types.rs b/crates/intrinsic-test/src/arm/types.rs index 28f6310060..fbbadae2ca 100644 --- a/crates/intrinsic-test/src/arm/types.rs +++ b/crates/intrinsic-test/src/arm/types.rs @@ -12,6 +12,9 @@ impl IntrinsicTypeDefinition for ArmIntrinsicType { self.metadata .get("type") .expect("Failed to extract the C typename in Aarch!") + .replace("*", "") + .replace(" ", "") + .trim() .to_string() } diff --git a/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/crates/intrinsic-test/src/common/intrinsic_helpers.rs index ffb1a1c6bd..b10430f5d4 100644 --- a/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -26,6 +26,7 @@ pub enum TypeKind { Poly, Void, Mask, + Vector, } impl FromStr for TypeKind { @@ -43,6 +44,7 @@ impl FromStr for TypeKind { "uint" | "unsigned" | "UI8" | "UI16" | "UI32" | "UI64" => Ok(Self::Int(Sign::Unsigned)), "void" => Ok(Self::Void), "MASK" => Ok(Self::Mask), + "M64" | "M128" | "M256" | "M512" => Ok(Self::Vector), _ => Err(format!("Impossible to parse argument kind {s}")), } } @@ -63,6 +65,7 @@ impl fmt::Display for TypeKind { Self::Char(Sign::Signed) => "char", Self::Char(Sign::Unsigned) => "unsigned char", Self::Mask => "mask", + Self::Vector => "vector", } ) } @@ -84,10 +87,13 @@ impl TypeKind { /// Gets the rust prefix for the type kind i.e. i, u, f. pub fn rust_prefix(&self) -> &str { match self { + Self::BFloat => "bf", Self::Float => "f", Self::Int(Sign::Signed) => "i", Self::Int(Sign::Unsigned) => "u", Self::Poly => "u", + Self::Char(Sign::Unsigned) => "u", + Self::Char(Sign::Signed) => "i", _ => unreachable!("Unused type kind: {:#?}", self), } } From e57c4bf29b40e2db3e02ec1258f048276f8b864d Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Fri, 4 Jul 2025 13:17:47 +0530 Subject: [PATCH 17/17] feat: added memsize and rust_type implementation Notes: 1. rust_type deinition may need future work for accuracy --- crates/intrinsic-test/src/x86/types.rs | 93 ++++++++++++++++++--- crates/intrinsic-test/src/x86/xml_parser.rs | 22 ++--- 2 files changed, 93 insertions(+), 22 deletions(-) diff --git a/crates/intrinsic-test/src/x86/types.rs b/crates/intrinsic-test/src/x86/types.rs index 05a8c05c8a..936421cc06 100644 --- a/crates/intrinsic-test/src/x86/types.rs +++ b/crates/intrinsic-test/src/x86/types.rs @@ -23,13 +23,73 @@ impl IntrinsicTypeDefinition for X86IntrinsicType { // matches __m128, __m256 and similar types let re = Regex::new(r"\__m\d+\").unwrap(); match self.metadata.get("type") { - Some(type_data) if re.is_match(type_data) => type_data.to_string(), + Some(type_data) if re.is_match(type_data) => type_data.to_string(), _ => unreachable!("Shouldn't be called on this type"), } } fn rust_type(&self) -> String { - todo!("rust_type for X86IntrinsicType needs to be implemented!"); + // handling edge cases first + // the general handling is implemented below + if let Some(val) = self.metadata.get("type") { + match val.as_str() { + "__m128 const *" => { + return "&__m128".to_string(); + } + "__m128d const *" => { + return "&__m128d".to_string(); + } + "const void*" => { + return "&__m128d".to_string(); + } + _ => {} + } + } + + if self.kind() == TypeKind::Void && self.ptr { + // this has been handled by default settings in + // the from_param function of X86IntrinsicType + unreachable!() + } + + // general handling cases + let core_part = if self.kind() == TypeKind::Mask { + // all types of __mmask are handled here + format!("__mask{}", self.bit_len.unwrap()) + } else if self.simd_len.is_some() { + // all types of __m vector types are handled here + let re = Regex::new(r"\__m\d+[a-z]*").unwrap(); + let rust_type = self + .metadata + .get("type") + .map(|val| re.find(val).unwrap().as_str()); + rust_type.unwrap().to_string() + } else { + format!( + "{}{}", + self.kind.rust_prefix().to_string(), + self.bit_len.unwrap() + ) + }; + + // extracting "memsize" so that even vector types can be involved + let memwidth = self + .metadata + .get("memwidth") + .map(|n| str::parse::(n).unwrap()); + let prefix_part = if self.ptr && self.constant && self.bit_len.eq(&memwidth) { + "&" + } else if self.ptr && self.bit_len.eq(&memwidth) { + "&mut " + } else if self.ptr && self.constant { + "*const " + } else if self.ptr { + "*mut " + } else { + "" + }; + + return prefix_part.to_string() + core_part.as_str(); } /// Determines the load function for this type. @@ -124,6 +184,7 @@ impl X86IntrinsicType { // The assumption is that the parameter of type void may have param.type // as "__m128i", "__mmask8" and the like. ret.set_metadata("etype".to_string(), param.etype.clone()); + ret.set_metadata("memwidth".to_string(), param.memwidth.to_string()); if !param.etype.is_empty() { match TypeKind::from_str(param.etype.as_str()) { Ok(value) => { @@ -155,16 +216,26 @@ impl X86IntrinsicType { // then check the param.type and extract numeric part if there are double // underscores. divide this number with bit-len and set this as simd-len. + // Only __m types can have a simd-len. + if param.type_data.matches("__m").next().is_some() + && param.type_data.matches("__mmask").next().is_none() + { + let mut type_processed = param.type_data.clone(); + type_processed.retain(|c| c.is_numeric()); + ret.vec_len = match str::parse::(type_processed.as_str()) { + // If bit_len is None, vec_len will be None. + // Else vec_len will be (num_bits / bit_len). + Ok(num_bits) => ret.bit_len.and(Some(num_bits / ret.bit_len.unwrap())), + Err(_) => None, + }; + } - let mut type_processed = param.type_data.clone(); - type_processed.retain(|c| c.is_numeric()); - - ret.vec_len = match str::parse::(type_processed.as_str()) { - // If bit_len is None, vec_len will be None. - // Else vec_len will be (num_bits / bit_len). - Ok(num_bits) => ret.bit_len.and(Some(num_bits / ret.bit_len.unwrap())), - Err(_) => None, - }; + // default settings for "void *" parameters + // often used by intrinsics to denote memory address or so. + if ret.kind == TypeKind::Void && ret.ptr { + ret.kind = TypeKind::Int(Sign::Unsigned); + ret.bit_len = Some(8); + } // if param.etype == IMM, then it is a constant. // else it stays unchanged. diff --git a/crates/intrinsic-test/src/x86/xml_parser.rs b/crates/intrinsic-test/src/x86/xml_parser.rs index 4ccd00f815..a532e94ce9 100644 --- a/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/crates/intrinsic-test/src/x86/xml_parser.rs @@ -2,19 +2,19 @@ use crate::common::argument::{Argument, ArgumentList}; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::TypeKind; -use serde::Deserialize; +use serde::{Deserialize, Deserializer}; use std::path::Path; use super::intrinsic::X86IntrinsicType; -// Custom deserializer function to convert strings to u16 -// fn string_to_u16<'de, D>(deserializer: D) -> Result -// where -// D: Deserializer<'de>, -// { -// let s = String::deserialize(deserializer)?; -// return Ok(s.as_str().parse::().unwrap_or(0u16)); -// } +// Custom deserializer function to convert strings to u32 +fn string_to_u32<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + return s.as_str().parse::().or(Ok(0u16)); +} #[derive(Deserialize)] struct Data { @@ -42,8 +42,8 @@ pub struct Parameter { pub type_data: String, #[serde(rename = "@etype", default)] pub etype: String, - // #[serde(rename = "@memwidth", default, deserialize_with = "string_to_u16")] - // pub memwidth: u16, + #[serde(rename = "@memwidth", default, deserialize_with = "string_to_u32")] + pub memwidth: u32, #[serde(rename = "@varname", default)] pub var_name: String, }