Skip to main content

polydat_core/compile/jit/
host_isa.rs

1// Copyright 2024-2026 Jonathan Shook
2// SPDX-License-Identifier: Apache-2.0
3
4//! One source of truth for the effective native Cranelift ISA.
5//!
6//! `isa::lookup(Triple::host())` selects an architecture but does not infer
7//! optional host features. JIT code and the SIMD planner must instead consume
8//! the same `cranelift_native` builder, whose detection includes the OS-enabled
9//! architectural state checked by Rust's feature-detection macros.
10
11use cranelift_codegen::isa::OwnedTargetIsa;
12use cranelift_codegen::settings;
13
14/// Effective code-generation capabilities advertised by the native Cranelift
15/// builder used for this process.
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct EffectiveIsa {
18    /// Full target triple of the JIT host.
19    pub triple: String,
20    /// Width of Polydat's fixed register type plane. This is deliberately not
21    /// inferred from AVX/AVX-512 feature names.
22    pub polydat_register_bits: u16,
23    /// Cranelift version which produced this capability record.
24    pub cranelift_version: &'static str,
25    /// Enabled target-specific Cranelift boolean flags, sorted by name.
26    enabled_flags: Vec<&'static str>,
27}
28
29impl EffectiveIsa {
30    /// Probe the same native builder used by production JIT compilation.
31    pub fn detect() -> Result<Self, String> {
32        let isa = build_host_isa(settings::builder())?;
33        let mut enabled_flags: Vec<_> = isa
34            .isa_flags()
35            .into_iter()
36            .filter(|flag| flag.as_bool() == Some(true))
37            .map(|flag| flag.name)
38            .collect();
39        enabled_flags.sort_unstable();
40
41        Ok(Self {
42            triple: isa.triple().to_string(),
43            polydat_register_bits: 128,
44            cranelift_version: cranelift_native::VERSION,
45            enabled_flags,
46        })
47    }
48
49    /// Whether an ISA flag such as `has_avx2` is enabled in the builder.
50    pub fn has_flag(&self, flag: &str) -> bool {
51        self.enabled_flags.binary_search(&flag).is_ok()
52    }
53
54    /// Stable ordered flag list for diagnostics and plan-cache identity.
55    pub fn enabled_flags(&self) -> &[&'static str] {
56        &self.enabled_flags
57    }
58
59    /// Text fingerprint suitable for inclusion in a compiled-plan cache key.
60    pub fn fingerprint(&self) -> String {
61        format!(
62            "{}|clif={}|reg={}|{}",
63            self.triple,
64            self.cranelift_version,
65            self.polydat_register_bits,
66            self.enabled_flags.join(",")
67        )
68    }
69}
70
71/// Build a host ISA with native feature inference and caller-selected shared
72/// Cranelift flags.
73pub(crate) fn build_host_isa(
74    shared_flag_builder: settings::Builder,
75) -> Result<OwnedTargetIsa, String> {
76    let isa_builder =
77        cranelift_native::builder().map_err(|e| format!("native ISA detection failed: {e}"))?;
78    isa_builder
79        .finish(settings::Flags::new(shared_flag_builder))
80        .map_err(|e| format!("native ISA build failed: {e}"))
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn capability_record_matches_native_x86_detection() {
89        let caps = EffectiveIsa::detect().expect("host ISA");
90        assert_eq!(caps.polydat_register_bits, 128);
91        assert!(!caps.fingerprint().is_empty());
92
93        #[cfg(target_arch = "x86_64")]
94        {
95            assert_eq!(
96                caps.has_flag("has_avx"),
97                std::is_x86_feature_detected!("avx")
98            );
99            assert_eq!(
100                caps.has_flag("has_avx2"),
101                std::is_x86_feature_detected!("avx2")
102            );
103            assert_eq!(
104                caps.has_flag("has_fma"),
105                std::is_x86_feature_detected!("fma")
106            );
107        }
108    }
109}