#![allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum DetectionMethod {
Ipfp,
Registry,
Both,
}
#[doc(hidden)]
pub const fn const_bytes_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut i = 0;
while i < a.len() {
if a[i] != b[i] {
return false;
}
i += 1;
}
true
}
macro_rules! features {
($($variant:ident = ($bit:literal, $name:literal, $method:ident)),* $(,)?) => {
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum Feature {
$($variant = $bit,)*
}
const ALL_FEATURES: &[Feature] = &[$(Feature::$variant),*];
impl Feature {
pub const fn name(self) -> &'static str {
match self {
$(Feature::$variant => $name,)*
}
}
#[allow(dead_code, reason = "consumed by internal tests; classification is informational")]
pub(crate) const fn detection_method(self) -> DetectionMethod {
match self {
$(Feature::$variant => DetectionMethod::$method,)*
}
}
pub const fn from_name(name: &str) -> Option<Self> {
let bytes = name.as_bytes();
$(
if $crate::features::const_bytes_eq(bytes, $name.as_bytes()) {
return Some(Feature::$variant);
}
)*
None
}
pub fn all() -> impl Iterator<Item = Self> {
ALL_FEATURES.iter().copied()
}
}
};
}
features! {
Asimd = (0, "asimd", Ipfp),
Fp = (1, "fp", Ipfp),
Fp16 = (2, "fp16", Both),
Fhm = (3, "fhm", Registry),
Fcma = (4, "fcma", Registry),
Bf16 = (5, "bf16", Both),
I8mm = (6, "i8mm", Both),
JsConv = (7, "jsconv", Ipfp),
FrintTs = (8, "frintts", Registry),
Rdm = (9, "rdm", Both),
Dotprod = (10, "dotprod", Ipfp),
Aes = (11, "aes", Ipfp),
Pmull = (12, "pmull", Ipfp),
Sha2 = (13, "sha2", Ipfp),
Sha3 = (14, "sha3", Both),
Sm4 = (15, "sm4", Registry),
Crc = (16, "crc", Ipfp),
Lse = (17, "lse", Ipfp),
Lse2 = (18, "lse2", Both),
Lse128 = (19, "lse128", Registry),
Rcpc = (20, "rcpc", Ipfp),
Rcpc2 = (21, "rcpc2", Registry),
Rcpc3 = (22, "rcpc3", Registry),
Paca = (23, "paca", Registry),
Pacg = (24, "pacg", Registry),
PauthLr = (25, "pauth-lr", Registry),
Bti = (26, "bti", Registry),
Dpb = (27, "dpb", Registry),
Dpb2 = (28, "dpb2", Registry),
Mte = (29, "mte", Registry),
Mops = (30, "mops", Registry),
Dit = (31, "dit", Registry),
Sb = (32, "sb", Registry),
Ssbs = (33, "ssbs", Registry),
FlagM = (34, "flagm", Registry),
FlagM2 = (35, "flagm2", Registry),
Rand = (36, "rand", Registry),
Tme = (37, "tme", Registry),
Ecv = (38, "ecv", Registry),
Cssc = (39, "cssc", Registry),
WfxT = (40, "wfxt", Registry),
Hbc = (41, "hbc", Registry),
Lut = (42, "lut", Registry),
FaMinMax = (43, "faminmax", Registry),
Fp8 = (44, "fp8", Registry),
Fp8Dot2 = (45, "fp8dot2", Registry),
Fp8Dot4 = (46, "fp8dot4", Registry),
Fp8Fma = (47, "fp8fma", Registry),
Fpmr = (48, "fpmr", Registry),
Sve = (49, "sve", Ipfp),
Sve2 = (50, "sve2", Ipfp),
Sve2p1 = (51, "sve2p1", Ipfp),
Sve2Aes = (52, "sve2-aes", Ipfp),
Sve2Bitperm= (53, "sve2-bitperm", Ipfp),
Sve2Sha3 = (54, "sve2-sha3", Ipfp),
Sve2Sm4 = (55, "sve2-sm4", Ipfp),
SveB16b16 = (56, "sve-b16b16", Ipfp),
F32mm = (57, "f32mm", Ipfp),
F64mm = (58, "f64mm", Ipfp),
Sme = (59, "sme", Both),
Sme2 = (60, "sme2", Ipfp),
Sme2p1 = (61, "sme2p1", Ipfp),
SmeB16b16 = (62, "sme-b16b16", Ipfp),
SmeF64f64 = (64, "sme-f64f64", Ipfp),
SmeF8f16 = (65, "sme-f8f16", Ipfp),
SmeF8f32 = (66, "sme-f8f32", Ipfp),
SmeFa64 = (67, "sme-fa64", Ipfp),
SmeI16i64 = (68, "sme-i16i64", Ipfp),
SmeLutv2 = (69, "sme-lutv2", Ipfp),
SsveFp8Dot2= (70, "ssve-fp8dot2", Ipfp),
SsveFp8Dot4= (71, "ssve-fp8dot4", Ipfp),
SsveFp8Fma = (72, "ssve-fp8fma", Ipfp),
SmeF16f16 = (73, "sme-f16f16", Ipfp),
}
const _: () = {
let mut i = 0;
while i < ALL_FEATURES.len() {
let bit = ALL_FEATURES[i] as u8;
assert!(
bit < 128,
"Feature discriminant out of range: must be in 0..128"
);
assert!(
bit != 63,
"Feature occupies bit 63, reserved as `INIT_BIT` in `lo` — pick a different discriminant",
);
assert!(
bit != 127,
"Feature occupies bit 127, reserved as `INIT_BIT` in `hi` — pick a different discriminant",
);
let mut j = i + 1;
while j < ALL_FEATURES.len() {
assert!(
(ALL_FEATURES[i] as u8) != (ALL_FEATURES[j] as u8),
"Two features share the same discriminant — discriminants must be unique",
);
j += 1;
}
i += 1;
}
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_features_roundtrip_name() {
for f in Feature::all() {
assert_eq!(Feature::from_name(f.name()), Some(f), "{}", f.name());
}
}
#[test]
fn every_feature_has_detection_method() {
for f in Feature::all() {
let _ = f.detection_method();
}
}
}