use super::intrinsic::ArmIntrinsicType; use crate::common::argument::{Argument, ArgumentList}; use crate::common::constraint::Constraint; use crate::common::intrinsic::Intrinsic; use crate::common::intrinsic_helpers::IntrinsicType; use serde::Deserialize; use serde_json::Value; use std::collections::HashMap; use std::path::Path; #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] struct ReturnType { value: String, } #[derive(Deserialize, Debug)] #[serde(untagged, deny_unknown_fields)] pub enum ArgPrep { Register { #[serde(rename = "register")] #[allow(dead_code)] reg: String, }, Immediate { #[serde(rename = "minimum")] min: i64, #[serde(rename = "maximum")] max: i64, }, Nothing {}, } impl TryFrom for ArgPrep { type Error = serde_json::Error; fn try_from(value: Value) -> Result { serde_json::from_value(value) } } #[derive(Deserialize, Debug)] struct JsonIntrinsic { #[serde(rename = "SIMD_ISA")] simd_isa: String, name: String, arguments: Vec, return_type: ReturnType, #[serde(rename = "Arguments_Preparation")] args_prep: Option>, #[serde(rename = "Architectures")] architectures: Vec, } pub fn get_neon_intrinsics( filename: &Path, target: &str, ) -> Result>, Box> { let file = std::fs::File::open(filename)?; let reader = std::io::BufReader::new(file); let json: Vec = serde_json::from_reader(reader).expect("Couldn't parse JSON"); let parsed = json .into_iter() .filter_map(|intr| { if intr.simd_isa == "Neon" { Some(json_to_intrinsic(intr, target).expect("Couldn't parse JSON")) } else { None } }) .collect(); Ok(parsed) } fn json_to_intrinsic( mut intr: JsonIntrinsic, target: &str, ) -> Result, Box> { let name = intr.name.replace(['[', ']'], ""); let results = ArmIntrinsicType::from_c(&intr.return_type.value, target)?; let args = intr .arguments .into_iter() .enumerate() .map(|(i, arg)| { let (type_name, arg_name) = Argument::::type_and_name_from_c(&arg); 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 constraint: Option = arg_prep.and_then(|a| a.try_into().ok()); let ty = ArmIntrinsicType::from_c(type_name, target) .unwrap_or_else(|_| panic!("Failed to parse argument '{arg}'")); let mut arg = Argument::::new(i, String::from(arg_name), ty, constraint); // The JSON doesn't list immediates as const let IntrinsicType { ref mut constant, .. } = arg.ty.data; if arg.name.starts_with("imm") { *constant = true } arg }) .collect(); let arguments = ArgumentList:: { args }; Ok(Intrinsic { name, arguments, results, arch_tags: intr.architectures, }) } /// ARM-specific impl TryFrom for Constraint { type Error = (); fn try_from(prep: ArgPrep) -> Result { let parsed_ints = match prep { ArgPrep::Immediate { min, max } => Ok((min, max)), _ => Err(()), }; if let Ok((min, max)) = parsed_ints { if min == max { Ok(Constraint::Equal(min)) } else { Ok(Constraint::Range(min..max + 1)) } } else { Err(()) } } }