1 | use crate::arch::asm; |
2 | #[cfg (test)] |
3 | use 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" )] |
9 | macro_rules! bt { |
10 | ($inst:expr) => { |
11 | concat!($inst, " {b:e}, ({p:e})" ) |
12 | }; |
13 | } |
14 | #[cfg (target_pointer_width = "64" )] |
15 | macro_rules! bt { |
16 | ($inst:expr) => { |
17 | concat!($inst, " {b:e}, ({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=_bittest) |
24 | #[inline ] |
25 | #[cfg_attr (test, assert_instr(bt))] |
26 | #[stable (feature = "simd_x86_bittest" , since = "1.55.0" )] |
27 | pub unsafe fn _bittest(p: *const i32, b: i32) -> u8 { |
28 | let r: u8; |
29 | asm!( |
30 | bt!("btl" ), |
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=_bittestandset) |
43 | #[inline ] |
44 | #[cfg_attr (test, assert_instr(bts))] |
45 | #[stable (feature = "simd_x86_bittest" , since = "1.55.0" )] |
46 | pub unsafe fn _bittestandset(p: *mut i32, b: i32) -> u8 { |
47 | let r: u8; |
48 | asm!( |
49 | bt!("btsl" ), |
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=_bittestandreset) |
62 | #[inline ] |
63 | #[cfg_attr (test, assert_instr(btr))] |
64 | #[stable (feature = "simd_x86_bittest" , since = "1.55.0" )] |
65 | pub unsafe fn _bittestandreset(p: *mut i32, b: i32) -> u8 { |
66 | let r: u8; |
67 | asm!( |
68 | bt!("btrl" ), |
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=_bittestandcomplement) |
81 | #[inline ] |
82 | #[cfg_attr (test, assert_instr(btc))] |
83 | #[stable (feature = "simd_x86_bittest" , since = "1.55.0" )] |
84 | pub unsafe fn _bittestandcomplement(p: *mut i32, b: i32) -> u8 { |
85 | let r: u8; |
86 | asm!( |
87 | bt!("btcl" ), |
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)] |
98 | mod tests { |
99 | use crate::core_arch::x86::*; |
100 | |
101 | #[test ] |
102 | #[cfg_attr (miri, ignore)] // Uses inline assembly |
103 | fn test_bittest() { |
104 | unsafe { |
105 | let a = 0b0101_0000i32; |
106 | assert_eq!(_bittest(&a as _, 4), 1); |
107 | assert_eq!(_bittest(&a as _, 5), 0); |
108 | } |
109 | } |
110 | |
111 | #[test ] |
112 | #[cfg_attr (miri, ignore)] // Uses inline assembly |
113 | fn test_bittestandset() { |
114 | unsafe { |
115 | let mut a = 0b0101_0000i32; |
116 | assert_eq!(_bittestandset(&mut a as _, 4), 1); |
117 | assert_eq!(_bittestandset(&mut a as _, 4), 1); |
118 | assert_eq!(_bittestandset(&mut a as _, 5), 0); |
119 | assert_eq!(_bittestandset(&mut a as _, 5), 1); |
120 | } |
121 | } |
122 | |
123 | #[test ] |
124 | #[cfg_attr (miri, ignore)] // Uses inline assembly |
125 | fn test_bittestandreset() { |
126 | unsafe { |
127 | let mut a = 0b0101_0000i32; |
128 | assert_eq!(_bittestandreset(&mut a as _, 4), 1); |
129 | assert_eq!(_bittestandreset(&mut a as _, 4), 0); |
130 | assert_eq!(_bittestandreset(&mut a as _, 5), 0); |
131 | assert_eq!(_bittestandreset(&mut a as _, 5), 0); |
132 | } |
133 | } |
134 | |
135 | #[test ] |
136 | #[cfg_attr (miri, ignore)] // Uses inline assembly |
137 | fn test_bittestandcomplement() { |
138 | unsafe { |
139 | let mut a = 0b0101_0000i32; |
140 | assert_eq!(_bittestandcomplement(&mut a as _, 4), 1); |
141 | assert_eq!(_bittestandcomplement(&mut a as _, 4), 0); |
142 | assert_eq!(_bittestandcomplement(&mut a as _, 4), 1); |
143 | assert_eq!(_bittestandcomplement(&mut a as _, 5), 0); |
144 | assert_eq!(_bittestandcomplement(&mut a as _, 5), 1); |
145 | } |
146 | } |
147 | } |
148 | |