core/stdarch/crates/core_arch/src/x86_64/
bt.rs

1use crate::arch::asm;
2#[cfg(test)]
3use stdarch_test::assert_instr;
4
5// x32 wants to use a 32-bit address size, but asm! defaults to using the full
6// register name (e.g. rax). We have to explicitly override the placeholder to
7// use the 32-bit register name in that case.
8#[cfg(target_pointer_width = "32")]
9macro_rules! bt {
10    ($inst:expr) => {
11        concat!($inst, " {b}, ({p:e})")
12    };
13}
14#[cfg(target_pointer_width = "64")]
15macro_rules! bt {
16    ($inst:expr) => {
17        concat!($inst, " {b}, ({p})")
18    };
19}
20
21/// Returns the bit in position `b` of the memory addressed by `p`.
22///
23/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_bittest64)
24#[inline]
25#[cfg_attr(test, assert_instr(bt))]
26#[stable(feature = "simd_x86_bittest", since = "1.55.0")]
27pub unsafe fn _bittest64(p: *const i64, b: i64) -> u8 {
28    let r: u8;
29    asm!(
30        bt!("btq"),
31        "setc {r}",
32        p = in(reg) p,
33        b = in(reg) b,
34        r = out(reg_byte) r,
35        options(readonly, nostack, pure, att_syntax)
36    );
37    r
38}
39
40/// Returns the bit in position `b` of the memory addressed by `p`, then sets the bit to `1`.
41///
42/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_bittestandset64)
43#[inline]
44#[cfg_attr(test, assert_instr(bts))]
45#[stable(feature = "simd_x86_bittest", since = "1.55.0")]
46pub unsafe fn _bittestandset64(p: *mut i64, b: i64) -> u8 {
47    let r: u8;
48    asm!(
49        bt!("btsq"),
50        "setc {r}",
51        p = in(reg) p,
52        b = in(reg) b,
53        r = out(reg_byte) r,
54        options(nostack, att_syntax)
55    );
56    r
57}
58
59/// Returns the bit in position `b` of the memory addressed by `p`, then resets that bit to `0`.
60///
61/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_bittestandreset64)
62#[inline]
63#[cfg_attr(test, assert_instr(btr))]
64#[stable(feature = "simd_x86_bittest", since = "1.55.0")]
65pub unsafe fn _bittestandreset64(p: *mut i64, b: i64) -> u8 {
66    let r: u8;
67    asm!(
68        bt!("btrq"),
69        "setc {r}",
70        p = in(reg) p,
71        b = in(reg) b,
72        r = out(reg_byte) r,
73        options(nostack, att_syntax)
74    );
75    r
76}
77
78/// Returns the bit in position `b` of the memory addressed by `p`, then inverts that bit.
79///
80/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_bittestandcomplement64)
81#[inline]
82#[cfg_attr(test, assert_instr(btc))]
83#[stable(feature = "simd_x86_bittest", since = "1.55.0")]
84pub unsafe fn _bittestandcomplement64(p: *mut i64, b: i64) -> u8 {
85    let r: u8;
86    asm!(
87        bt!("btcq"),
88        "setc {r}",
89        p = in(reg) p,
90        b = in(reg) b,
91        r = out(reg_byte) r,
92        options(nostack, att_syntax)
93    );
94    r
95}
96
97#[cfg(test)]
98mod tests {
99    use crate::core_arch::x86_64::*;
100
101    #[test]
102    #[cfg_attr(miri, ignore)] // Uses inline assembly
103    fn test_bittest64() {
104        unsafe {
105            let a = 0b0101_0000i64;
106            assert_eq!(_bittest64(&a as _, 4), 1);
107            assert_eq!(_bittest64(&a as _, 5), 0);
108        }
109    }
110
111    #[test]
112    #[cfg_attr(miri, ignore)] // Uses inline assembly
113    fn test_bittestandset64() {
114        unsafe {
115            let mut a = 0b0101_0000i64;
116            assert_eq!(_bittestandset64(&mut a as _, 4), 1);
117            assert_eq!(_bittestandset64(&mut a as _, 4), 1);
118            assert_eq!(_bittestandset64(&mut a as _, 5), 0);
119            assert_eq!(_bittestandset64(&mut a as _, 5), 1);
120        }
121    }
122
123    #[test]
124    #[cfg_attr(miri, ignore)] // Uses inline assembly
125    fn test_bittestandreset64() {
126        unsafe {
127            let mut a = 0b0101_0000i64;
128            assert_eq!(_bittestandreset64(&mut a as _, 4), 1);
129            assert_eq!(_bittestandreset64(&mut a as _, 4), 0);
130            assert_eq!(_bittestandreset64(&mut a as _, 5), 0);
131            assert_eq!(_bittestandreset64(&mut a as _, 5), 0);
132        }
133    }
134
135    #[test]
136    #[cfg_attr(miri, ignore)] // Uses inline assembly
137    fn test_bittestandcomplement64() {
138        unsafe {
139            let mut a = 0b0101_0000i64;
140            assert_eq!(_bittestandcomplement64(&mut a as _, 4), 1);
141            assert_eq!(_bittestandcomplement64(&mut a as _, 4), 0);
142            assert_eq!(_bittestandcomplement64(&mut a as _, 4), 1);
143            assert_eq!(_bittestandcomplement64(&mut a as _, 5), 0);
144            assert_eq!(_bittestandcomplement64(&mut a as _, 5), 1);
145        }
146    }
147}