use crate::detect::{Feature, cache};
pub(crate) fn detect_features() -> cache::Initializer {
let mut value = cache::Initializer::default();
{
let mut enable_feature = |f, enable| {
if enable {
value.set(f as u32);
}
};
let aa64isar0: u64;
unsafe { asm!("mrs $0, ID_AA64ISAR0_EL1" : "=r"(aa64isar0)); }
let aes = bits_shift(aa64isar0, 7, 4) >= 1;
let pmull = bits_shift(aa64isar0, 7, 4) >= 2;
let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
enable_feature(Feature::pmull, pmull);
enable_feature(Feature::crypto, aes && pmull && sha1 && sha2);
enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 1);
enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);
let aa64pfr0: u64;
unsafe { asm!("mrs $0, ID_AA64PFR0_EL1" : "=r"(aa64pfr0)); }
let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
enable_feature(Feature::fp, fp);
enable_feature(Feature::fp16, fphp);
enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1);
enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);
let aa64isar1: u64;
unsafe { asm!("mrs $0, ID_AA64ISAR1_EL1" : "=r"(aa64isar1)); }
enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
}
value
}
#[inline]
fn bits_shift(x: u64, high: usize, low: usize) -> u64 {
(x >> low) & ((1 << (high - low + 1)) - 1)
}