use std::fmt::{self}; /* This file is acting as a bridge between the old neon types and how they * have a fairly complex way of picking suffixes and the new world. If possible * it would be good to clean this up. At least it is self contained and the * logic simple */ use crate::typekinds::{BaseType, BaseTypeKind, TypeKind, VectorType}; use serde::{Deserialize, Serialize}; use std::str::FromStr; #[allow(clippy::enum_variant_names)] #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)] pub enum SuffixKind { Normal, Base, NoQ, NSuffix, NoQNSuffix, DupNox, Dup, /* Get the number of lanes or panic if there are not any Lanes */ Lane, Rot270, Rot270Lane, Rot270LaneQ, Rot180, Rot180Lane, Rot180LaneQ, Rot90, Rot90Lane, Rot90LaneQ, /* Force the type to be unsigned */ Unsigned, Tuple, NoX, BaseByteSize, LaneNoX, LaneQNoX, } pub fn type_to_size(str_type: &str) -> i32 { match str_type { "int8x8_t" | "int8x16_t" | "i8" | "s8" | "uint8x8_t" | "uint8x16_t" | "u8" | "poly8x8_t" | "poly8x16_t" => 8, "int16x4_t" | "int16x8_t" | "i16" | "s16" | "uint16x4_t" | "uint16x8_t" | "u16" | "float16x4_t" | "float16x8_t" | "_f16" | "poly16x4_t" | "poly16x8_t" => 16, "int32x2_t" | "int32x4_t" | "i32" | "s32" | "uint32x2_t" | "uint32x4_t" | "u32" | "float32x2_t" | "float32x4_t" | "f32" => 32, "int64x1_t" | "int64x2_t" | "i64" | "s64" | "uint64x1_t" | "uint64x2_t" | "u64" | "float64x1_t" | "float64x2_t" | "f64" | "poly64x1_t" | "poly64x2_t" | "p64" => 64, "p128" => 128, _ => panic!("unknown type: {str_type}"), } } fn neon_get_base_and_char(ty: &VectorType) -> (u32, char, bool) { let lanes = ty.lanes(); match ty.base_type() { BaseType::Sized(BaseTypeKind::Float, size) => (*size, 'f', *size * lanes == 128), BaseType::Sized(BaseTypeKind::Int, size) => (*size, 's', *size * lanes == 128), BaseType::Sized(BaseTypeKind::UInt, size) => (*size, 'u', *size * lanes == 128), BaseType::Sized(BaseTypeKind::Poly, size) => (*size, 'p', *size * lanes == 128), _ => panic!("Unhandled {ty:?}"), } } /* @TODO * for the chained enum types we can safely delete them as we can index the * types array */ pub fn make_neon_suffix(type_kind: TypeKind, suffix_kind: SuffixKind) -> String { match type_kind { TypeKind::Vector(ty) => { let tuple_size = ty.tuple_size().map_or(0, |t| t.to_int()); let (base_size, prefix_char, requires_q) = neon_get_base_and_char(&ty); let prefix_q = if requires_q { "q" } else { "" }; let lanes = ty.lanes(); match suffix_kind { SuffixKind::Normal => { let mut str_suffix: String = format!("{prefix_q}_{prefix_char}{base_size}"); if tuple_size > 0 { str_suffix.push_str("_x"); str_suffix.push_str(tuple_size.to_string().as_str()); } str_suffix } SuffixKind::NSuffix => { format!("{prefix_q}_n_{prefix_char}{base_size}") } SuffixKind::NoQ => format!("_{prefix_char}{base_size}"), SuffixKind::NoQNSuffix => format!("_n{prefix_char}{base_size}"), SuffixKind::Unsigned => { let t = type_kind.to_string(); if t.starts_with("u") { return t; } format!("u{t}") } SuffixKind::Lane => { if lanes == 0 { panic!("type {type_kind} has no lanes!") } else { format!("{lanes}") } } SuffixKind::Tuple => { if tuple_size == 0 { panic!("type {type_kind} has no lanes!") } else { format!("{tuple_size}") } } SuffixKind::Base => base_size.to_string(), SuffixKind::NoX => { format!("{prefix_q}_{prefix_char}{base_size}") } SuffixKind::Dup => { let mut str_suffix: String = format!("{prefix_q}_dup_{prefix_char}{base_size}"); if tuple_size > 0 { str_suffix.push_str("_x"); str_suffix.push_str(tuple_size.to_string().as_str()); } str_suffix } SuffixKind::DupNox => { format!("{prefix_q}_dup_{prefix_char}{base_size}") } SuffixKind::LaneNoX => { format!("{prefix_q}_lane_{prefix_char}{base_size}") } SuffixKind::LaneQNoX => { format!("{prefix_q}_laneq_{prefix_char}{base_size}") } SuffixKind::Rot270 => { format!("{prefix_q}_rot270_{prefix_char}{base_size}") } SuffixKind::Rot270Lane => { format!("{prefix_q}_rot270_lane_{prefix_char}{base_size}") } SuffixKind::Rot270LaneQ => { format!("{prefix_q}_rot270_laneq_{prefix_char}{base_size}") } SuffixKind::Rot180 => { format!("{prefix_q}_rot180_{prefix_char}{base_size}") } SuffixKind::Rot180Lane => { format!("{prefix_q}_rot180_lane_{prefix_char}{base_size}") } SuffixKind::Rot180LaneQ => { format!("{prefix_q}_rot180_laneq_{prefix_char}{base_size}") } SuffixKind::Rot90 => { format!("{prefix_q}_rot90_{prefix_char}{base_size}") } SuffixKind::Rot90Lane => { format!("{prefix_q}_rot90_lane_{prefix_char}{base_size}") } SuffixKind::Rot90LaneQ => { format!("{prefix_q}_rot90_laneq_{prefix_char}{base_size}") } SuffixKind::BaseByteSize => format!("{}", base_size / 8), } } _ => panic!("Cannot only make neon vector types suffixed"), } } impl FromStr for SuffixKind { type Err = String; fn from_str(s: &str) -> Result { match s { "no" => Ok(SuffixKind::Normal), "noq" => Ok(SuffixKind::NoQ), "N" => Ok(SuffixKind::NSuffix), "noq_N" => Ok(SuffixKind::NoQNSuffix), "dup_nox" => Ok(SuffixKind::DupNox), "dup" => Ok(SuffixKind::Dup), "lane" => Ok(SuffixKind::Lane), "base" => Ok(SuffixKind::Base), "tuple" => Ok(SuffixKind::Tuple), "rot270" => Ok(SuffixKind::Rot270), "rot270_lane" => Ok(SuffixKind::Rot270Lane), "rot270_laneq" => Ok(SuffixKind::Rot270LaneQ), "rot90" => Ok(SuffixKind::Rot90), "rot90_lane" => Ok(SuffixKind::Rot90Lane), "rot90_laneq" => Ok(SuffixKind::Rot90LaneQ), "rot180" => Ok(SuffixKind::Rot180), "rot180_lane" => Ok(SuffixKind::Rot180LaneQ), "rot180_laneq" => Ok(SuffixKind::Rot180LaneQ), "u" => Ok(SuffixKind::Unsigned), "nox" => Ok(SuffixKind::NoX), "base_byte_size" => Ok(SuffixKind::BaseByteSize), "lane_nox" => Ok(SuffixKind::LaneNoX), "laneq_nox" => Ok(SuffixKind::LaneQNoX), _ => Err(format!("unknown suffix type: {s}")), } } } impl fmt::Display for SuffixKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SuffixKind::Normal => write!(f, "normal"), SuffixKind::NoQ => write!(f, "NoQ"), SuffixKind::NSuffix => write!(f, "NSuffix"), SuffixKind::NoQNSuffix => write!(f, "NoQNSuffix"), SuffixKind::DupNox => write!(f, "DupNox"), SuffixKind::Dup => write!(f, "Dup",), SuffixKind::Lane => write!(f, "Lane"), SuffixKind::LaneNoX => write!(f, "LaneNoX"), SuffixKind::LaneQNoX => write!(f, "LaneQNoX"), SuffixKind::Base => write!(f, "Base"), SuffixKind::Rot270 => write!(f, "Rot270",), SuffixKind::Rot270Lane => write!(f, "Rot270Lane"), SuffixKind::Rot270LaneQ => write!(f, "Rot270LaneQ"), SuffixKind::Rot90 => write!(f, "Rot90",), SuffixKind::Rot90Lane => write!(f, "Rot90Lane"), SuffixKind::Rot90LaneQ => write!(f, "Rot90LaneQ"), SuffixKind::Rot180 => write!(f, "Rot180",), SuffixKind::Rot180Lane => write!(f, "Rot180Lane"), SuffixKind::Rot180LaneQ => write!(f, "Rot180LaneQ"), SuffixKind::Unsigned => write!(f, "Unsigned"), SuffixKind::Tuple => write!(f, "Tuple"), SuffixKind::NoX => write!(f, "NoX"), SuffixKind::BaseByteSize => write!(f, "BaseByteSize"), } } }