1use std::cell::Cell;
9use std::sync::atomic::{AtomicU8, Ordering};
10
11static BMI2: AtomicU8 = AtomicU8::new(0);
13
14thread_local! {
15 static SCALAR_ONLY: Cell<bool> = const { Cell::new(false) };
16}
17
18#[inline]
20pub fn bmi2() -> bool {
21 if SCALAR_ONLY.with(Cell::get) {
22 return false;
23 }
24 match BMI2.load(Ordering::Relaxed) {
25 2 => true,
26 1 => false,
27 _ => {
28 let yes = detect();
29 BMI2.store(if yes { 2 } else { 1 }, Ordering::Relaxed);
30 yes
31 }
32 }
33}
34
35#[cfg(target_arch = "x86_64")]
36fn detect() -> bool {
37 std::arch::is_x86_feature_detected!("bmi1") && std::arch::is_x86_feature_detected!("bmi2") && std::arch::is_x86_feature_detected!("lzcnt")
38}
39
40#[cfg(not(target_arch = "x86_64"))]
41fn detect() -> bool {
42 false
43}
44
45pub fn set_scalar_only(on: bool) {
48 SCALAR_ONLY.with(|c| c.set(on));
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn scalar_switch() {
57 set_scalar_only(true);
58 assert!(!bmi2());
59 set_scalar_only(false);
60 }
61}