| use regex::Regex; |
| use serde_with::{DeserializeFromStr, SerializeDisplay}; |
| use std::str::FromStr; |
| use std::{fmt, sync::LazyLock}; |
| |
| use crate::{ |
| fn_suffix::SuffixKind, |
| predicate_forms::PredicationMask, |
| typekinds::{ToRepr, TypeKind, TypeKindOptions, VectorTupleSize}, |
| }; |
| |
| #[derive(Debug, Clone, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr)] |
| pub enum Wildcard { |
| Type(Option<usize>), |
| /// NEON type derivated by a base type |
| NEONType(Option<usize>, Option<VectorTupleSize>, Option<SuffixKind>), |
| /// SVE type derivated by a base type |
| SVEType(Option<usize>, Option<VectorTupleSize>), |
| /// Integer representation of bitsize |
| Size(Option<usize>), |
| /// Integer representation of bitsize minus one |
| SizeMinusOne(Option<usize>), |
| /// Literal representation of the bitsize: b(yte), h(half), w(ord) or d(ouble) |
| SizeLiteral(Option<usize>), |
| /// Literal representation of the type kind: f(loat), s(igned), u(nsigned) |
| TypeKind(Option<usize>, Option<TypeKindOptions>), |
| /// Log2 of the size in bytes |
| SizeInBytesLog2(Option<usize>), |
| /// Predicate to be inferred from the specified type |
| Predicate(Option<usize>), |
| /// Predicate to be inferred from the greatest type |
| MaxPredicate, |
| |
| Scale(Box<Wildcard>, Box<TypeKind>), |
| |
| // Other wildcards |
| LLVMLink, |
| NVariant, |
| /// Predicate forms to use and placeholder for a predicate form function name modifier |
| PredicateForms(PredicationMask), |
| |
| /// User-set wildcard through `substitutions` |
| Custom(String), |
| } |
| |
| impl Wildcard { |
| pub fn is_nonpredicate_type(&self) -> bool { |
| matches!( |
| self, |
| Wildcard::Type(..) | Wildcard::NEONType(..) | Wildcard::SVEType(..) |
| ) |
| } |
| |
| pub fn get_typeset_index(&self) -> Option<usize> { |
| match self { |
| Wildcard::Type(idx) | Wildcard::NEONType(idx, ..) | Wildcard::SVEType(idx, ..) => { |
| Some(idx.unwrap_or(0)) |
| } |
| _ => None, |
| } |
| } |
| } |
| |
| impl FromStr for Wildcard { |
| type Err = String; |
| |
| fn from_str(s: &str) -> Result<Self, Self::Err> { |
| static RE: LazyLock<Regex> = LazyLock::new(|| { |
| Regex::new(r"^(?P<wildcard>\w+?)(?:_x(?P<tuple_size>[2-4]))?(?:\[(?P<index>\d+)\])?(?:\.(?P<modifiers>\w+))?(?:\s+as\s+(?P<scale_to>.*?))?$").unwrap() |
| }); |
| |
| if let Some(c) = RE.captures(s) { |
| let wildcard_name = &c["wildcard"]; |
| let inputset_index = c |
| .name("index") |
| .map(<&str>::from) |
| .map(usize::from_str) |
| .transpose() |
| .map_err(|_| format!("{:#?} is not a valid type index", &c["index"]))?; |
| let tuple_size = c |
| .name("tuple_size") |
| .map(<&str>::from) |
| .map(VectorTupleSize::from_str) |
| .transpose() |
| .map_err(|_| format!("{:#?} is not a valid tuple size", &c["tuple_size"]))?; |
| let modifiers = c.name("modifiers").map(<&str>::from); |
| |
| let wildcard = match (wildcard_name, inputset_index, tuple_size, modifiers) { |
| ("type", index, None, None) => Ok(Wildcard::Type(index)), |
| ("neon_type", index, tuple, modifier) => { |
| if let Some(str_suffix) = modifier { |
| let suffix_kind = SuffixKind::from_str(str_suffix); |
| return Ok(Wildcard::NEONType(index, tuple, Some(suffix_kind.unwrap()))); |
| } else { |
| Ok(Wildcard::NEONType(index, tuple, None)) |
| } |
| } |
| ("sve_type", index, tuple, None) => Ok(Wildcard::SVEType(index, tuple)), |
| ("size", index, None, None) => Ok(Wildcard::Size(index)), |
| ("size_minus_one", index, None, None) => Ok(Wildcard::SizeMinusOne(index)), |
| ("size_literal", index, None, None) => Ok(Wildcard::SizeLiteral(index)), |
| ("type_kind", index, None, modifiers) => Ok(Wildcard::TypeKind( |
| index, |
| modifiers.map(|modifiers| modifiers.parse()).transpose()?, |
| )), |
| ("size_in_bytes_log2", index, None, None) => Ok(Wildcard::SizeInBytesLog2(index)), |
| ("predicate", index, None, None) => Ok(Wildcard::Predicate(index)), |
| ("max_predicate", None, None, None) => Ok(Wildcard::MaxPredicate), |
| ("llvm_link", None, None, None) => Ok(Wildcard::LLVMLink), |
| ("_n", None, None, None) => Ok(Wildcard::NVariant), |
| (w, None, None, None) if w.starts_with('_') => { |
| // test for predicate forms |
| let pf_mask = PredicationMask::from_str(&w[1..]); |
| if let Ok(mask) = pf_mask { |
| if mask.has_merging() { |
| Ok(Wildcard::PredicateForms(mask)) |
| } else { |
| Err("cannot add predication without a Merging form".to_string()) |
| } |
| } else { |
| Err(format!("invalid wildcard `{s:#?}`")) |
| } |
| } |
| (cw, None, None, None) => Ok(Wildcard::Custom(cw.to_string())), |
| _ => Err(format!("invalid wildcard `{s:#?}`")), |
| }?; |
| |
| let scale_to = c |
| .name("scale_to") |
| .map(<&str>::from) |
| .map(TypeKind::from_str) |
| .transpose() |
| .map_err(|_| format!("{:#?} is not a valid type", &c["scale_to"]))?; |
| |
| if let Some(scale_to) = scale_to { |
| Ok(Wildcard::Scale(Box::new(wildcard), Box::new(scale_to))) |
| } else { |
| Ok(wildcard) |
| } |
| } else { |
| Err(format!("## invalid wildcard `{s:#?}`")) |
| } |
| } |
| } |
| |
| impl fmt::Display for Wildcard { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self { |
| Self::Type(None) => write!(f, "type"), |
| Self::Type(Some(index)) => write!(f, "type[{index}]"), |
| Self::NEONType(None, None, None) => write!(f, "neon_type"), |
| Self::NEONType(None, None, Some(suffix_kind)) => write!(f, "neon_type.{suffix_kind}"), |
| Self::NEONType(Some(index), None, None) => write!(f, "neon_type[{index}]"), |
| Self::NEONType(Some(index), None, Some(suffix_kind)) => { |
| write!(f, "neon_type[{index}].{suffix_kind}") |
| } |
| Self::NEONType(None, Some(tuple_size), Some(suffix_kind)) => { |
| write!(f, "neon_type_x{tuple_size}.{suffix_kind}") |
| } |
| Self::NEONType(None, Some(tuple_size), None) => write!(f, "neon_type_x{tuple_size}"), |
| Self::NEONType(Some(index), Some(tuple_size), None) => { |
| write!(f, "neon_type_x{tuple_size}[{index}]") |
| } |
| Self::NEONType(Some(index), Some(tuple_size), Some(suffix_kind)) => { |
| write!(f, "neon_type_x{tuple_size}[{index}].{suffix_kind}") |
| } |
| Self::SVEType(None, None) => write!(f, "sve_type"), |
| Self::SVEType(Some(index), None) => write!(f, "sve_type[{index}]"), |
| Self::SVEType(None, Some(tuple_size)) => write!(f, "sve_type_x{tuple_size}"), |
| Self::SVEType(Some(index), Some(tuple_size)) => { |
| write!(f, "sve_type_x{tuple_size}[{index}]") |
| } |
| Self::Size(None) => write!(f, "size"), |
| Self::Size(Some(index)) => write!(f, "size[{index}]"), |
| Self::SizeMinusOne(None) => write!(f, "size_minus_one"), |
| Self::SizeMinusOne(Some(index)) => write!(f, "size_minus_one[{index}]"), |
| Self::SizeLiteral(None) => write!(f, "size_literal"), |
| Self::SizeLiteral(Some(index)) => write!(f, "size_literal[{index}]"), |
| Self::TypeKind(None, None) => write!(f, "type_kind"), |
| Self::TypeKind(None, Some(opts)) => write!(f, "type_kind.{opts}"), |
| Self::TypeKind(Some(index), None) => write!(f, "type_kind[{index}]"), |
| Self::TypeKind(Some(index), Some(opts)) => write!(f, "type_kind[{index}].{opts}"), |
| Self::SizeInBytesLog2(None) => write!(f, "size_in_bytes_log2"), |
| Self::SizeInBytesLog2(Some(index)) => write!(f, "size_in_bytes_log2[{index}]"), |
| Self::Predicate(None) => write!(f, "predicate"), |
| Self::Predicate(Some(index)) => write!(f, "predicate[{index}]"), |
| Self::MaxPredicate => write!(f, "max_predicate"), |
| Self::LLVMLink => write!(f, "llvm_link"), |
| Self::NVariant => write!(f, "_n"), |
| Self::PredicateForms(mask) => write!(f, "_{mask}"), |
| |
| Self::Scale(wildcard, ty) => write!(f, "{wildcard} as {}", ty.rust_repr()), |
| Self::Custom(cw) => write!(f, "{cw}"), |
| } |
| } |
| } |