//! Stuff for handling `#[target_feature]` (needed for unsafe check). use std::borrow::Cow; use std::sync::LazyLock; use hir_def::FunctionId; use hir_def::attrs::AttrFlags; use intern::Symbol; use rustc_hash::{FxHashMap, FxHashSet}; use crate::db::HirDatabase; #[derive(Debug, Default, Clone)] pub struct TargetFeatures<'db> { pub(crate) enabled: Cow<'db, FxHashSet>, } impl<'db> TargetFeatures<'db> { pub fn from_fn(db: &'db dyn HirDatabase, owner: FunctionId) -> Self { let mut result = TargetFeatures::from_fn_no_implications(db, owner); result.expand_implications(); result } fn expand_implications(&mut self) { let all_implications = LazyLock::force(&TARGET_FEATURE_IMPLICATIONS); let enabled = self.enabled.to_mut(); let mut queue = enabled.iter().cloned().collect::>(); while let Some(feature) = queue.pop() { if let Some(implications) = all_implications.get(&feature) { for implication in implications { if enabled.insert(implication.clone()) { queue.push(implication.clone()); } } } } } /// Retrieves the target features from the attributes, and does not expand the target features implied by them. pub(crate) fn from_fn_no_implications(db: &'db dyn HirDatabase, owner: FunctionId) -> Self { let enabled = AttrFlags::target_features(db, owner); Self { enabled: Cow::Borrowed(enabled) } } } // List of the target features each target feature implies. // Ideally we'd depend on rustc for this, but rustc_target doesn't compile on stable, // and t-compiler prefers for it to stay this way. static TARGET_FEATURE_IMPLICATIONS: LazyLock>> = LazyLock::new(|| { let mut result = FxHashMap::>::default(); for &(feature_str, implications) in TARGET_FEATURE_IMPLICATIONS_RAW { let feature = Symbol::intern(feature_str); let implications = implications.iter().copied().map(Symbol::intern); // Some target features appear in two archs, e.g. Arm and x86. // Sometimes they contain different implications, e.g. `aes`. // We should probably choose by the active arch, but for now just merge them. result.entry(feature).or_default().extend(implications); } let mut result = result .into_iter() .map(|(feature, implications)| (feature, Box::from_iter(implications))) .collect::>(); result.shrink_to_fit(); result }); // spellchecker:off const TARGET_FEATURE_IMPLICATIONS_RAW: &[(&str, &[&str])] = &[ // Arm ("aes", &["neon"]), ("dotprod", &["neon"]), ("fp-armv8", &["vfp4"]), ("fp16", &["neon"]), ("i8mm", &["neon"]), ("neon", &["vfp3"]), ("sha2", &["neon"]), ("v6", &["v5te"]), ("v6k", &["v6"]), ("v6t2", &["v6k", "thumb2"]), ("v7", &["v6t2"]), ("v8", &["v7"]), ("vfp3", &["vfp2", "d32"]), ("vfp4", &["vfp3"]), // Aarch64 ("aes", &["neon"]), ("dotprod", &["neon"]), ("dpb2", &["dpb"]), ("f32mm", &["sve"]), ("f64mm", &["sve"]), ("fcma", &["neon"]), ("fhm", &["fp16"]), ("fp16", &["neon"]), ("fp8", &["faminmax", "lut", "bf16"]), ("fp8dot2", &["fp8dot4"]), ("fp8dot4", &["fp8fma"]), ("fp8fma", &["fp8"]), ("jsconv", &["neon"]), ("lse128", &["lse"]), ("rcpc2", &["rcpc"]), ("rcpc3", &["rcpc2"]), ("rdm", &["neon"]), ("sha2", &["neon"]), ("sha3", &["sha2"]), ("sm4", &["neon"]), ("sme", &["bf16"]), ("sme-b16b16", &["bf16", "sme2", "sve-b16b16"]), ("sme-f16f16", &["sme2"]), ("sme-f64f64", &["sme"]), ("sme-f8f16", &["sme-f8f32"]), ("sme-f8f32", &["sme2", "fp8"]), ("sme-fa64", &["sme", "sve2"]), ("sme-i16i64", &["sme"]), ("sme2", &["sme"]), ("sme2p1", &["sme2"]), ("ssve-fp8dot2", &["ssve-fp8dot4"]), ("ssve-fp8dot4", &["ssve-fp8fma"]), ("ssve-fp8fma", &["sme2", "fp8"]), ("sve", &["neon"]), ("sve-b16b16", &["bf16"]), ("sve2", &["sve"]), ("sve2-aes", &["sve2", "aes"]), ("sve2-bitperm", &["sve2"]), ("sve2-sha3", &["sve2", "sha3"]), ("sve2-sm4", &["sve2", "sm4"]), ("sve2p1", &["sve2"]), ("v8.1a", &["crc", "lse", "rdm", "pan", "lor", "vh"]), ("v8.2a", &["v8.1a", "ras", "dpb"]), ("v8.3a", &["v8.2a", "rcpc", "paca", "pacg", "jsconv"]), ("v8.4a", &["v8.3a", "dotprod", "dit", "flagm"]), ("v8.5a", &["v8.4a", "ssbs", "sb", "dpb2", "bti"]), ("v8.6a", &["v8.5a", "bf16", "i8mm"]), ("v8.7a", &["v8.6a", "wfxt"]), ("v8.8a", &["v8.7a", "hbc", "mops"]), ("v8.9a", &["v8.8a", "cssc"]), ("v9.1a", &["v9a", "v8.6a"]), ("v9.2a", &["v9.1a", "v8.7a"]), ("v9.3a", &["v9.2a", "v8.8a"]), ("v9.4a", &["v9.3a", "v8.9a"]), ("v9.5a", &["v9.4a"]), ("v9a", &["v8.5a", "sve2"]), // x86 ("aes", &["sse2"]), ("amx-bf16", &["amx-tile"]), ("amx-complex", &["amx-tile"]), ("amx-fp16", &["amx-tile"]), ("amx-int8", &["amx-tile"]), ("avx", &["sse4.2"]), ("avx2", &["avx"]), ("avx512bf16", &["avx512bw"]), ("avx512bitalg", &["avx512bw"]), ("avx512bw", &["avx512f"]), ("avx512cd", &["avx512f"]), ("avx512dq", &["avx512f"]), ("avx512f", &["avx2", "fma", "f16c"]), ("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]), ("avx512ifma", &["avx512f"]), ("avx512vbmi", &["avx512bw"]), ("avx512vbmi2", &["avx512bw"]), ("avx512vl", &["avx512f"]), ("avx512vnni", &["avx512f"]), ("avx512vp2intersect", &["avx512f"]), ("avx512vpopcntdq", &["avx512f"]), ("avxifma", &["avx2"]), ("avxneconvert", &["avx2"]), ("avxvnni", &["avx2"]), ("avxvnniint16", &["avx2"]), ("avxvnniint8", &["avx2"]), ("f16c", &["avx"]), ("fma", &["avx"]), ("gfni", &["sse2"]), ("kl", &["sse2"]), ("pclmulqdq", &["sse2"]), ("sha", &["sse2"]), ("sha512", &["avx2"]), ("sm3", &["avx"]), ("sm4", &["avx2"]), ("sse2", &["sse"]), ("sse3", &["sse2"]), ("sse4.1", &["ssse3"]), ("sse4.2", &["sse4.1"]), ("sse4a", &["sse3"]), ("ssse3", &["sse3"]), ("vaes", &["avx2", "aes"]), ("vpclmulqdq", &["avx", "pclmulqdq"]), ("widekl", &["kl"]), ("xop", &[/*"fma4", */ "avx", "sse4a"]), ("xsavec", &["xsave"]), ("xsaveopt", &["xsave"]), ("xsaves", &["xsave"]), // Hexagon ("hvx-length128b", &["hvx"]), // PowerPC ("power10-vector", &["power9-vector"]), ("power8-altivec", &["altivec"]), ("power8-crypto", &["power8-altivec"]), ("power8-vector", &["vsx", "power8-altivec"]), ("power9-altivec", &["power8-altivec"]), ("power9-vector", &["power8-vector", "power9-altivec"]), ("vsx", &["altivec"]), // MIPS // RISC-V ("a", &["zaamo", "zalrsc"]), ("d", &["f"]), ("zabha", &["zaamo"]), ("zdinx", &["zfinx"]), ("zfh", &["zfhmin"]), ("zfhmin", &["f"]), ("zhinx", &["zhinxmin"]), ("zhinxmin", &["zfinx"]), ("zk", &["zkn", "zkr", "zkt"]), ("zkn", &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), ("zks", &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), // WASM ("relaxed-simd", &["simd128"]), // BPF ("alu32", &[]), // CSKY ("10e60", &["7e10"]), ("2e3", &["e2"]), ("3e3r2", &["3e3r1", "doloop"]), ("3e3r3", &["doloop"]), ("3e7", &["2e3"]), ("7e10", &["3e7"]), ("e1", &["elrw"]), ("e2", &["e2"]), ("mp", &["2e3"]), ("mp1e2", &["3e7"]), // LoongArch ("d", &["f"]), ("lasx", &["lsx"]), ("lsx", &["d"]), // IBM Z ("nnp-assist", &["vector"]), ("vector-enhancements-1", &["vector"]), ("vector-enhancements-2", &["vector-enhancements-1"]), ("vector-packed-decimal", &["vector"]), ("vector-packed-decimal-enhancement", &["vector-packed-decimal"]), ("vector-packed-decimal-enhancement-2", &["vector-packed-decimal-enhancement"]), // SPARC // m68k ("isa-68010", &["isa-68000"]), ("isa-68020", &["isa-68010"]), ("isa-68030", &["isa-68020"]), ("isa-68040", &["isa-68030", "isa-68882"]), ("isa-68060", &["isa-68040"]), ("isa-68882", &["isa-68881"]), ]; // spellchecker:on