use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ArmArch {
Armv8_0A,
Armv8_1A,
Armv8_2A,
Armv8_3A,
Armv8_4A,
Armv8_5A,
Armv8_6A,
Armv8_7A,
Armv8_8A,
Armv8_9A,
Armv9_0A,
Armv9_1A,
Armv9_2A,
Armv9_3A,
Armv9_4A,
}
impl ArmArch {
pub fn min_for_feature(feat: ArmFeature) -> Option<ArmArch> {
match feat {
ArmFeature::LSE => Some(ArmArch::Armv8_1A),
ArmFeature::RAS => Some(ArmArch::Armv8_2A),
ArmFeature::FP16 => Some(ArmArch::Armv8_2A),
ArmFeature::DotProd => Some(ArmArch::Armv8_2A),
ArmFeature::RCPC => Some(ArmArch::Armv8_3A),
ArmFeature::PAuth => Some(ArmArch::Armv8_3A),
ArmFeature::FlagM => Some(ArmArch::Armv8_4A),
ArmFeature::RDM => Some(ArmArch::Armv8_1A),
ArmFeature::MTE => Some(ArmArch::Armv8_5A),
ArmFeature::SVE => Some(ArmArch::Armv8_2A),
ArmFeature::SVE2 => Some(ArmArch::Armv9_0A),
ArmFeature::SME => Some(ArmArch::Armv9_0A),
ArmFeature::SME2 => Some(ArmArch::Armv9_2A),
ArmFeature::THE => Some(ArmArch::Armv8_8A),
ArmFeature::GCS => Some(ArmArch::Armv9_4A),
ArmFeature::FP8 => Some(ArmArch::Armv9_4A),
ArmFeature::FAMINMAX => Some(ArmArch::Armv9_2A),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArmFeature {
FP, ASIMD, CRC, Crypto,
LSE, RDM, LRCPC,
FP16, FullFP16, DotProd, RCPC, RAS, SVE, LSE2,
PAuth, FCMLA, FJCVTZS,
FlagM, FlagM2, DIT, LRCPC2, NV,
MTE, FRINTTS, SB, SSBS, PREDRES,
BTI, ECV, FGT, AMU,
WFXT, XS,
THE, MOPS,
LRCPC3, SPECRES2, RME,
SVE2, SME, TME,
SME2, FAMINMAX, LUT, BF16, I8MM, F32MM, F64MM,
MTE2, MTE3, BRBE,
FP8, GCS, CHK, LRCPC4,
AppleAES, }
impl ArmFeature {
pub fn dependencies(&self) -> &[ArmFeature] {
match self {
ArmFeature::ASIMD => &[ArmFeature::FP],
ArmFeature::FP16 => &[ArmFeature::FP, ArmFeature::ASIMD],
ArmFeature::FullFP16 => &[ArmFeature::FP16, ArmFeature::ASIMD],
ArmFeature::DotProd => &[ArmFeature::ASIMD],
ArmFeature::SVE => &[ArmFeature::FP, ArmFeature::ASIMD],
ArmFeature::SVE2 => &[ArmFeature::SVE],
ArmFeature::SME => &[ArmFeature::SVE, ArmFeature::BF16],
ArmFeature::SME2 => &[ArmFeature::SME],
ArmFeature::I8MM => &[ArmFeature::ASIMD],
ArmFeature::F32MM => &[ArmFeature::SVE],
ArmFeature::F64MM => &[ArmFeature::SVE],
ArmFeature::FlagM2 => &[ArmFeature::FlagM],
ArmFeature::LRCPC2 => &[ArmFeature::LRCPC],
ArmFeature::LRCPC3 => &[ArmFeature::LRCPC2],
ArmFeature::LRCPC4 => &[ArmFeature::LRCPC3],
ArmFeature::MTE2 => &[ArmFeature::MTE],
ArmFeature::MTE3 => &[ArmFeature::MTE2],
ArmFeature::SPECRES2 => &[ArmFeature::PREDRES],
_ => &[],
}
}
pub fn name(&self) -> &str {
match self {
ArmFeature::FP => "fp",
ArmFeature::ASIMD => "asimd",
ArmFeature::CRC => "crc",
ArmFeature::Crypto => "crypto",
ArmFeature::LSE => "lse",
ArmFeature::RDM => "rdm",
ArmFeature::LRCPC => "lrcpc",
ArmFeature::FP16 => "fp16",
ArmFeature::FullFP16 => "fullfp16",
ArmFeature::DotProd => "dotprod",
ArmFeature::RCPC => "rcpc",
ArmFeature::RAS => "ras",
ArmFeature::SVE => "sve",
ArmFeature::LSE2 => "lse2",
ArmFeature::PAuth => "pauth",
ArmFeature::FCMLA => "fcmla",
ArmFeature::FJCVTZS => "fjcvtzs",
ArmFeature::FlagM => "flagm",
ArmFeature::FlagM2 => "flagm2",
ArmFeature::DIT => "dit",
ArmFeature::LRCPC2 => "lrcpc2",
ArmFeature::NV => "nv",
ArmFeature::MTE => "mte",
ArmFeature::FRINTTS => "frintts",
ArmFeature::SB => "sb",
ArmFeature::SSBS => "ssbs",
ArmFeature::PREDRES => "predres",
ArmFeature::BTI => "bti",
ArmFeature::ECV => "ecv",
ArmFeature::FGT => "fgt",
ArmFeature::AMU => "amu",
ArmFeature::WFXT => "wfxt",
ArmFeature::XS => "xs",
ArmFeature::THE => "the",
ArmFeature::MOPS => "mops",
ArmFeature::LRCPC3 => "lrcpc3",
ArmFeature::SPECRES2 => "specres2",
ArmFeature::RME => "rme",
ArmFeature::SVE2 => "sve2",
ArmFeature::SME => "sme",
ArmFeature::TME => "tme",
ArmFeature::SME2 => "sme2",
ArmFeature::FAMINMAX => "faminmax",
ArmFeature::LUT => "lut",
ArmFeature::BF16 => "bf16",
ArmFeature::I8MM => "i8mm",
ArmFeature::F32MM => "f32mm",
ArmFeature::F64MM => "f64mm",
ArmFeature::MTE2 => "mte2",
ArmFeature::MTE3 => "mte3",
ArmFeature::BRBE => "brbe",
ArmFeature::FP8 => "fp8",
ArmFeature::GCS => "gcs",
ArmFeature::CHK => "chk",
ArmFeature::LRCPC4 => "lrcpc4",
ArmFeature::AppleAES => "apple-aes",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArmCpu {
CortexA53,
CortexA55,
CortexA57,
CortexA65,
CortexA65AE,
CortexA72,
CortexA73,
CortexA75,
CortexA76,
CortexA76AE,
CortexA77,
CortexA78,
CortexA78AE,
CortexA78C,
CortexA710,
CortexA715,
CortexA720,
CortexA725,
CortexA520,
CortexX1,
CortexX1C,
CortexX2,
CortexX3,
CortexX4,
CortexX925,
NeoverseN1,
NeoverseN2,
NeoverseV1,
NeoverseV2,
NeoverseV3,
NeoverseE1,
NeoverseE2,
AppleA7,
AppleA8,
AppleA9,
AppleA10,
AppleA11,
AppleA12,
AppleA13,
AppleA14,
AppleA15,
AppleA16,
AppleA17,
AppleA18,
AppleM1,
AppleM2,
AppleM3,
AppleM4,
AppleM1Pro,
AppleM1Max,
AppleM1Ultra,
AppleM2Pro,
AppleM2Max,
AppleM2Ultra,
AppleM3Pro,
AppleM3Max,
AppleM3Ultra,
AppleM4Pro,
AppleM4Max,
Kryo3xx,
Kryo4xx,
Kryo5xx,
Kryo6xx,
Oryon,
Snapdragon8Gen1,
Snapdragon8Gen2,
Snapdragon8Gen3,
SnapdragonXElite,
ExynosM3,
ExynosM4,
ExynosM5,
Exynos2200,
Exynos2400,
Dimensity9000,
Dimensity9200,
Dimensity9300,
Grace,
TegraOrin,
Ampere1,
Ampere1A,
AmpereOne,
Altra,
AltraMax,
Graviton1,
Graviton2,
Graviton3,
Graviton4,
TensorG1,
TensorG2,
TensorG3,
SQ1,
SQ2,
SQ3,
FujitsuA64FX,
ThunderX2T99,
ThunderX3T110,
ThunderXT88,
HisiliconTSV110,
MarvellTX3,
Generic,
}
impl ArmCpu {
pub fn name(&self) -> &str {
match self {
ArmCpu::CortexA53 => "cortex-a53",
ArmCpu::CortexA55 => "cortex-a55",
ArmCpu::CortexA57 => "cortex-a57",
ArmCpu::CortexA65 => "cortex-a65",
ArmCpu::CortexA65AE => "cortex-a65ae",
ArmCpu::CortexA72 => "cortex-a72",
ArmCpu::CortexA73 => "cortex-a73",
ArmCpu::CortexA75 => "cortex-a75",
ArmCpu::CortexA76 => "cortex-a76",
ArmCpu::CortexA76AE => "cortex-a76ae",
ArmCpu::CortexA77 => "cortex-a77",
ArmCpu::CortexA78 => "cortex-a78",
ArmCpu::CortexA78AE => "cortex-a78ae",
ArmCpu::CortexA78C => "cortex-a78c",
ArmCpu::CortexA710 => "cortex-a710",
ArmCpu::CortexA715 => "cortex-a715",
ArmCpu::CortexA720 => "cortex-a720",
ArmCpu::CortexA725 => "cortex-a725",
ArmCpu::CortexA520 => "cortex-a520",
ArmCpu::CortexX1 => "cortex-x1",
ArmCpu::CortexX1C => "cortex-x1c",
ArmCpu::CortexX2 => "cortex-x2",
ArmCpu::CortexX3 => "cortex-x3",
ArmCpu::CortexX4 => "cortex-x4",
ArmCpu::CortexX925 => "cortex-x925",
ArmCpu::NeoverseN1 => "neoverse-n1",
ArmCpu::NeoverseN2 => "neoverse-n2",
ArmCpu::NeoverseV1 => "neoverse-v1",
ArmCpu::NeoverseV2 => "neoverse-v2",
ArmCpu::NeoverseV3 => "neoverse-v3",
ArmCpu::NeoverseE1 => "neoverse-e1",
ArmCpu::NeoverseE2 => "neoverse-e2",
ArmCpu::AppleA7 => "apple-a7",
ArmCpu::AppleA8 => "apple-a8",
ArmCpu::AppleA9 => "apple-a9",
ArmCpu::AppleA10 => "apple-a10",
ArmCpu::AppleA11 => "apple-a11",
ArmCpu::AppleA12 => "apple-a12",
ArmCpu::AppleA13 => "apple-a13",
ArmCpu::AppleA14 => "apple-a14",
ArmCpu::AppleA15 => "apple-a15",
ArmCpu::AppleA16 => "apple-a16",
ArmCpu::AppleA17 => "apple-a17",
ArmCpu::AppleA18 => "apple-a18",
ArmCpu::AppleM1 => "apple-m1",
ArmCpu::AppleM2 => "apple-m2",
ArmCpu::AppleM3 => "apple-m3",
ArmCpu::AppleM4 => "apple-m4",
ArmCpu::AppleM1Pro => "apple-m1-pro",
ArmCpu::AppleM1Max => "apple-m1-max",
ArmCpu::AppleM1Ultra => "apple-m1-ultra",
ArmCpu::AppleM2Pro => "apple-m2-pro",
ArmCpu::AppleM2Max => "apple-m2-max",
ArmCpu::AppleM2Ultra => "apple-m2-ultra",
ArmCpu::AppleM3Pro => "apple-m3-pro",
ArmCpu::AppleM3Max => "apple-m3-max",
ArmCpu::AppleM3Ultra => "apple-m3-ultra",
ArmCpu::AppleM4Pro => "apple-m4-pro",
ArmCpu::AppleM4Max => "apple-m4-max",
ArmCpu::Kryo3xx => "kryo-3xx",
ArmCpu::Kryo4xx => "kryo-4xx",
ArmCpu::Kryo5xx => "kryo-5xx",
ArmCpu::Kryo6xx => "kryo-6xx",
ArmCpu::Oryon => "oryon",
ArmCpu::Snapdragon8Gen1 => "snapdragon-8gen1",
ArmCpu::Snapdragon8Gen2 => "snapdragon-8gen2",
ArmCpu::Snapdragon8Gen3 => "snapdragon-8gen3",
ArmCpu::SnapdragonXElite => "snapdragon-x-elite",
ArmCpu::ExynosM3 => "exynos-m3",
ArmCpu::ExynosM4 => "exynos-m4",
ArmCpu::ExynosM5 => "exynos-m5",
ArmCpu::Exynos2200 => "exynos-2200",
ArmCpu::Exynos2400 => "exynos-2400",
ArmCpu::ThunderX2T99 => "thunderx2t99",
ArmCpu::ThunderX3T110 => "thunderx3t110",
ArmCpu::ThunderXT88 => "thunderxt88",
ArmCpu::Ampere1 => "ampere1",
ArmCpu::Ampere1A => "ampere1a",
ArmCpu::Grace => "grace",
ArmCpu::FujitsuA64FX => "a64fx",
ArmCpu::HisiliconTSV110 => "tsv110",
ArmCpu::MarvellTX3 => "thunderx3t110",
ArmCpu::Dimensity9000 => "dimensity-9000",
ArmCpu::Dimensity9200 => "dimensity-9200",
ArmCpu::Dimensity9300 => "dimensity-9300",
ArmCpu::TegraOrin => "tegra-orin",
ArmCpu::AmpereOne => "ampere-one",
ArmCpu::Altra => "altra",
ArmCpu::AltraMax => "altra-max",
ArmCpu::Graviton1 => "graviton1",
ArmCpu::Graviton2 => "graviton2",
ArmCpu::Graviton3 => "graviton3",
ArmCpu::Graviton4 => "graviton4",
ArmCpu::TensorG1 => "tensor-g1",
ArmCpu::TensorG2 => "tensor-g2",
ArmCpu::TensorG3 => "tensor-g3",
ArmCpu::SQ1 => "sq1",
ArmCpu::SQ2 => "sq2",
ArmCpu::SQ3 => "sq3",
ArmCpu::Generic => "generic",
}
}
pub fn arch(&self) -> ArmArch {
match self {
ArmCpu::CortexA53 | ArmCpu::CortexA57 => ArmArch::Armv8_0A,
ArmCpu::CortexA72 | ArmCpu::CortexA73 => ArmArch::Armv8_0A,
ArmCpu::CortexA55 | ArmCpu::CortexA75 => ArmArch::Armv8_2A,
ArmCpu::CortexA76 | ArmCpu::CortexA76AE => ArmArch::Armv8_2A,
ArmCpu::CortexA77 | ArmCpu::CortexA78 | ArmCpu::CortexA78AE | ArmCpu::CortexA78C => {
ArmArch::Armv8_2A
}
ArmCpu::CortexA710 => ArmArch::Armv9_0A,
ArmCpu::CortexA715 => ArmArch::Armv9_0A,
ArmCpu::CortexA720 | ArmCpu::CortexA725 => ArmArch::Armv9_2A,
ArmCpu::CortexA520 => ArmArch::Armv9_2A,
ArmCpu::CortexX1 | ArmCpu::CortexX1C | ArmCpu::CortexX2 => ArmArch::Armv9_0A,
ArmCpu::CortexX3 => ArmArch::Armv9_2A,
ArmCpu::CortexX4 | ArmCpu::CortexX925 => ArmArch::Armv9_2A,
ArmCpu::NeoverseN1 => ArmArch::Armv8_2A,
ArmCpu::NeoverseN2 => ArmArch::Armv9_0A,
ArmCpu::NeoverseV1 => ArmArch::Armv8_4A,
ArmCpu::NeoverseV2 => ArmArch::Armv9_0A,
ArmCpu::NeoverseV3 => ArmArch::Armv9_2A,
ArmCpu::NeoverseE1 | ArmCpu::NeoverseE2 => ArmArch::Armv8_2A,
ArmCpu::AppleA7 | ArmCpu::AppleA8 => ArmArch::Armv8_0A,
ArmCpu::AppleA9 | ArmCpu::AppleA10 => ArmArch::Armv8_0A,
ArmCpu::AppleA11 => ArmArch::Armv8_2A,
ArmCpu::AppleA12 | ArmCpu::AppleA13 => ArmArch::Armv8_3A,
ArmCpu::AppleA14
| ArmCpu::AppleM1
| ArmCpu::AppleM1Pro
| ArmCpu::AppleM1Max
| ArmCpu::AppleM1Ultra => ArmArch::Armv8_5A,
ArmCpu::AppleA15
| ArmCpu::AppleM2
| ArmCpu::AppleM2Pro
| ArmCpu::AppleM2Max
| ArmCpu::AppleM2Ultra => ArmArch::Armv8_6A,
ArmCpu::AppleA16 => ArmArch::Armv8_6A,
ArmCpu::AppleA17
| ArmCpu::AppleA18
| ArmCpu::AppleM3
| ArmCpu::AppleM3Pro
| ArmCpu::AppleM3Max
| ArmCpu::AppleM3Ultra => ArmArch::Armv8_6A,
ArmCpu::AppleM4 | ArmCpu::AppleM4Pro | ArmCpu::AppleM4Max => ArmArch::Armv9_2A,
ArmCpu::FujitsuA64FX => ArmArch::Armv8_2A,
ArmCpu::Ampere1
| ArmCpu::Ampere1A
| ArmCpu::AmpereOne
| ArmCpu::Grace
| ArmCpu::Altra
| ArmCpu::AltraMax => ArmArch::Armv8_6A,
ArmCpu::Graviton1 => ArmArch::Armv8_0A,
ArmCpu::Graviton2 => ArmArch::Armv8_2A,
ArmCpu::Graviton3 => ArmArch::Armv8_4A,
ArmCpu::Graviton4 => ArmArch::Armv9_2A,
ArmCpu::TensorG1 => ArmArch::Armv8_2A,
ArmCpu::TensorG2 => ArmArch::Armv9_0A,
ArmCpu::TensorG3 => ArmArch::Armv9_2A,
ArmCpu::SQ1 | ArmCpu::SQ2 => ArmArch::Armv8_0A,
ArmCpu::SQ3 => ArmArch::Armv8_2A,
ArmCpu::Exynos2200 => ArmArch::Armv9_0A,
ArmCpu::Exynos2400 => ArmArch::Armv9_2A,
ArmCpu::Dimensity9000 => ArmArch::Armv9_0A,
ArmCpu::Dimensity9200 => ArmArch::Armv9_0A,
ArmCpu::Dimensity9300 => ArmArch::Armv9_2A,
ArmCpu::TegraOrin => ArmArch::Armv8_6A,
ArmCpu::Snapdragon8Gen1 => ArmArch::Armv9_0A,
ArmCpu::Snapdragon8Gen2 => ArmArch::Armv9_0A,
ArmCpu::Snapdragon8Gen3 => ArmArch::Armv9_2A,
ArmCpu::SnapdragonXElite => ArmArch::Armv9_2A,
_ => ArmArch::Armv8_0A,
}
}
pub fn core_name(&self) -> &str {
match self {
ArmCpu::AppleA14
| ArmCpu::AppleM1
| ArmCpu::AppleM1Pro
| ArmCpu::AppleM1Max
| ArmCpu::AppleM1Ultra => "firestorm",
ArmCpu::AppleA15 | ArmCpu::AppleM2 | ArmCpu::AppleM2Pro | ArmCpu::AppleM2Max => {
"avalanche"
}
ArmCpu::AppleA16 => "everest",
ArmCpu::AppleA17
| ArmCpu::AppleA18
| ArmCpu::AppleM3
| ArmCpu::AppleM3Pro
| ArmCpu::AppleM3Max
| ArmCpu::AppleM3Ultra => "sawtooth",
ArmCpu::AppleM4 | ArmCpu::AppleM4Pro | ArmCpu::AppleM4Max => "donan",
ArmCpu::CortexA53 => "apollo",
ArmCpu::CortexA55 => "ananke",
ArmCpu::CortexA57 => "atlas",
ArmCpu::CortexA72 => "maia",
ArmCpu::CortexA73 => "artemis",
ArmCpu::CortexA75 => "prometheus",
ArmCpu::CortexA76 | ArmCpu::CortexA76AE => "enyon",
ArmCpu::CortexA77 => "deimos",
ArmCpu::CortexA78 | ArmCpu::CortexA78AE | ArmCpu::CortexA78C => "hercules",
ArmCpu::CortexA710 => "matterhorn",
ArmCpu::CortexA715 => "makalu",
ArmCpu::CortexA720 => "kryo",
ArmCpu::CortexX1 | ArmCpu::CortexX1C => "hunter",
ArmCpu::CortexX2 => "matterhorn-elite",
ArmCpu::CortexX3 => "makalu-elite",
ArmCpu::CortexX4 => "blackhawk",
ArmCpu::CortexX925 => "cortex-x925",
_ => self.name(),
}
}
pub fn features(&self) -> Vec<ArmFeature> {
let mut feats = Vec::new();
feats.push(ArmFeature::FP);
feats.push(ArmFeature::ASIMD);
feats.push(ArmFeature::CRC);
match self {
ArmCpu::CortexA53 | ArmCpu::CortexA57 => {
feats.push(ArmFeature::Crypto);
}
ArmCpu::CortexA55 | ArmCpu::CortexA72 | ArmCpu::CortexA73 | ArmCpu::CortexA75 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::RDM);
}
ArmCpu::CortexA76
| ArmCpu::CortexA76AE
| ArmCpu::CortexA77
| ArmCpu::CortexA78
| ArmCpu::CortexA78AE
| ArmCpu::CortexA78C => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::RAS);
}
ArmCpu::CortexA710
| ArmCpu::CortexA715
| ArmCpu::CortexX1
| ArmCpu::CortexX1C
| ArmCpu::CortexX2 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RAS);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::BTI);
}
ArmCpu::CortexA720
| ArmCpu::CortexA725
| ArmCpu::CortexX3
| ArmCpu::CortexX4
| ArmCpu::CortexX925 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RAS);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::BTI);
feats.push(ArmFeature::I8MM);
feats.push(ArmFeature::BF16);
}
ArmCpu::NeoverseN1 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::RAS);
}
ArmCpu::NeoverseN2 | ArmCpu::NeoverseV1 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RAS);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::BTI);
}
ArmCpu::NeoverseV2 | ArmCpu::NeoverseV3 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RAS);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::BTI);
feats.push(ArmFeature::I8MM);
feats.push(ArmFeature::BF16);
}
ArmCpu::AppleA12 | ArmCpu::AppleA13 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::AppleAES);
}
ArmCpu::AppleA14
| ArmCpu::AppleM1
| ArmCpu::AppleM1Pro
| ArmCpu::AppleM1Max
| ArmCpu::AppleM1Ultra => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::FullFP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::PAuth);
feats.push(ArmFeature::FlagM);
feats.push(ArmFeature::FRINTTS);
feats.push(ArmFeature::AppleAES);
}
ArmCpu::AppleA15
| ArmCpu::AppleM2
| ArmCpu::AppleM2Pro
| ArmCpu::AppleM2Max
| ArmCpu::AppleM2Ultra => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::FullFP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::PAuth);
feats.push(ArmFeature::FlagM);
feats.push(ArmFeature::FlagM2);
feats.push(ArmFeature::FRINTTS);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::AppleAES);
}
ArmCpu::AppleA16 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::FullFP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::PAuth);
feats.push(ArmFeature::FlagM);
feats.push(ArmFeature::FlagM2);
feats.push(ArmFeature::FRINTTS);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
feats.push(ArmFeature::AppleAES);
}
ArmCpu::AppleA17
| ArmCpu::AppleA18
| ArmCpu::AppleM3
| ArmCpu::AppleM3Pro
| ArmCpu::AppleM3Max
| ArmCpu::AppleM3Ultra => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::FullFP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::PAuth);
feats.push(ArmFeature::FlagM);
feats.push(ArmFeature::FlagM2);
feats.push(ArmFeature::FRINTTS);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
feats.push(ArmFeature::AppleAES);
}
ArmCpu::AppleM4 | ArmCpu::AppleM4Pro | ArmCpu::AppleM4Max => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::FullFP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::PAuth);
feats.push(ArmFeature::FlagM);
feats.push(ArmFeature::FlagM2);
feats.push(ArmFeature::FRINTTS);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::SME);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
feats.push(ArmFeature::FP8);
feats.push(ArmFeature::AppleAES);
}
ArmCpu::Graviton1 => {
feats.push(ArmFeature::Crypto);
}
ArmCpu::Graviton2 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::RDM);
}
ArmCpu::Graviton3 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::RDM);
}
ArmCpu::Graviton4 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::SME);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
}
ArmCpu::TensorG1 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::RDM);
}
ArmCpu::TensorG2 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::MTE);
}
ArmCpu::TensorG3 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::BF16);
}
ArmCpu::SQ1 | ArmCpu::SQ2 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::LSE);
}
ArmCpu::SQ3 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::RDM);
}
ArmCpu::Exynos2200 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
}
ArmCpu::Exynos2400 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
}
ArmCpu::Dimensity9000 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
}
ArmCpu::Dimensity9200 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::BTI);
}
ArmCpu::Dimensity9300 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::BTI);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
}
ArmCpu::TegraOrin => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
}
ArmCpu::AmpereOne | ArmCpu::Altra | ArmCpu::AltraMax => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::RAS);
}
ArmCpu::Snapdragon8Gen1 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
}
ArmCpu::Snapdragon8Gen2 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
}
ArmCpu::Snapdragon8Gen3 => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
}
ArmCpu::SnapdragonXElite => {
feats.push(ArmFeature::Crypto);
feats.push(ArmFeature::FP16);
feats.push(ArmFeature::DotProd);
feats.push(ArmFeature::LSE);
feats.push(ArmFeature::LSE2);
feats.push(ArmFeature::RCPC);
feats.push(ArmFeature::RDM);
feats.push(ArmFeature::SVE);
feats.push(ArmFeature::SVE2);
feats.push(ArmFeature::MTE);
feats.push(ArmFeature::MTE2);
feats.push(ArmFeature::BF16);
feats.push(ArmFeature::I8MM);
}
_ => {
feats.push(ArmFeature::Crypto);
}
}
feats
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ArmTuning {
pub pref_function_alignment: u32,
pub pref_loop_alignment: u32,
pub max_bytes_for_loop_alignment: u32,
pub use_sw_pipelining: bool,
pub prefer_predicated_execution: bool,
pub enable_loop_fusion: bool,
pub fuse_aes: bool,
pub fuse_literals: bool,
pub fuse_address: bool,
pub machine_scheduler: bool,
pub post_ra_scheduler: bool,
pub dispatch_width: u32,
pub ldst_issue_width: u32,
pub num_int_pipes: u32,
pub num_fp_pipes: u32,
}
impl Default for ArmTuning {
fn default() -> Self {
ArmTuning {
pref_function_alignment: 16,
pref_loop_alignment: 16,
max_bytes_for_loop_alignment: 16,
use_sw_pipelining: false,
prefer_predicated_execution: false,
enable_loop_fusion: false,
fuse_aes: false,
fuse_literals: false,
fuse_address: false,
machine_scheduler: true,
post_ra_scheduler: false,
dispatch_width: 2,
ldst_issue_width: 1,
num_int_pipes: 2,
num_fp_pipes: 2,
}
}
}
impl ArmCpu {
pub fn tuning(&self) -> ArmTuning {
let base = ArmTuning::default();
match self {
ArmCpu::CortexA53 | ArmCpu::CortexA55 | ArmCpu::CortexA520 => ArmTuning {
pref_function_alignment: 16,
pref_loop_alignment: 16,
max_bytes_for_loop_alignment: 16,
dispatch_width: 2,
ldst_issue_width: 1,
num_int_pipes: 2,
num_fp_pipes: 1,
..base
},
ArmCpu::CortexA57 | ArmCpu::CortexA72 => ArmTuning {
pref_function_alignment: 32,
pref_loop_alignment: 16,
max_bytes_for_loop_alignment: 32,
dispatch_width: 3,
ldst_issue_width: 1,
num_int_pipes: 2,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
..base
},
ArmCpu::CortexA73 | ArmCpu::CortexA75 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 16,
max_bytes_for_loop_alignment: 32,
dispatch_width: 3,
ldst_issue_width: 1,
num_int_pipes: 3,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
..base
},
ArmCpu::CortexA76
| ArmCpu::CortexA76AE
| ArmCpu::CortexA77
| ArmCpu::CortexA78
| ArmCpu::CortexA78AE
| ArmCpu::CortexA78C => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::CortexA710 | ArmCpu::CortexA715 | ArmCpu::CortexA720 | ArmCpu::CortexA725 => {
ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 5,
ldst_issue_width: 2,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
}
}
ArmCpu::CortexX1 | ArmCpu::CortexX1C | ArmCpu::CortexX2 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 5,
ldst_issue_width: 2,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::CortexX3 | ArmCpu::CortexX4 | ArmCpu::CortexX925 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 3,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::NeoverseN1 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
..base
},
ArmCpu::NeoverseN2 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 5,
ldst_issue_width: 2,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::NeoverseV1 | ArmCpu::NeoverseV2 | ArmCpu::NeoverseV3 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 3,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::AppleA12 | ArmCpu::AppleA13 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 6,
ldst_issue_width: 2,
num_int_pipes: 6,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
..base
},
ArmCpu::AppleA14
| ArmCpu::AppleM1
| ArmCpu::AppleM1Pro
| ArmCpu::AppleM1Max
| ArmCpu::AppleM1Ultra => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 3,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::AppleA15
| ArmCpu::AppleA16
| ArmCpu::AppleM2
| ArmCpu::AppleM2Pro
| ArmCpu::AppleM2Max
| ArmCpu::AppleM2Ultra => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 3,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::AppleA17
| ArmCpu::AppleA18
| ArmCpu::AppleM3
| ArmCpu::AppleM3Pro
| ArmCpu::AppleM3Max
| ArmCpu::AppleM3Ultra => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 9,
ldst_issue_width: 4,
num_int_pipes: 8,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::AppleM4 | ArmCpu::AppleM4Pro | ArmCpu::AppleM4Max => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 10,
ldst_issue_width: 4,
num_int_pipes: 9,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::Snapdragon8Gen1 | ArmCpu::Snapdragon8Gen2 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 6,
ldst_issue_width: 3,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::Snapdragon8Gen3 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 4,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::SnapdragonXElite => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 10,
ldst_issue_width: 4,
num_int_pipes: 8,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::Exynos2200 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 6,
ldst_issue_width: 3,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::Exynos2400 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 4,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::Dimensity9000 | ArmCpu::Dimensity9200 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 6,
ldst_issue_width: 3,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::Dimensity9300 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 4,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::Grace => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 3,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::TegraOrin => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
machine_scheduler: true,
..base
},
ArmCpu::Altra | ArmCpu::AltraMax => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
..base
},
ArmCpu::AmpereOne => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 3,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::Graviton1 => ArmTuning {
pref_function_alignment: 16,
pref_loop_alignment: 16,
max_bytes_for_loop_alignment: 16,
dispatch_width: 2,
ldst_issue_width: 1,
num_int_pipes: 2,
num_fp_pipes: 1,
..base
},
ArmCpu::Graviton2 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
..base
},
ArmCpu::Graviton3 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 6,
ldst_issue_width: 3,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::Graviton4 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 8,
ldst_issue_width: 4,
num_int_pipes: 6,
num_fp_pipes: 4,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
post_ra_scheduler: true,
..base
},
ArmCpu::TensorG1 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
..base
},
ArmCpu::TensorG2 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 5,
ldst_issue_width: 2,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
machine_scheduler: true,
..base
},
ArmCpu::TensorG3 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 6,
ldst_issue_width: 3,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
fuse_address: true,
machine_scheduler: true,
..base
},
ArmCpu::SQ1 | ArmCpu::SQ2 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 64,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
fuse_literals: true,
..base
},
ArmCpu::SQ3 => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 5,
ldst_issue_width: 2,
num_int_pipes: 5,
num_fp_pipes: 3,
fuse_aes: true,
fuse_literals: true,
machine_scheduler: true,
..base
},
ArmCpu::FujitsuA64FX => ArmTuning {
pref_function_alignment: 64,
pref_loop_alignment: 64,
max_bytes_for_loop_alignment: 128,
dispatch_width: 4,
ldst_issue_width: 2,
num_int_pipes: 4,
num_fp_pipes: 2,
fuse_aes: true,
use_sw_pipelining: true,
..base
},
_ => base,
}
}
}
#[derive(Debug, Clone)]
pub struct ArmSubtarget {
pub cpu: ArmCpu,
pub arch: ArmArch,
pub features: HashMap<ArmFeature, bool>,
pub tuning: ArmTuning,
pub is_64bit: bool,
pub min_sve_vl: u32,
pub max_sve_vl: u32,
pub has_streaming_sve: bool,
pub streaming_sve_vl: u32,
}
impl ArmSubtarget {
pub fn new(cpu: ArmCpu, is_64bit: bool) -> Self {
let arch = cpu.arch();
let tuning = cpu.tuning();
let cpu_features = cpu.features();
let mut features = HashMap::new();
features.insert(ArmFeature::FP, false);
features.insert(ArmFeature::ASIMD, false);
for feat in cpu_features {
Self::enable_feature_recursive(&mut features, feat);
}
let has_sve = *features.get(&ArmFeature::SVE).unwrap_or(&false);
let has_sme = *features.get(&ArmFeature::SME).unwrap_or(&false);
let svl = if has_sve { 128 } else { 0 };
ArmSubtarget {
cpu,
arch,
features,
tuning,
is_64bit,
min_sve_vl: svl,
max_sve_vl: if has_sve { 2048 } else { 0 },
has_streaming_sve: has_sme,
streaming_sve_vl: if has_sme { 128 } else { 0 },
}
}
fn enable_feature_recursive(features: &mut HashMap<ArmFeature, bool>, feat: ArmFeature) {
if *features.get(&feat).unwrap_or(&false) {
return; }
for dep in feat.dependencies() {
Self::enable_feature_recursive(features, *dep);
}
features.insert(feat, true);
}
pub fn has_feature(&self, feat: ArmFeature) -> bool {
*self.features.get(&feat).unwrap_or(&false)
}
pub fn get_target_cpu(&self) -> String {
self.cpu.name().to_string()
}
pub fn has_neon(&self) -> bool {
self.has_feature(ArmFeature::ASIMD)
}
pub fn has_sve(&self) -> bool {
self.has_feature(ArmFeature::SVE)
}
pub fn has_sve2(&self) -> bool {
self.has_feature(ArmFeature::SVE2)
}
pub fn has_sme(&self) -> bool {
self.has_feature(ArmFeature::SME)
}
pub fn has_pauth(&self) -> bool {
self.has_feature(ArmFeature::PAuth)
}
pub fn has_bti(&self) -> bool {
self.has_feature(ArmFeature::BTI)
}
pub fn has_mte(&self) -> bool {
self.has_feature(ArmFeature::MTE)
}
pub fn pref_function_alignment(&self) -> u32 {
self.tuning.pref_function_alignment
}
pub fn pref_loop_alignment(&self) -> u32 {
self.tuning.pref_loop_alignment
}
pub fn max_bytes_for_loop_alignment(&self) -> u32 {
self.tuning.max_bytes_for_loop_alignment
}
pub fn resolve_features(requested: &[ArmFeature]) -> Vec<ArmFeature> {
let mut features = HashMap::new();
for feat in requested {
Self::enable_feature_recursive(&mut features, *feat);
}
features
.into_iter()
.filter(|(_, enabled)| *enabled)
.map(|(feat, _)| feat)
.collect()
}
}
impl Default for ArmSubtarget {
fn default() -> Self {
ArmSubtarget::new(ArmCpu::Generic, true)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subtarget_default() {
let st = ArmSubtarget::default();
assert!(st.is_64bit);
assert_eq!(st.cpu, ArmCpu::Generic);
}
#[test]
fn test_cortex_a76_features() {
let st = ArmSubtarget::new(ArmCpu::CortexA76, true);
assert!(st.has_feature(ArmFeature::FP));
assert!(st.has_feature(ArmFeature::ASIMD));
assert!(st.has_feature(ArmFeature::DotProd));
assert!(st.has_feature(ArmFeature::LSE));
assert!(!st.has_feature(ArmFeature::SVE));
assert!(!st.has_feature(ArmFeature::SME));
}
#[test]
fn test_cortex_x2_features() {
let st = ArmSubtarget::new(ArmCpu::CortexX2, true);
assert!(st.has_feature(ArmFeature::FP));
assert!(st.has_feature(ArmFeature::ASIMD));
assert!(st.has_feature(ArmFeature::SVE));
assert!(st.has_feature(ArmFeature::SVE2));
assert!(st.has_feature(ArmFeature::BTI));
assert!(!st.has_feature(ArmFeature::SME));
}
#[test]
fn test_cortex_x4_features() {
let st = ArmSubtarget::new(ArmCpu::CortexX4, true);
assert!(st.has_feature(ArmFeature::SVE2));
assert!(st.has_feature(ArmFeature::BF16));
assert!(st.has_feature(ArmFeature::I8MM));
assert!(st.has_feature(ArmFeature::MTE2));
}
#[test]
fn test_apple_m1_features() {
let st = ArmSubtarget::new(ArmCpu::AppleM1, true);
assert!(st.has_feature(ArmFeature::FP));
assert!(st.has_feature(ArmFeature::ASIMD));
assert!(st.has_feature(ArmFeature::FullFP16));
assert!(st.has_feature(ArmFeature::AppleAES));
assert!(!st.has_feature(ArmFeature::SVE));
assert!(!st.has_feature(ArmFeature::MTE));
}
#[test]
fn test_apple_m4_features() {
let st = ArmSubtarget::new(ArmCpu::AppleM4, true);
assert!(st.has_feature(ArmFeature::SVE));
assert!(st.has_feature(ArmFeature::SVE2));
assert!(st.has_feature(ArmFeature::SME));
assert!(st.has_feature(ArmFeature::FP8));
assert!(st.has_feature(ArmFeature::MTE2));
}
#[test]
fn test_feature_dependency_chain() {
let mut features = HashMap::new();
ArmSubtarget::enable_feature_recursive(&mut features, ArmFeature::ASIMD);
assert!(features[&ArmFeature::FP]);
assert!(features[&ArmFeature::ASIMD]);
}
#[test]
fn test_sve2_depends_on_sve() {
let mut features = HashMap::new();
ArmSubtarget::enable_feature_recursive(&mut features, ArmFeature::SVE2);
assert!(features[&ArmFeature::FP]);
assert!(features[&ArmFeature::ASIMD]);
assert!(features[&ArmFeature::SVE]);
assert!(features[&ArmFeature::SVE2]);
}
#[test]
fn test_sme_depends_on_sve() {
let mut features = HashMap::new();
ArmSubtarget::enable_feature_recursive(&mut features, ArmFeature::SME);
assert!(features[&ArmFeature::SVE]);
assert!(features[&ArmFeature::BF16]);
assert!(features[&ArmFeature::SME]);
}
#[test]
fn test_cpu_arch_levels() {
assert_eq!(ArmCpu::CortexA53.arch(), ArmArch::Armv8_0A);
assert_eq!(ArmCpu::CortexA76.arch(), ArmArch::Armv8_2A);
assert_eq!(ArmCpu::CortexX1.arch(), ArmArch::Armv9_0A);
assert_eq!(ArmCpu::CortexX4.arch(), ArmArch::Armv9_2A);
assert_eq!(ArmCpu::AppleM1.arch(), ArmArch::Armv8_5A);
assert_eq!(ArmCpu::AppleM4.arch(), ArmArch::Armv9_2A);
}
#[test]
fn test_tuning_params() {
let st_a53 = ArmSubtarget::new(ArmCpu::CortexA53, true);
assert_eq!(st_a53.tuning.dispatch_width, 2);
assert_eq!(st_a53.pref_function_alignment(), 16);
let st_x4 = ArmSubtarget::new(ArmCpu::CortexX4, true);
assert_eq!(st_x4.tuning.dispatch_width, 8);
assert!(st_x4.tuning.post_ra_scheduler);
}
#[test]
fn test_neoverse_n2_has_sve2() {
let st = ArmSubtarget::new(ArmCpu::NeoverseN2, true);
assert!(st.has_sve2());
assert!(st.has_bti());
assert!(st.has_mte());
}
#[test]
fn test_resolve_features_dedup() {
let resolved =
ArmSubtarget::resolve_features(&[ArmFeature::FP, ArmFeature::ASIMD, ArmFeature::SVE2]);
assert!(resolved.contains(&ArmFeature::FP));
assert!(resolved.contains(&ArmFeature::ASIMD));
assert!(resolved.contains(&ArmFeature::SVE));
assert!(resolved.contains(&ArmFeature::SVE2));
}
#[test]
fn test_has_feature_default_false() {
let st = ArmSubtarget::new(ArmCpu::CortexA53, true);
assert!(!st.has_feature(ArmFeature::SVE));
assert!(!st.has_feature(ArmFeature::MTE));
assert!(!st.has_feature(ArmFeature::SME));
}
#[test]
fn test_cpu_name_roundtrip() {
for cpu in &[
ArmCpu::CortexA53,
ArmCpu::CortexA76,
ArmCpu::CortexX4,
ArmCpu::AppleM1,
ArmCpu::NeoverseV2,
] {
let name = cpu.name();
assert!(!name.is_empty());
}
}
}