From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- .../crates/intrinsic-test/src/acle_csv_parser.rs | 319 +++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 library/stdarch/crates/intrinsic-test/src/acle_csv_parser.rs (limited to 'library/stdarch/crates/intrinsic-test/src/acle_csv_parser.rs') diff --git a/library/stdarch/crates/intrinsic-test/src/acle_csv_parser.rs b/library/stdarch/crates/intrinsic-test/src/acle_csv_parser.rs new file mode 100644 index 000000000..d7b066485 --- /dev/null +++ b/library/stdarch/crates/intrinsic-test/src/acle_csv_parser.rs @@ -0,0 +1,319 @@ +use itertools::Itertools; +use regex::Regex; +use serde::Deserialize; + +use crate::argument::{Argument, ArgumentList, Constraint}; +use crate::intrinsic::Intrinsic; +use crate::types::{IntrinsicType, TypeKind}; + +pub fn get_acle_intrinsics(filename: &str) -> Vec { + let data = std::fs::read_to_string(filename).expect("Failed to open ACLE intrinsics file"); + + let data = data + .lines() + .filter_map(|l| { + (!(l.starts_with("") || l.is_empty() || l.starts_with("
"))) + .then(|| l.replace("
\t", "")) + }) + .join("\n"); + + let mut csv_reader = csv::ReaderBuilder::new() + .delimiter(b'\t') + .from_reader(data.as_bytes()); + + let mut intrinsics: Vec = csv_reader + .deserialize() + .filter_map(|x: Result| x.ok().map(|i| i.into())) + .collect::>(); + + // Intrinsics such as vshll_n_s8 exist twice in the ACLE with different constraints. + intrinsics.sort_by(|a, b| a.name.cmp(&b.name)); + let (intrinsics, duplicates) = intrinsics.partition_dedup_by(|a, b| a.name == b.name); + for duplicate in duplicates { + let name = &duplicate.name; + let constraints = duplicate + .arguments + .args + .drain(..) + .filter(|a| a.has_constraint()); + let intrinsic = intrinsics.iter_mut().find(|i| &i.name == name).unwrap(); + + for mut constraint in constraints { + let real_constraint = intrinsic + .arguments + .args + .iter_mut() + .find(|a| a.name == constraint.name) + .unwrap(); + real_constraint + .constraints + .push(constraint.constraints.pop().unwrap()); + } + } + + intrinsics.to_vec() +} + +impl Into for ACLEIntrinsicLine { + fn into(self) -> Intrinsic { + let signature = self.intrinsic; + let (ret_ty, remaining) = signature.split_once(' ').unwrap(); + + let results = type_from_c(ret_ty) + .unwrap_or_else(|_| panic!("Failed to parse return type: {}", ret_ty)); + + let (name, args) = remaining.split_once('(').unwrap(); + let args = args.trim_end_matches(')'); + + // Typo in ACLE data + let args = args.replace("int16x8q_t", "int16x8_t"); + + let arg_prep = self.argument_preparation.as_str(); + let args = args + .split(',') + .enumerate() + .map(move |(idx, arg)| { + let arg = arg.trim(); + if arg.starts_with("__builtin_constant_p") { + handle_constraint(idx, arg, arg_prep) + } else { + from_c(idx, arg) + } + }) + .collect(); + let arguments = ArgumentList { args }; + let a64_only = match &*self.supported_architectures { + "A64" => true, + "v7/A32/A64" | "A32/A64" => false, + _ => panic!("Invalid supported architectures"), + }; + + Intrinsic { + name: name.to_string(), + arguments, + results, + a64_only, + } + } +} + +fn handle_constraint(idx: usize, arg: &str, prep: &str) -> Argument { + let prep = prep.replace(' ', ""); + + let name = arg + .trim_start_matches("__builtin_constant_p") + .trim_start_matches(|ref c| c == &' ' || c == &'(') + .trim_end_matches(')') + .to_string(); + + let ty = IntrinsicType::Type { + constant: true, + kind: TypeKind::Int, + bit_len: Some(32), + simd_len: None, + vec_len: None, + }; + + let constraints = prep + .split(';') + .find_map(|p| handle_range_constraint(&name, p).or_else(|| handle_eq_constraint(&name, p))) + .map(|c| vec![c]) + .unwrap_or_default(); + + Argument { + pos: idx, + name, + ty, + constraints, + } +} + +fn handle_range_constraint(name: &str, data: &str) -> Option { + lazy_static! { + static ref RANGE_CONSTRAINT: Regex = + Regex::new(r#"([0-9]+)<=([[:alnum:]]+)<=([0-9]+)"#).unwrap(); + } + + let captures = RANGE_CONSTRAINT.captures(data)?; + if captures.get(2).map(|c| c.as_str() == name).unwrap_or(false) { + match (captures.get(1), captures.get(3)) { + (Some(start), Some(end)) => { + let start = start.as_str().parse::().unwrap(); + let end = end.as_str().parse::().unwrap() + 1; + Some(Constraint::Range(start..end)) + } + _ => panic!("Invalid constraint"), + } + } else { + None + } +} + +fn handle_eq_constraint(name: &str, data: &str) -> Option { + lazy_static! { + static ref EQ_CONSTRAINT: Regex = Regex::new(r#"([[:alnum:]]+)==([0-9]+)"#).unwrap(); + } + let captures = EQ_CONSTRAINT.captures(data)?; + if captures.get(1).map(|c| c.as_str() == name).unwrap_or(false) { + captures + .get(2) + .map(|c| Constraint::Equal(c.as_str().parse::().unwrap())) + } else { + None + } +} + +fn from_c(pos: usize, s: &str) -> Argument { + let name_index = s + .chars() + .rev() + .take_while(|c| c != &'*' && c != &' ') + .count(); + + let name_start = s.len() - name_index; + let name = s[name_start..].to_string(); + let s = s[..name_start].trim(); + + Argument { + pos, + name, + ty: type_from_c(s).unwrap_or_else(|_| panic!("Failed to parse type: {}", s)), + constraints: vec![], + } +} + +fn type_from_c(s: &str) -> Result { + const CONST_STR: &str = "const "; + + if let Some(s) = s.strip_suffix('*') { + let (s, constant) = if s.ends_with(CONST_STR) { + (&s[..s.len() - (CONST_STR.len() + 1)], true) + } else { + (s, false) + }; + + let s = s.trim_end(); + + Ok(IntrinsicType::Ptr { + constant, + child: Box::new(type_from_c(s)?), + }) + } else { + // [const ]TYPE[{bitlen}[x{simdlen}[x{vec_len}]]][_t] + + let (mut s, constant) = if let Some(s) = s.strip_prefix(CONST_STR) { + (s, true) + } else { + (s, false) + }; + s = s.strip_suffix("_t").unwrap_or(s); + + let mut parts = s.split('x'); // [[{bitlen}], [{simdlen}], [{vec_len}] ] + + let start = parts.next().ok_or("Impossible to parse type")?; + + if let Some(digit_start) = start.find(|c: char| c.is_ascii_digit()) { + let (arg_kind, bit_len) = start.split_at(digit_start); + + let arg_kind = arg_kind.parse::()?; + let bit_len = bit_len.parse::().map_err(|err| err.to_string())?; + + let simd_len = parts.next().map(|part| part.parse::().ok()).flatten(); + let vec_len = parts.next().map(|part| part.parse::().ok()).flatten(); + + Ok(IntrinsicType::Type { + constant, + kind: arg_kind, + bit_len: Some(bit_len), + simd_len, + vec_len, + }) + } else { + Ok(IntrinsicType::Type { + constant, + kind: start.parse::()?, + bit_len: None, + simd_len: None, + vec_len: None, + }) + } + } +} + +#[derive(Deserialize, Debug, PartialEq, Clone)] +struct ACLEIntrinsicLine { + #[serde(rename = "Intrinsic")] + intrinsic: String, + #[serde(rename = "Argument preparation")] + argument_preparation: String, + #[serde(rename = "AArch64 Instruction")] + aarch64_instruction: String, + #[serde(rename = "Result")] + result: String, + #[serde(rename = "Supported architectures")] + supported_architectures: String, +} + +#[cfg(test)] +mod test { + use super::*; + use crate::argument::Argument; + use crate::types::{IntrinsicType, TypeKind}; + + #[test] + fn parse_simd() { + let expected = Argument { + pos: 0, + name: "a".into(), + ty: IntrinsicType::Type { + constant: false, + kind: TypeKind::Int, + bit_len: Some(32), + simd_len: Some(4), + vec_len: None, + }, + constraints: vec![], + }; + let actual = from_c(0, "int32x4_t a"); + assert_eq!(expected, actual); + } + + #[test] + fn parse_simd_with_vec() { + let expected = Argument { + pos: 0, + name: "a".into(), + ty: IntrinsicType::Type { + constant: false, + kind: TypeKind::Int, + bit_len: Some(32), + simd_len: Some(4), + vec_len: Some(2), + }, + constraints: vec![], + }; + let actual = from_c(0, "int32x4x2_t a"); + assert_eq!(expected, actual); + } + + #[test] + fn test_ptr() { + let expected = Argument { + pos: 0, + name: "ptr".into(), + ty: crate::types::IntrinsicType::Ptr { + constant: true, + child: Box::new(IntrinsicType::Type { + constant: false, + kind: TypeKind::Int, + bit_len: Some(8), + simd_len: None, + vec_len: None, + }), + }, + constraints: vec![], + }; + let actual = from_c(0, "int8_t const *ptr"); + assert_eq!(expected, actual); + } +} -- cgit v1.2.3