blob: 6c40d88df45fdd7b7f02a713eb1f6edb7ef67ec9 [file] [log] [blame]
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}"),
}
}
}