Skip to content

Commit 66db811

Browse files
authored
cmov: eliminate macros from portable backend (#1339)
Replaces them with simple one-line functions, which are duplicated for 32-bit and 64-bit, but they're simple enough the duplication may not be worth plastering over with macros.
1 parent 733d149 commit 66db811

File tree

1 file changed

+41
-32
lines changed

1 file changed

+41
-32
lines changed

cmov/src/portable.rs

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@
88
99
use crate::{Cmov, CmovEq, Condition};
1010

11-
/// Bitwise non-zero: returns `1` if `x != 0`, and otherwise returns `0`.
12-
macro_rules! bitnz {
13-
($value:expr, $bits:expr) => {
14-
core::hint::black_box(($value | $value.wrapping_neg()) >> ($bits - 1))
15-
};
16-
}
17-
1811
impl Cmov for u16 {
1912
#[inline]
2013
fn cmovnz(&mut self, value: &Self, condition: Condition) {
@@ -46,96 +39,112 @@ impl CmovEq for u16 {
4639
impl Cmov for u32 {
4740
#[inline]
4841
fn cmovnz(&mut self, value: &Self, condition: Condition) {
49-
let mask = nzmask32(condition);
42+
let mask = masknz32(condition);
5043
*self = (*self & !mask) | (*value & mask);
5144
}
5245

5346
#[inline]
5447
fn cmovz(&mut self, value: &Self, condition: Condition) {
55-
let mask = nzmask32(condition);
48+
let mask = masknz32(condition);
5649
*self = (*self & mask) | (*value & !mask);
5750
}
5851
}
5952

6053
impl CmovEq for u32 {
6154
#[inline]
6255
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
63-
let xor = self ^ rhs;
64-
let ne = bitnz!(xor, u32::BITS) as u8;
56+
let ne = testnz32(self ^ rhs) as u8;
6557
output.cmovnz(&input, ne);
6658
}
6759

6860
#[inline]
6961
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
70-
let xor = self ^ rhs;
71-
let ne = bitnz!(xor, u32::BITS) as u8;
62+
let ne = testnz32(self ^ rhs) as u8;
7263
output.cmovnz(&input, ne ^ 1);
7364
}
7465
}
7566

7667
impl Cmov for u64 {
7768
#[inline]
7869
fn cmovnz(&mut self, value: &Self, condition: Condition) {
79-
let mask = nzmask64(condition);
70+
let mask = masknz64(condition);
8071
*self = (*self & !mask) | (*value & mask);
8172
}
8273

8374
#[inline]
8475
fn cmovz(&mut self, value: &Self, condition: Condition) {
85-
let mask = nzmask64(condition);
76+
let mask = masknz64(condition);
8677
*self = (*self & mask) | (*value & !mask);
8778
}
8879
}
8980

9081
impl CmovEq for u64 {
9182
#[inline]
9283
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
93-
let xor = self ^ rhs;
94-
let ne = bitnz!(xor, u64::BITS) as u8;
84+
let ne = testnz64(self ^ rhs) as u8;
9585
output.cmovnz(&input, ne);
9686
}
9787

9888
#[inline]
9989
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
100-
let xor = self ^ rhs;
101-
let ne = bitnz!(xor, u64::BITS) as u8;
90+
let ne = testnz64(self ^ rhs) as u8;
10291
output.cmovnz(&input, ne ^ 1);
10392
}
10493
}
10594

95+
/// Returns `0` if `x` is `0`, otherwise returns `1` (32-bit version)
96+
pub fn testnz32(mut x: u32) -> u32 {
97+
x |= x.wrapping_neg();
98+
core::hint::black_box(x >> (u32::BITS - 1))
99+
}
100+
101+
/// Returns `0` if `x` is `0`, otherwise returns `1` (64-bit version)
102+
pub fn testnz64(mut x: u64) -> u64 {
103+
x |= x.wrapping_neg();
104+
core::hint::black_box(x >> (u64::BITS - 1))
105+
}
106+
106107
/// Return a [`u32::MAX`] mask if `condition` is non-zero, otherwise return zero for a zero input.
107-
pub fn nzmask32(condition: Condition) -> u32 {
108-
bitnz!(condition as u32, u32::BITS).wrapping_neg()
108+
pub fn masknz32(condition: Condition) -> u32 {
109+
testnz32(condition as u32).wrapping_neg()
109110
}
110111

111112
/// Return a [`u64::MAX`] mask if `condition` is non-zero, otherwise return zero for a zero input.
112-
pub fn nzmask64(condition: Condition) -> u64 {
113-
bitnz!(condition as u64, u64::BITS).wrapping_neg()
113+
pub fn masknz64(condition: Condition) -> u64 {
114+
testnz64(condition as u64).wrapping_neg()
114115
}
115116

116117
#[cfg(test)]
117118
mod tests {
118119
#[test]
119-
fn bitnz() {
120-
assert_eq!(bitnz!(0u8, u8::BITS), 0);
120+
fn testnz32() {
121+
assert_eq!(super::testnz32(0), 0);
122+
for i in 1..=u8::MAX {
123+
assert_eq!(super::testnz32(i as u32), 1);
124+
}
125+
}
126+
127+
#[test]
128+
fn testnz64() {
129+
assert_eq!(super::testnz64(0), 0);
121130
for i in 1..=u8::MAX {
122-
assert_eq!(bitnz!(i, u8::BITS), 1);
131+
assert_eq!(super::testnz64(i as u64), 1);
123132
}
124133
}
125134

126135
#[test]
127-
fn nzmask32() {
128-
assert_eq!(super::nzmask32(0), 0);
136+
fn masknz32() {
137+
assert_eq!(super::masknz32(0), 0);
129138
for i in 1..=u8::MAX {
130-
assert_eq!(super::nzmask32(i), u32::MAX);
139+
assert_eq!(super::masknz32(i), u32::MAX);
131140
}
132141
}
133142

134143
#[test]
135-
fn nzmask64() {
136-
assert_eq!(super::nzmask64(0), 0);
144+
fn masknz64() {
145+
assert_eq!(super::masknz64(0), 0);
137146
for i in 1..=u8::MAX {
138-
assert_eq!(super::nzmask64(i), u64::MAX);
147+
assert_eq!(super::masknz64(i), u64::MAX);
139148
}
140149
}
141150
}

0 commit comments

Comments
 (0)