use cranelift_codegen::isa::OwnedTargetIsa;
use cranelift_codegen::settings;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EffectiveIsa {
pub triple: String,
pub polydat_register_bits: u16,
pub cranelift_version: &'static str,
enabled_flags: Vec<&'static str>,
}
impl EffectiveIsa {
pub fn detect() -> Result<Self, String> {
let isa = build_host_isa(settings::builder())?;
let mut enabled_flags: Vec<_> = isa
.isa_flags()
.into_iter()
.filter(|flag| flag.as_bool() == Some(true))
.map(|flag| flag.name)
.collect();
enabled_flags.sort_unstable();
Ok(Self {
triple: isa.triple().to_string(),
polydat_register_bits: 128,
cranelift_version: cranelift_native::VERSION,
enabled_flags,
})
}
pub fn has_flag(&self, flag: &str) -> bool {
self.enabled_flags.binary_search(&flag).is_ok()
}
pub fn enabled_flags(&self) -> &[&'static str] {
&self.enabled_flags
}
pub fn fingerprint(&self) -> String {
format!(
"{}|clif={}|reg={}|{}",
self.triple,
self.cranelift_version,
self.polydat_register_bits,
self.enabled_flags.join(",")
)
}
}
pub(crate) fn build_host_isa(
shared_flag_builder: settings::Builder,
) -> Result<OwnedTargetIsa, String> {
let isa_builder =
cranelift_native::builder().map_err(|e| format!("native ISA detection failed: {e}"))?;
isa_builder
.finish(settings::Flags::new(shared_flag_builder))
.map_err(|e| format!("native ISA build failed: {e}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn capability_record_matches_native_x86_detection() {
let caps = EffectiveIsa::detect().expect("host ISA");
assert_eq!(caps.polydat_register_bits, 128);
assert!(!caps.fingerprint().is_empty());
#[cfg(target_arch = "x86_64")]
{
assert_eq!(
caps.has_flag("has_avx"),
std::is_x86_feature_detected!("avx")
);
assert_eq!(
caps.has_flag("has_avx2"),
std::is_x86_feature_detected!("avx2")
);
assert_eq!(
caps.has_flag("has_fma"),
std::is_x86_feature_detected!("fma")
);
}
}
}