From e86b274e6cfcbd13893fc9589fb5928bdf025f4b Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 4 Aug 2025 12:55:35 +0530 Subject: [PATCH 1/8] feat: added a skeletal structure for loongarch in `intrinsic-test` --- crates/intrinsic-test/Cargo.toml | 1 + .../intrinsic-test/src/loongarch/intrinsic.rs | 43 +++++++++ crates/intrinsic-test/src/loongarch/mod.rs | 50 ++++++++++ crates/intrinsic-test/src/loongarch/types.rs | 93 +++++++++++++++++++ crates/intrinsic-test/src/main.rs | 4 + 5 files changed, 191 insertions(+) create mode 100644 crates/intrinsic-test/src/loongarch/intrinsic.rs create mode 100644 crates/intrinsic-test/src/loongarch/mod.rs create mode 100644 crates/intrinsic-test/src/loongarch/types.rs diff --git a/crates/intrinsic-test/Cargo.toml b/crates/intrinsic-test/Cargo.toml index fbbf90e140..b59e216678 100644 --- a/crates/intrinsic-test/Cargo.toml +++ b/crates/intrinsic-test/Cargo.toml @@ -19,3 +19,4 @@ pretty_env_logger = "0.5.0" rayon = "1.5.0" diff = "0.1.12" itertools = "0.14.0" +regex = "1.11.1" diff --git a/crates/intrinsic-test/src/loongarch/intrinsic.rs b/crates/intrinsic-test/src/loongarch/intrinsic.rs new file mode 100644 index 0000000000..0b17575f2d --- /dev/null +++ b/crates/intrinsic-test/src/loongarch/intrinsic.rs @@ -0,0 +1,43 @@ +use crate::common::argument::ArgumentList; +use crate::common::indentation::Indentation; +use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition}; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, Sign, TypeKind}; +use std::ops::{Deref, DerefMut}; + +#[derive(Debug, Clone, PartialEq)] +pub struct LoongArchIntrinsicType(pub IntrinsicType); + +impl Deref for LoongArchIntrinsicType { + type Target = IntrinsicType; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for LoongArchIntrinsicType { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl IntrinsicDefinition for Intrinsic { + fn arguments(&self) -> ArgumentList { + self.arguments.clone() + } + + fn results(&self) -> LoongArchIntrinsicType { + 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 { + unimplemented!("print_result_c of IntrinsicDefinition is not defined!") + } +} diff --git a/crates/intrinsic-test/src/loongarch/mod.rs b/crates/intrinsic-test/src/loongarch/mod.rs new file mode 100644 index 0000000000..e943bbae17 --- /dev/null +++ b/crates/intrinsic-test/src/loongarch/mod.rs @@ -0,0 +1,50 @@ +mod intrinsic; +mod types; + +use std::fs::{self, File}; + +use rayon::prelude::*; + +use crate::common::SupportedArchitectureTest; +use crate::common::cli::ProcessedCli; +use crate::common::compare::compare_outputs; + +use crate::common::intrinsic::Intrinsic; +use intrinsic::LoongArchIntrinsicType; + +pub struct LoongArchArchitectureTest { + intrinsics: Vec>, + cli_options: ProcessedCli, +} + +impl SupportedArchitectureTest for LoongArchArchitectureTest { + fn create(cli_options: ProcessedCli) -> Box { + unimplemented!("create of LoongArchIntrinsicType is not defined!") + } + + fn build_c_file(&self) -> bool { + unimplemented!("build_c_file of LoongArchIntrinsicType is not defined!") + } + + fn build_rust_file(&self) -> bool { + unimplemented!("build_rust_file of LoongArchIntrinsicType is not defined!") + } + + fn compare_outputs(&self) -> bool { + if self.cli_options.toolchain.is_some() { + let intrinsics_name_list = self + .intrinsics + .iter() + .map(|i| i.name.clone()) + .collect::>(); + + compare_outputs( + &intrinsics_name_list, + &self.cli_options.runner, + &self.cli_options.target, + ) + } else { + true + } + } +} diff --git a/crates/intrinsic-test/src/loongarch/types.rs b/crates/intrinsic-test/src/loongarch/types.rs new file mode 100644 index 0000000000..cf2b429963 --- /dev/null +++ b/crates/intrinsic-test/src/loongarch/types.rs @@ -0,0 +1,93 @@ +use super::intrinsic::LoongArchIntrinsicType; +use crate::common::cli::Language; +use crate::common::intrinsic_helpers::IntrinsicTypeDefinition; + +impl IntrinsicTypeDefinition for LoongArchIntrinsicType { + /// 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 { + unimplemented!("c_type for LoongArchIntrinsicType is not implemented!") + } + + fn c_single_vector_type(&self) -> String { + unimplemented!("c_single_vector_type for LoongArchIntrinsicType is not implemented!") + } + + // fn rust_type(&self) -> String { + // // 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. + fn get_load_function(&self, _language: Language) -> String { + unimplemented!("get_load_function for LoongArchIntrinsicType is not implemented!") + } + + /// Determines the get lane function for this type. + fn get_lane_function(&self) -> String { + todo!("get_lane_function for LoongArchIntrinsicType needs to be implemented!"); + } + + fn from_c(s: &str, target: &str) -> Result { + todo!("from_c for LoongArchIntrinsicType needs to be implemented!"); + } +} diff --git a/crates/intrinsic-test/src/main.rs b/crates/intrinsic-test/src/main.rs index 538f317a29..a645d2f409 100644 --- a/crates/intrinsic-test/src/main.rs +++ b/crates/intrinsic-test/src/main.rs @@ -3,8 +3,11 @@ extern crate log; mod arm; mod common; +mod loongarch; use arm::ArmArchitectureTest; +use loongarch::LoongArchArchitectureTest; + use common::SupportedArchitectureTest; use common::cli::{Cli, ProcessedCli}; @@ -21,6 +24,7 @@ fn main() { Some(ArmArchitectureTest::create(processed_cli_options)) } + "loongarch64-unknown-linux-gnu" => Some(LoongArchArchitectureTest::create(processed_cli_options)), _ => None, }; From ac7200da31414cacdcbbb9bef160becc8851dcbf Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 11 Aug 2025 13:51:52 +0530 Subject: [PATCH 2/8] chore: restructure LoongArchIntrinsicType struct --- .../intrinsic-test/src/loongarch/intrinsic.rs | 8 ++- crates/intrinsic-test/src/loongarch/types.rs | 70 +------------------ 2 files changed, 7 insertions(+), 71 deletions(-) diff --git a/crates/intrinsic-test/src/loongarch/intrinsic.rs b/crates/intrinsic-test/src/loongarch/intrinsic.rs index 0b17575f2d..33ba2dd9f8 100644 --- a/crates/intrinsic-test/src/loongarch/intrinsic.rs +++ b/crates/intrinsic-test/src/loongarch/intrinsic.rs @@ -5,19 +5,21 @@ use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, S use std::ops::{Deref, DerefMut}; #[derive(Debug, Clone, PartialEq)] -pub struct LoongArchIntrinsicType(pub IntrinsicType); +pub struct LoongArchIntrinsicType { + pub data: IntrinsicType, +} impl Deref for LoongArchIntrinsicType { type Target = IntrinsicType; fn deref(&self) -> &Self::Target { - &self.0 + &self.data } } impl DerefMut for LoongArchIntrinsicType { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 + &mut self.data } } diff --git a/crates/intrinsic-test/src/loongarch/types.rs b/crates/intrinsic-test/src/loongarch/types.rs index cf2b429963..ca4afbd233 100644 --- a/crates/intrinsic-test/src/loongarch/types.rs +++ b/crates/intrinsic-test/src/loongarch/types.rs @@ -13,70 +13,6 @@ impl IntrinsicTypeDefinition for LoongArchIntrinsicType { unimplemented!("c_single_vector_type for LoongArchIntrinsicType is not implemented!") } - // fn rust_type(&self) -> String { - // // 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. fn get_load_function(&self, _language: Language) -> String { unimplemented!("get_load_function for LoongArchIntrinsicType is not implemented!") @@ -86,8 +22,6 @@ impl IntrinsicTypeDefinition for LoongArchIntrinsicType { fn get_lane_function(&self) -> String { todo!("get_lane_function for LoongArchIntrinsicType needs to be implemented!"); } - - fn from_c(s: &str, target: &str) -> Result { - todo!("from_c for LoongArchIntrinsicType needs to be implemented!"); - } } + +impl LoongArchIntrinsicType From b3366455114f7896e36ff0e01f858ddd904058ed Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 11 Aug 2025 13:52:34 +0530 Subject: [PATCH 3/8] feat: adding a parser for LoongArch spec sheets --- crates/intrinsic-test/src/loongarch/mod.rs | 1 + crates/intrinsic-test/src/loongarch/parser.rs | 177 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 crates/intrinsic-test/src/loongarch/parser.rs diff --git a/crates/intrinsic-test/src/loongarch/mod.rs b/crates/intrinsic-test/src/loongarch/mod.rs index e943bbae17..6220d04ce8 100644 --- a/crates/intrinsic-test/src/loongarch/mod.rs +++ b/crates/intrinsic-test/src/loongarch/mod.rs @@ -1,4 +1,5 @@ mod intrinsic; +mod parser; mod types; use std::fs::{self, File}; diff --git a/crates/intrinsic-test/src/loongarch/parser.rs b/crates/intrinsic-test/src/loongarch/parser.rs new file mode 100644 index 0000000000..267dfe2389 --- /dev/null +++ b/crates/intrinsic-test/src/loongarch/parser.rs @@ -0,0 +1,177 @@ +use std::fs::{self, File}; +use std::io::{BufRead, BufReader}; +use std::path::Path; + +use crate::common::intrinsic::Intrinsic; +use crate::common::intrinsic_helpers::IntrinsicType; +use crate::loongarch::intrinsic::LoongArchIntrinsicType; + +pub fn get_loongson_intrinsics( + path: &Path, + target: &str +) -> Result>, Box> { + let f = File::open(path).unwrap_or_else(|_| panic!("Failed to open {}", path.display())); + let f = BufReader::new(f); + + let mut para_num; + let mut current_name: Option = None; + let mut asm_fmts: Vec = Vec::new(); + let mut impl_function_str = String::new(); + let mut call_function_str = String::new(); + let mut out = String::new(); + + let mut intrinsics: Vec> = Vec::new(); + for line in f.lines() { + let line = line.unwrap(); + if line.is_empty() { + continue; + } + if let Some(name) = line.strip_prefix("name = ") { + current_name = Some(String::from(name)); + } else if line.starts_with("asm-fmts = ") { + asm_fmts = line[10..] + .split(',') + .map(|v| v.trim().to_string()) + .collect(); + } else if line.starts_with("data-types = ") { + let current_name = current_name.clone().unwrap(); + let data_types: Vec<&str> = line + .get(12..) + .unwrap() + .split(',') + .map(|e| e.trim()) + .collect(); + let in_t; + let out_t; + if data_types.len() == 2 { + in_t = [data_types[1], "NULL", "NULL", "NULL"]; + out_t = data_types[0]; + para_num = 1; + } else if data_types.len() == 3 { + in_t = [data_types[1], data_types[2], "NULL", "NULL"]; + out_t = data_types[0]; + para_num = 2; + } else if data_types.len() == 4 { + in_t = [data_types[1], data_types[2], data_types[3], "NULL"]; + out_t = data_types[0]; + para_num = 3; + } else if data_types.len() == 5 { + in_t = [data_types[1], data_types[2], data_types[3], data_types[4]]; + out_t = data_types[0]; + para_num = 4; + } else { + panic!("DEBUG: line: {0} len: {1}", line, data_types.len()); + } + + // TODO: implement the below functions + // create list of intrinsics + let intrinsic = gen_intrinsic(current_name.as_str(), asm_fmts.as_slice(), &in_t, out_t, para_num, target); + if intrinsic.is_ok() { + intrinsics.push(intrinsic.unwrap()); + } + } + }; + return Ok(intrinsics) +} + +fn gen_intrinsic( + current_name: &str, + asm_fmts: &[String], + in_t: &[&str; 4], + out_t: &str, + para_num: i32, + target: &str, +) -> Result, Box> { + let type_to_ct = |t: &str| -> &str { + match t { + "V16QI" => "union v16qi", + "V32QI" => "union v32qi", + "V8HI" => "union v8hi", + "V16HI" => "union v16hi", + "V4SI" => "union v4si", + "V8SI" => "union v8si", + "V2DI" => "union v2di", + "V4DI" => "union v4di", + "UV16QI" => "union uv16qi", + "UV32QI" => "union uv32qi", + "UV8HI" => "union uv8hi", + "UV16HI" => "union uv16hi", + "UV4SI" => "union uv4si", + "UV8SI" => "union uv8si", + "UV2DI" => "union uv2di", + "UV4DI" => "union uv4di", + "SI" => "int32_t", + "DI" => "int64_t", + "USI" => "uint32_t", + "UDI" => "uint64_t", + "V4SF" => "union v4sf", + "V8SF" => "union v8sf", + "V2DF" => "union v2df", + "V4DF" => "union v4df", + "UQI" => "uint32_t", + "QI" => "int32_t", + "CVPOINTER" => "void*", + "HI" => "int32_t", + _ => panic!("unknown type: {t}"), + } + }; + let type_to_size = |v: &str, t: &str| -> u32 { + let n = if v.starts_with('_') { + v.get(1..).unwrap() + } else { + v + }; + match t { + "A16QI" => 8, + "AM16QI" => 8, + "V16QI" => 8, + "V32QI" => 8, + "A32QI" => 8, + "AM32QI" => 8, + "V8HI" => 16, + "V16HI" => 16, + "V4SI" => 32, + "V8SI" => 32, + "V2DI" => 64, + "V4DI" => 64, + "UV16QI" => 8, + "UV32QI" => 8, + "UV8HI" => 16, + "UV16HI" => 16, + "UV4SI" => 32, + "UV8SI" => 32, + "UV2DI" => 64, + "UV4DI" => 64, + "V4SF" => 32, + "V8SF" => 32, + "V2DF" => 64, + "V4DF" => 64, + "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "CVPOINTER" | "HI" => 0, + _ => panic!("unknown type: {t}"), + } + }; + let type_to_rp = |t: &str| -> Option { + match t { + "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "HI" | => None, + "V32QI" | "V16HI" | "V8SI" | "V4DI" | "UV32QI" | "UV16HI" | "UV8SI" | "UV4DI" + | "V8SF" | "V4DF" => Some(4) + _ => Some(2), + } + }; + let type_to_imm = |t| -> i8 { + match t { + 'b' => 4, + 'h' => 3, + 'w' => 2, + 'd' => 1, + _ => panic!("unsupported type"), + } + }; + + Ok(Intrinsic { + name: current_name.to_string(), + arguments, + results: results, + arch_tags: vec![target.to_string()], + }) +} \ No newline at end of file From c0e8a27b378355a8e94f95cb7b3f3036d465c87d Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 11 Aug 2025 20:02:32 +0530 Subject: [PATCH 4/8] feat: create parser for LoongArch intrinsics --- crates/intrinsic-test/src/loongarch/mod.rs | 20 +- crates/intrinsic-test/src/loongarch/parser.rs | 194 +++++++----------- crates/intrinsic-test/src/loongarch/types.rs | 56 ++++- 3 files changed, 149 insertions(+), 121 deletions(-) diff --git a/crates/intrinsic-test/src/loongarch/mod.rs b/crates/intrinsic-test/src/loongarch/mod.rs index 6220d04ce8..61b97d5e3c 100644 --- a/crates/intrinsic-test/src/loongarch/mod.rs +++ b/crates/intrinsic-test/src/loongarch/mod.rs @@ -6,11 +6,13 @@ use std::fs::{self, File}; use rayon::prelude::*; +use crate::common::intrinsic_helpers::TypeKind; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; use crate::common::intrinsic::Intrinsic; +use crate::loongarch::parser::get_loongson_intrinsics; use intrinsic::LoongArchIntrinsicType; pub struct LoongArchArchitectureTest { @@ -20,7 +22,23 @@ pub struct LoongArchArchitectureTest { impl SupportedArchitectureTest for LoongArchArchitectureTest { fn create(cli_options: ProcessedCli) -> Box { - unimplemented!("create of LoongArchIntrinsicType is not defined!") + let mut intrinsics = get_loongson_intrinsics(&cli_options.filename, &cli_options.target) + .expect("Error parsing input file"); + + intrinsics.sort_by(|a, b| a.name.cmp(&b.name)); + + let mut intrinsics = intrinsics + .into_iter() + .filter(|i| i.results.kind() != TypeKind::Void) + .filter(|i| !i.arguments.iter().any(|a| a.is_ptr())) + .filter(|i| !cli_options.skip.contains(&i.name)) + .collect::>(); + intrinsics.dedup(); + + Box::new(Self { + intrinsics, + cli_options, + }) } fn build_c_file(&self) -> bool { diff --git a/crates/intrinsic-test/src/loongarch/parser.rs b/crates/intrinsic-test/src/loongarch/parser.rs index 267dfe2389..6f0603928b 100644 --- a/crates/intrinsic-test/src/loongarch/parser.rs +++ b/crates/intrinsic-test/src/loongarch/parser.rs @@ -1,9 +1,9 @@ -use std::fs::{self, File}; +use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::Path; +use crate::common::argument::{Argument, ArgumentList}; use crate::common::intrinsic::Intrinsic; -use crate::common::intrinsic_helpers::IntrinsicType; use crate::loongarch::intrinsic::LoongArchIntrinsicType; pub fn get_loongson_intrinsics( @@ -13,12 +13,8 @@ pub fn get_loongson_intrinsics( let f = File::open(path).unwrap_or_else(|_| panic!("Failed to open {}", path.display())); let f = BufReader::new(f); - let mut para_num; let mut current_name: Option = None; let mut asm_fmts: Vec = Vec::new(); - let mut impl_function_str = String::new(); - let mut call_function_str = String::new(); - let mut out = String::new(); let mut intrinsics: Vec> = Vec::new(); for line in f.lines() { @@ -35,37 +31,25 @@ pub fn get_loongson_intrinsics( .collect(); } else if line.starts_with("data-types = ") { let current_name = current_name.clone().unwrap(); - let data_types: Vec<&str> = line + let mut data_types: Vec = line .get(12..) .unwrap() .split(',') - .map(|e| e.trim()) + .map(|e| e.trim().to_string()) .collect(); - let in_t; - let out_t; - if data_types.len() == 2 { - in_t = [data_types[1], "NULL", "NULL", "NULL"]; - out_t = data_types[0]; - para_num = 1; - } else if data_types.len() == 3 { - in_t = [data_types[1], data_types[2], "NULL", "NULL"]; - out_t = data_types[0]; - para_num = 2; - } else if data_types.len() == 4 { - in_t = [data_types[1], data_types[2], data_types[3], "NULL"]; - out_t = data_types[0]; - para_num = 3; - } else if data_types.len() == 5 { - in_t = [data_types[1], data_types[2], data_types[3], data_types[4]]; - out_t = data_types[0]; - para_num = 4; - } else { + let arguments; + let return_type; + let data_types_len = data_types.len(); + if data_types_len > 0 && data_types_len < 6 { + arguments = data_types.split_off(1); + + // Being explicit here with the variable name + return_type = data_types.get(0).unwrap(); + } else { panic!("DEBUG: line: {0} len: {1}", line, data_types.len()); } - // TODO: implement the below functions - // create list of intrinsics - let intrinsic = gen_intrinsic(current_name.as_str(), asm_fmts.as_slice(), &in_t, out_t, para_num, target); + let intrinsic = gen_intrinsic(current_name.as_str(), asm_fmts.clone(), arguments, return_type, target); if intrinsic.is_ok() { intrinsics.push(intrinsic.unwrap()); } @@ -76,98 +60,72 @@ pub fn get_loongson_intrinsics( fn gen_intrinsic( current_name: &str, - asm_fmts: &[String], - in_t: &[&str; 4], - out_t: &str, - para_num: i32, + asm_fmts: Vec, + args: Vec, + return_type: &String, target: &str, ) -> Result, Box> { - let type_to_ct = |t: &str| -> &str { - match t { - "V16QI" => "union v16qi", - "V32QI" => "union v32qi", - "V8HI" => "union v8hi", - "V16HI" => "union v16hi", - "V4SI" => "union v4si", - "V8SI" => "union v8si", - "V2DI" => "union v2di", - "V4DI" => "union v4di", - "UV16QI" => "union uv16qi", - "UV32QI" => "union uv32qi", - "UV8HI" => "union uv8hi", - "UV16HI" => "union uv16hi", - "UV4SI" => "union uv4si", - "UV8SI" => "union uv8si", - "UV2DI" => "union uv2di", - "UV4DI" => "union uv4di", - "SI" => "int32_t", - "DI" => "int64_t", - "USI" => "uint32_t", - "UDI" => "uint64_t", - "V4SF" => "union v4sf", - "V8SF" => "union v8sf", - "V2DF" => "union v2df", - "V4DF" => "union v4df", - "UQI" => "uint32_t", - "QI" => "int32_t", - "CVPOINTER" => "void*", - "HI" => "int32_t", - _ => panic!("unknown type: {t}"), - } - }; - let type_to_size = |v: &str, t: &str| -> u32 { - let n = if v.starts_with('_') { - v.get(1..).unwrap() + let para_num = args.len(); + let mut arguments = asm_fmts + .iter() + .zip(args.iter()) + .enumerate() + .map(|(i, (asm_fmt, arg_type))| { + let ty = LoongArchIntrinsicType::from_values(asm_fmt, arg_type).unwrap(); + let arg = Argument::::new(i, format!("_{i}_{}", arg_type), ty, None); + return arg; + }) + .collect::>>(); + + if para_num == 1 && args[0] == "HI" { + match asm_fmts[1].as_str() { + "si13" | "i13" => arguments[0].ty.constant = true, + "si10" => arguments[0].ty.constant = true, + _ => panic!("unsupported assembly format: {:?}", asm_fmts), + }; + } else if para_num == 2 && (args[1] == "UQI" || args[1] == "USI") { + if asm_fmts[2].starts_with("ui") { + arguments[1].ty.constant = true; } else { - v + panic!("unsupported assembly format: {:?}", asm_fmts); }; - match t { - "A16QI" => 8, - "AM16QI" => 8, - "V16QI" => 8, - "V32QI" => 8, - "A32QI" => 8, - "AM32QI" => 8, - "V8HI" => 16, - "V16HI" => 16, - "V4SI" => 32, - "V8SI" => 32, - "V2DI" => 64, - "V4DI" => 64, - "UV16QI" => 8, - "UV32QI" => 8, - "UV8HI" => 16, - "UV16HI" => 16, - "UV4SI" => 32, - "UV8SI" => 32, - "UV2DI" => 64, - "UV4DI" => 64, - "V4SF" => 32, - "V8SF" => 32, - "V2DF" => 64, - "V4DF" => 64, - "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "CVPOINTER" | "HI" => 0, - _ => panic!("unknown type: {t}"), - } - }; - let type_to_rp = |t: &str| -> Option { - match t { - "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "HI" | => None, - "V32QI" | "V16HI" | "V8SI" | "V4DI" | "UV32QI" | "UV16HI" | "UV8SI" | "UV4DI" - | "V8SF" | "V4DF" => Some(4) - _ => Some(2), - } - }; - let type_to_imm = |t| -> i8 { - match t { - 'b' => 4, - 'h' => 3, - 'w' => 2, - 'd' => 1, - _ => panic!("unsupported type"), - } - }; - + } else if para_num == 2 && args[1] == "QI" { + if asm_fmts[2].starts_with("si") { + arguments[1].ty.constant = true; + } else { + panic!("unsupported assembly format: {:?}", asm_fmts); + }; + } else if para_num == 2 && args[0] == "CVPOINTER" && args[1] == "SI" { + if asm_fmts[2].starts_with("si") { + arguments[1].ty.constant = true; + } else { + panic!("unsupported assembly format: {:?}", asm_fmts); + }; + } else if para_num == 3 && (args[2] == "USI" || args[2] == "UQI") { + if asm_fmts[2].starts_with("ui") { + arguments[2].ty.constant = true; + } else { + panic!("unsupported assembly format: {:?}", asm_fmts); + }; + } else if para_num == 3 && args[1] == "CVPOINTER" && args[2] == "SI" { + match asm_fmts[2].as_str() { + "si12" => arguments[2].ty.constant = true, + _ => panic!("unsupported assembly format: {:?}", asm_fmts), + }; + } else if para_num == 4 { + match (asm_fmts[3].as_str(), current_name.chars().last().unwrap()) { + ("si8", t) => { + arguments[2].ty.constant = true; + arguments[3].ty.constant = true; + }, + (_, _) => panic!( + "unsupported assembly format: {:?} for {}", + asm_fmts, current_name + ), + }; + } + let results = LoongArchIntrinsicType::from_values(return_type, &asm_fmts[0])?; + let arguments = ArgumentList:: { args: arguments }; Ok(Intrinsic { name: current_name.to_string(), arguments, diff --git a/crates/intrinsic-test/src/loongarch/types.rs b/crates/intrinsic-test/src/loongarch/types.rs index ca4afbd233..0d5fc7a053 100644 --- a/crates/intrinsic-test/src/loongarch/types.rs +++ b/crates/intrinsic-test/src/loongarch/types.rs @@ -1,6 +1,6 @@ use super::intrinsic::LoongArchIntrinsicType; use crate::common::cli::Language; -use crate::common::intrinsic_helpers::IntrinsicTypeDefinition; +use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; impl IntrinsicTypeDefinition for LoongArchIntrinsicType { /// Gets a string containing the type in C format. @@ -24,4 +24,56 @@ impl IntrinsicTypeDefinition for LoongArchIntrinsicType { } } -impl LoongArchIntrinsicType +impl LoongArchIntrinsicType { + /// Accepts X, Y and Z. + /// Returns a `LoongArchType` + pub fn from_values(asm_fmt: &String, data_type: &String) -> Result { + let bit_len = match data_type.as_str() { + "A16QI" => Some(8), + "AM16QI" => Some(8), + "V16QI" => Some(8), + "V32QI" => Some(8), + "A32QI" => Some(8), + "AM32QI" => Some(8), + "V8HI" => Some(16), + "V16HI" => Some(16), + "V4SI" => Some(32), + "V8SI" => Some(32), + "V2DI" => Some(64), + "V4DI" => Some(64), + "UV16QI" => Some(8), + "UV32QI" => Some(8), + "UV8HI" => Some(16), + "UV16HI" => Some(16), + "UV4SI" => Some(32), + "UV8SI" => Some(32), + "UV2DI" => Some(64), + "UV4DI" => Some(64), + "V4SF" => Some(32), + "V8SF" => Some(32), + "V2DF" => Some(64), + "V4DF" => Some(64), + "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "CVPOINTER" | "HI" => None, + _ => panic!("unknown type {data_type} with ASM {asm_fmt}"), + }; + + let vec_len = match data_type.as_str() { + "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "HI" | => None, + "V32QI" | "V16HI" | "V8SI" | "V4DI" | "UV32QI" | "UV16HI" | "UV8SI" | "UV4DI" + | "V8SF" | "V4DF" => Some(4), + _ => Some(2), + }; + + Ok(LoongArchIntrinsicType { + data: IntrinsicType { + constant: false, + ptr_constant: false, + ptr: false, + kind: TypeKind::Mask, + bit_len, + vec_len, + simd_len: None + } + }) + } +} From 1ddb2d0cee88b25e53a071af8bd54dc54c2088bd Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 11 Aug 2025 22:09:13 +0530 Subject: [PATCH 5/8] chore: formatting --- Cargo.lock | 1 + .../intrinsic-test/src/loongarch/intrinsic.rs | 4 ++- crates/intrinsic-test/src/loongarch/mod.rs | 2 +- crates/intrinsic-test/src/loongarch/parser.rs | 27 ++++++++++++------- crates/intrinsic-test/src/loongarch/types.rs | 4 +++ crates/intrinsic-test/src/main.rs | 4 ++- 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9df0791b86..d3f2509cd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,6 +341,7 @@ dependencies = [ "log", "pretty_env_logger", "rayon", + "regex", "serde", "serde_json", ] diff --git a/crates/intrinsic-test/src/loongarch/intrinsic.rs b/crates/intrinsic-test/src/loongarch/intrinsic.rs index 33ba2dd9f8..ddd96250d7 100644 --- a/crates/intrinsic-test/src/loongarch/intrinsic.rs +++ b/crates/intrinsic-test/src/loongarch/intrinsic.rs @@ -40,6 +40,8 @@ impl IntrinsicDefinition for Intrinsic String { - unimplemented!("print_result_c of IntrinsicDefinition is not defined!") + unimplemented!( + "print_result_c of IntrinsicDefinition is not defined!" + ) } } diff --git a/crates/intrinsic-test/src/loongarch/mod.rs b/crates/intrinsic-test/src/loongarch/mod.rs index 61b97d5e3c..0f26e1967d 100644 --- a/crates/intrinsic-test/src/loongarch/mod.rs +++ b/crates/intrinsic-test/src/loongarch/mod.rs @@ -6,10 +6,10 @@ use std::fs::{self, File}; use rayon::prelude::*; -use crate::common::intrinsic_helpers::TypeKind; use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; +use crate::common::intrinsic_helpers::TypeKind; use crate::common::intrinsic::Intrinsic; use crate::loongarch::parser::get_loongson_intrinsics; diff --git a/crates/intrinsic-test/src/loongarch/parser.rs b/crates/intrinsic-test/src/loongarch/parser.rs index 6f0603928b..d21d924d9e 100644 --- a/crates/intrinsic-test/src/loongarch/parser.rs +++ b/crates/intrinsic-test/src/loongarch/parser.rs @@ -8,11 +8,11 @@ use crate::loongarch::intrinsic::LoongArchIntrinsicType; pub fn get_loongson_intrinsics( path: &Path, - target: &str + target: &str, ) -> Result>, Box> { let f = File::open(path).unwrap_or_else(|_| panic!("Failed to open {}", path.display())); let f = BufReader::new(f); - + let mut current_name: Option = None; let mut asm_fmts: Vec = Vec::new(); @@ -42,20 +42,26 @@ pub fn get_loongson_intrinsics( let data_types_len = data_types.len(); if data_types_len > 0 && data_types_len < 6 { arguments = data_types.split_off(1); - + // Being explicit here with the variable name return_type = data_types.get(0).unwrap(); - } else { + } else { panic!("DEBUG: line: {0} len: {1}", line, data_types.len()); } - let intrinsic = gen_intrinsic(current_name.as_str(), asm_fmts.clone(), arguments, return_type, target); + let intrinsic = gen_intrinsic( + current_name.as_str(), + asm_fmts.clone(), + arguments, + return_type, + target, + ); if intrinsic.is_ok() { intrinsics.push(intrinsic.unwrap()); } } - }; - return Ok(intrinsics) + } + return Ok(intrinsics); } fn gen_intrinsic( @@ -72,7 +78,8 @@ fn gen_intrinsic( .enumerate() .map(|(i, (asm_fmt, arg_type))| { let ty = LoongArchIntrinsicType::from_values(asm_fmt, arg_type).unwrap(); - let arg = Argument::::new(i, format!("_{i}_{}", arg_type), ty, None); + let arg = + Argument::::new(i, format!("_{i}_{}", arg_type), ty, None); return arg; }) .collect::>>(); @@ -117,7 +124,7 @@ fn gen_intrinsic( ("si8", t) => { arguments[2].ty.constant = true; arguments[3].ty.constant = true; - }, + } (_, _) => panic!( "unsupported assembly format: {:?} for {}", asm_fmts, current_name @@ -132,4 +139,4 @@ fn gen_intrinsic( results: results, arch_tags: vec![target.to_string()], }) -} \ No newline at end of file +} diff --git a/crates/intrinsic-test/src/loongarch/types.rs b/crates/intrinsic-test/src/loongarch/types.rs index 0d5fc7a053..d0241b5efa 100644 --- a/crates/intrinsic-test/src/loongarch/types.rs +++ b/crates/intrinsic-test/src/loongarch/types.rs @@ -1,5 +1,9 @@ use super::intrinsic::LoongArchIntrinsicType; use crate::common::cli::Language; +<<<<<<< HEAD +======= +use crate::common::intrinsic_helpers::Sign; +>>>>>>> b094de07 (chenj) use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; impl IntrinsicTypeDefinition for LoongArchIntrinsicType { diff --git a/crates/intrinsic-test/src/main.rs b/crates/intrinsic-test/src/main.rs index a645d2f409..7faf4a6a1f 100644 --- a/crates/intrinsic-test/src/main.rs +++ b/crates/intrinsic-test/src/main.rs @@ -24,7 +24,9 @@ fn main() { Some(ArmArchitectureTest::create(processed_cli_options)) } - "loongarch64-unknown-linux-gnu" => Some(LoongArchArchitectureTest::create(processed_cli_options)), + "loongarch64-unknown-linux-gnu" => { + Some(LoongArchArchitectureTest::create(processed_cli_options)) + } _ => None, }; From 1a488a9abb699aa4466d5c3c6e69851e7e62bf14 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Mon, 11 Aug 2025 22:15:43 +0530 Subject: [PATCH 6/8] fix: sharpen the IntrinsicType recognition function `from_values` --- crates/intrinsic-test/src/loongarch/types.rs | 68 +++++++++----------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/crates/intrinsic-test/src/loongarch/types.rs b/crates/intrinsic-test/src/loongarch/types.rs index d0241b5efa..341759059f 100644 --- a/crates/intrinsic-test/src/loongarch/types.rs +++ b/crates/intrinsic-test/src/loongarch/types.rs @@ -1,9 +1,6 @@ use super::intrinsic::LoongArchIntrinsicType; use crate::common::cli::Language; -<<<<<<< HEAD -======= use crate::common::intrinsic_helpers::Sign; ->>>>>>> b094de07 (chenj) use crate::common::intrinsic_helpers::{IntrinsicType, IntrinsicTypeDefinition, TypeKind}; impl IntrinsicTypeDefinition for LoongArchIntrinsicType { @@ -32,42 +29,37 @@ impl LoongArchIntrinsicType { /// Accepts X, Y and Z. /// Returns a `LoongArchType` pub fn from_values(asm_fmt: &String, data_type: &String) -> Result { - let bit_len = match data_type.as_str() { - "A16QI" => Some(8), - "AM16QI" => Some(8), - "V16QI" => Some(8), - "V32QI" => Some(8), - "A32QI" => Some(8), - "AM32QI" => Some(8), - "V8HI" => Some(16), - "V16HI" => Some(16), - "V4SI" => Some(32), - "V8SI" => Some(32), - "V2DI" => Some(64), - "V4DI" => Some(64), - "UV16QI" => Some(8), - "UV32QI" => Some(8), - "UV8HI" => Some(16), - "UV16HI" => Some(16), - "UV4SI" => Some(32), - "UV8SI" => Some(32), - "UV2DI" => Some(64), - "UV4DI" => Some(64), - "V4SF" => Some(32), - "V8SF" => Some(32), - "V2DF" => Some(64), - "V4DF" => Some(64), - "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "CVPOINTER" | "HI" => None, + let (bit_len, vec_len, type_kind) = match data_type.as_str() { + "A16QI" => (Some(8), Some(16), TypeKind::Int(Sign::Signed)), + "AM16QI" => (Some(8), Some(16), TypeKind::Int(Sign::Signed)), + "V16QI" => (Some(8), Some(16), TypeKind::Int(Sign::Signed)), + "V32QI" => (Some(8), Some(32), TypeKind::Int(Sign::Signed)), + "A32QI" => (Some(8), Some(32), TypeKind::Int(Sign::Signed)), + "AM32QI" => (Some(8), Some(32), TypeKind::Int(Sign::Signed)), + "V8HI" => (Some(16), Some(8), TypeKind::Int(Sign::Signed)), + "V16HI" => (Some(16), Some(16), TypeKind::Int(Sign::Signed)), + "V4SI" => (Some(32), Some(4), TypeKind::Int(Sign::Signed)), + "V8SI" => (Some(32), Some(8), TypeKind::Int(Sign::Signed)), + "V2DI" => (Some(64), Some(2), TypeKind::Int(Sign::Signed)), + "V4DI" => (Some(64), Some(4), TypeKind::Int(Sign::Signed)), + "UV16QI" => (Some(8), Some(16), TypeKind::Int(Sign::Unsigned)), + "UV32QI" => (Some(8), Some(32), TypeKind::Int(Sign::Unsigned)), + "UV8HI" => (Some(16), Some(8), TypeKind::Int(Sign::Unsigned)), + "UV16HI" => (Some(16), Some(16), TypeKind::Int(Sign::Unsigned)), + "UV4SI" => (Some(32), Some(4), TypeKind::Int(Sign::Unsigned)), + "UV8SI" => (Some(32), Some(8), TypeKind::Int(Sign::Unsigned)), + "UV2DI" => (Some(64), Some(2), TypeKind::Int(Sign::Unsigned)), + "UV4DI" => (Some(64), Some(4), TypeKind::Int(Sign::Unsigned)), + "V4SF" => (Some(32), Some(4), TypeKind::Float), + "V8SF" => (Some(32), Some(8), TypeKind::Float), + "V2DF" => (Some(64), Some(2), TypeKind::Float), + "V4DF" => (Some(64), Some(4), TypeKind::Float), + "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "CVPOINTER" | "HI" => { + (None, None, TypeKind::Int(Sign::Signed)) + } _ => panic!("unknown type {data_type} with ASM {asm_fmt}"), }; - let vec_len = match data_type.as_str() { - "SI" | "DI" | "USI" | "UDI" | "UQI" | "QI" | "HI" | => None, - "V32QI" | "V16HI" | "V8SI" | "V4DI" | "UV32QI" | "UV16HI" | "UV8SI" | "UV4DI" - | "V8SF" | "V4DF" => Some(4), - _ => Some(2), - }; - Ok(LoongArchIntrinsicType { data: IntrinsicType { constant: false, @@ -76,8 +68,8 @@ impl LoongArchIntrinsicType { kind: TypeKind::Mask, bit_len, vec_len, - simd_len: None - } + simd_len: None, + }, }) } } From ac7071e02a7d01a39da97e7dd80a0747881e9877 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Tue, 12 Aug 2025 09:53:10 +0530 Subject: [PATCH 7/8] feat: add C testfile compilation mechanism to loongarch --- .../intrinsic-test/src/loongarch/compile.rs | 29 ++++++++ crates/intrinsic-test/src/loongarch/config.rs | 9 +++ crates/intrinsic-test/src/loongarch/mod.rs | 69 ++++++++++++++++++- 3 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 crates/intrinsic-test/src/loongarch/compile.rs create mode 100644 crates/intrinsic-test/src/loongarch/config.rs diff --git a/crates/intrinsic-test/src/loongarch/compile.rs b/crates/intrinsic-test/src/loongarch/compile.rs new file mode 100644 index 0000000000..f8a2cb0149 --- /dev/null +++ b/crates/intrinsic-test/src/loongarch/compile.rs @@ -0,0 +1,29 @@ +use crate::common::cli::ProcessedCli; +use crate::common::compile_c::{CompilationCommandBuilder, CppCompilation}; + +pub fn build_cpp_compilation(config: &ProcessedCli) -> Option { + let cpp_compiler = config.cpp_compiler.as_ref()?; + + // -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations + let mut command = CompilationCommandBuilder::new() + .set_compiler(cpp_compiler) + .set_target(&config.target) + .set_opt_level("2") + .set_cxx_toolchain_dir(config.cxx_toolchain_dir.as_deref()) + .set_project_root("c_programs") + .add_extra_flags(vec![ + "-ffp-contract=off", + "-Wno-narrowing", + "-mlasx", + "-mlsx", + "-mfrecipe", + ]); + + if !cpp_compiler.contains("clang") { + command = command.add_extra_flag("-flax-vector-conversions"); + } + + let cpp_compiler = command.into_cpp_compilation(); + + Some(cpp_compiler) +} diff --git a/crates/intrinsic-test/src/loongarch/config.rs b/crates/intrinsic-test/src/loongarch/config.rs new file mode 100644 index 0000000000..fce768f98c --- /dev/null +++ b/crates/intrinsic-test/src/loongarch/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 `stdarch-gen-loongarch/lsx.spec` and `stdarch-gen-loongarch/lasx.spec`, +{line_prefix}published under the same license as the `intrinsic-test` crate.\n +" + ) +} diff --git a/crates/intrinsic-test/src/loongarch/mod.rs b/crates/intrinsic-test/src/loongarch/mod.rs index 0f26e1967d..53ba934ca3 100644 --- a/crates/intrinsic-test/src/loongarch/mod.rs +++ b/crates/intrinsic-test/src/loongarch/mod.rs @@ -1,3 +1,5 @@ +mod compile; +mod config; mod intrinsic; mod parser; mod types; @@ -6,12 +8,14 @@ use std::fs::{self, File}; use rayon::prelude::*; -use crate::common::SupportedArchitectureTest; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; +use crate::common::gen_c::{write_main_cpp, write_mod_cpp}; use crate::common::intrinsic_helpers::TypeKind; +use crate::common::{SupportedArchitectureTest, chunk_info}; use crate::common::intrinsic::Intrinsic; +use crate::loongarch::config::build_notices; use crate::loongarch::parser::get_loongson_intrinsics; use intrinsic::LoongArchIntrinsicType; @@ -42,7 +46,68 @@ impl SupportedArchitectureTest for LoongArchArchitectureTest { } fn build_c_file(&self) -> bool { - unimplemented!("build_c_file of LoongArchIntrinsicType is not defined!") + let c_target = "loongarch"; + let platform_headers = &["lasxintrin.h", "lsxintrin.h"]; + + let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len()); + + let cpp_compiler_wrapped = compile::build_cpp_compilation(&self.cli_options); + + let notice = &build_notices("// "); + fs::create_dir_all("c_programs").unwrap(); + self.intrinsics + .par_chunks(chunk_size) + .enumerate() + .map(|(i, chunk)| { + let c_filename = format!("c_programs/mod_{i}.cpp"); + let mut file = File::create(&c_filename).unwrap(); + write_mod_cpp(&mut file, notice, c_target, platform_headers, chunk).unwrap(); + + // compile this cpp file into a .o file. + // + // This is done because `cpp_compiler_wrapped` is None when + // the --generate-only flag is passed + if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() { + let output = cpp_compiler + .compile_object_file(&format!("mod_{i}.cpp"), &format!("mod_{i}.o"))?; + assert!(output.status.success(), "{output:?}"); + } + + Ok(()) + }) + .collect::>() + .unwrap(); + + let mut file = File::create("c_programs/main.cpp").unwrap(); + write_main_cpp( + &mut file, + c_target, + "\n", + self.intrinsics.iter().map(|i| i.name.as_str()), + ) + .unwrap(); + + // This is done because `cpp_compiler_wrapped` is None when + // the --generate-only flag is passed + if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() { + // compile this cpp file into a .o file + info!("compiling main.cpp"); + let output = cpp_compiler + .compile_object_file("main.cpp", "intrinsic-test-programs.o") + .unwrap(); + assert!(output.status.success(), "{output:?}"); + + let object_files = (0..chunk_count) + .map(|i| format!("mod_{i}.o")) + .chain(["intrinsic-test-programs.o".to_owned()]); + + let output = cpp_compiler + .link_executable(object_files, "intrinsic-test-programs") + .unwrap(); + assert!(output.status.success(), "{output:?}"); + } + + true } fn build_rust_file(&self) -> bool { From a1a842f07f5e8ccac6c4872595d05fad78239341 Mon Sep 17 00:00:00 2001 From: Madhav Madhusoodanan Date: Tue, 12 Aug 2025 10:21:26 +0530 Subject: [PATCH 8/8] feat: added rust test-file compilation mechanism for loongarch --- crates/intrinsic-test/src/loongarch/config.rs | 45 +++++++++++++++ crates/intrinsic-test/src/loongarch/mod.rs | 56 ++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/crates/intrinsic-test/src/loongarch/config.rs b/crates/intrinsic-test/src/loongarch/config.rs index fce768f98c..5c22a64802 100644 --- a/crates/intrinsic-test/src/loongarch/config.rs +++ b/crates/intrinsic-test/src/loongarch/config.rs @@ -7,3 +7,48 @@ pub fn build_notices(line_prefix: &str) -> String { " ) } + +pub const LOONGARCH_CONFIGURATIONS: &str = r#" +#![cfg_attr(any(target_arch = "loongarch64", target_arch = "loongarch32"), feature(stdarch_loongarch))] +"#; + +// Format f16 values (and vectors containing them) in a way that is consistent with C. +pub const F16_FORMATTING_DEF: &str = r#" +/// Used to continue `Debug`ging SIMD types as `MySimd(1, 2, 3, 4)`, as they +/// were before moving to array-based simd. +#[inline] +fn debug_simd_finish( + formatter: &mut core::fmt::Formatter<'_>, + type_name: &str, + array: &[T; N], +) -> core::fmt::Result { + core::fmt::Formatter::debug_tuple_fields_finish( + formatter, + type_name, + &core::array::from_fn::<&dyn core::fmt::Debug, N, _>(|i| &array[i]), + ) +} + +#[repr(transparent)] +struct Hex(T); + +impl core::fmt::Debug for Hex { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + ::fmt(&self.0, f) + } +} + +fn debug_f16(x: T) -> impl core::fmt::Debug { + Hex(x) +} + +trait DebugHexF16 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result; +} + +impl DebugHexF16 for f16 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#06x?}", self.to_bits()) + } +} + "#; diff --git a/crates/intrinsic-test/src/loongarch/mod.rs b/crates/intrinsic-test/src/loongarch/mod.rs index 53ba934ca3..67409033c1 100644 --- a/crates/intrinsic-test/src/loongarch/mod.rs +++ b/crates/intrinsic-test/src/loongarch/mod.rs @@ -11,11 +11,14 @@ use rayon::prelude::*; use crate::common::cli::ProcessedCli; use crate::common::compare::compare_outputs; use crate::common::gen_c::{write_main_cpp, write_mod_cpp}; +use crate::common::gen_rust::{ + compile_rust_programs, write_bin_cargo_toml, write_lib_cargo_toml, write_lib_rs, write_main_rs, +}; use crate::common::intrinsic_helpers::TypeKind; use crate::common::{SupportedArchitectureTest, chunk_info}; use crate::common::intrinsic::Intrinsic; -use crate::loongarch::config::build_notices; +use crate::loongarch::config::{F16_FORMATTING_DEF, LOONGARCH_CONFIGURATIONS, build_notices}; use crate::loongarch::parser::get_loongson_intrinsics; use intrinsic::LoongArchIntrinsicType; @@ -111,7 +114,56 @@ impl SupportedArchitectureTest for LoongArchArchitectureTest { } fn build_rust_file(&self) -> bool { - unimplemented!("build_rust_file of LoongArchIntrinsicType is not defined!") + std::fs::create_dir_all("rust_programs/src").unwrap(); + + let architecture = "loongarch64"; + + let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len()); + + let mut cargo = File::create("rust_programs/Cargo.toml").unwrap(); + write_bin_cargo_toml(&mut cargo, chunk_count).unwrap(); + + let mut main_rs = File::create("rust_programs/src/main.rs").unwrap(); + write_main_rs( + &mut main_rs, + chunk_count, + LOONGARCH_CONFIGURATIONS, + "", + self.intrinsics.iter().map(|i| i.name.as_str()), + ) + .unwrap(); + + let target = &self.cli_options.target; + let toolchain = self.cli_options.toolchain.as_deref(); + let linker = self.cli_options.linker.as_deref(); + + let notice = &build_notices("// "); + self.intrinsics + .par_chunks(chunk_size) + .enumerate() + .map(|(i, chunk)| { + std::fs::create_dir_all(format!("rust_programs/mod_{i}/src"))?; + + let rust_filename = format!("rust_programs/mod_{i}/src/lib.rs"); + trace!("generating `{rust_filename}`"); + let mut file = File::create(rust_filename)?; + + let cfg = LOONGARCH_CONFIGURATIONS; + let definitions = F16_FORMATTING_DEF; + write_lib_rs(&mut file, architecture, notice, cfg, definitions, chunk)?; + + let toml_filename = format!("rust_programs/mod_{i}/Cargo.toml"); + trace!("generating `{toml_filename}`"); + let mut file = File::create(toml_filename).unwrap(); + + write_lib_cargo_toml(&mut file, &format!("mod_{i}"))?; + + Ok(()) + }) + .collect::>() + .unwrap(); + + compile_rust_programs(toolchain, target, linker) } fn compare_outputs(&self) -> bool {