| 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 | |