77// TODO(tarcieri): more optimized implementation for small integers
88
99use crate :: { Cmov , CmovEq , Condition } ;
10- use core:: hint:: black_box;
1110
1211/// Bitwise non-zero: returns `1` if `x != 0`, and otherwise returns `0`.
1312macro_rules! bitnz {
1413 ( $value: expr, $bits: expr) => {
15- black_box( ( $value | $value. wrapping_neg( ) ) >> ( $bits - 1 ) )
14+ core :: hint :: black_box( ( $value | $value. wrapping_neg( ) ) >> ( $bits - 1 ) )
1615 } ;
1716}
1817
1918impl Cmov for u16 {
2019 #[ inline]
2120 fn cmovnz ( & mut self , value : & Self , condition : Condition ) {
22- let mut tmp = * self as u64 ;
23- tmp. cmovnz ( & ( * value as u64 ) , condition) ;
21+ let mut tmp = * self as u32 ;
22+ tmp. cmovnz ( & ( * value as u32 ) , condition) ;
2423 * self = tmp as u16 ;
2524 }
2625
2726 #[ inline]
2827 fn cmovz ( & mut self , value : & Self , condition : Condition ) {
29- let mut tmp = * self as u64 ;
30- tmp. cmovz ( & ( * value as u64 ) , condition) ;
28+ let mut tmp = * self as u32 ;
29+ tmp. cmovz ( & ( * value as u32 ) , condition) ;
3130 * self = tmp as u16 ;
3231 }
3332}
3433
3534impl CmovEq for u16 {
3635 #[ inline]
3736 fn cmovne ( & self , rhs : & Self , input : Condition , output : & mut Condition ) {
38- ( * self as u64 ) . cmovne ( & ( * rhs as u64 ) , input, output) ;
37+ ( * self as u32 ) . cmovne ( & ( * rhs as u32 ) , input, output) ;
3938 }
4039
4140 #[ inline]
4241 fn cmoveq ( & self , rhs : & Self , input : Condition , output : & mut Condition ) {
43- ( * self as u64 ) . cmoveq ( & ( * rhs as u64 ) , input, output) ;
42+ ( * self as u32 ) . cmoveq ( & ( * rhs as u32 ) , input, output) ;
4443 }
4544}
4645
4746impl Cmov for u32 {
4847 #[ inline]
4948 fn cmovnz ( & mut self , value : & Self , condition : Condition ) {
50- let mut tmp = * self as u64 ;
51- tmp. cmovnz ( & ( * value as u64 ) , condition) ;
52- * self = tmp as u32 ;
49+ let mask = nzmask32 ( condition) ;
50+ * self = ( * self & !mask) | ( * value & mask) ;
5351 }
5452
5553 #[ inline]
5654 fn cmovz ( & mut self , value : & Self , condition : Condition ) {
57- let mut tmp = * self as u64 ;
58- tmp. cmovz ( & ( * value as u64 ) , condition) ;
59- * self = tmp as u32 ;
55+ let mask = nzmask32 ( condition) ;
56+ * self = ( * self & mask) | ( * value & !mask) ;
6057 }
6158}
6259
6360impl CmovEq for u32 {
6461 #[ inline]
6562 fn cmovne ( & self , rhs : & Self , input : Condition , output : & mut Condition ) {
66- ( * self as u64 ) . cmovne ( & ( * rhs as u64 ) , input, output) ;
63+ let ne = bitnz ! ( self ^ rhs, u32 :: BITS ) as u8 ;
64+ output. cmovnz ( & input, ne) ;
6765 }
6866
6967 #[ inline]
7068 fn cmoveq ( & self , rhs : & Self , input : Condition , output : & mut Condition ) {
71- ( * self as u64 ) . cmoveq ( & ( * rhs as u64 ) , input, output) ;
69+ let ne = bitnz ! ( self ^ rhs, u32 :: BITS ) as u8 ;
70+ output. cmovnz ( & input, ne ^ 1 ) ;
7271 }
7372}
7473
7574impl Cmov for u64 {
7675 #[ inline]
7776 fn cmovnz ( & mut self , value : & Self , condition : Condition ) {
78- let mask = ( bitnz ! ( condition, u8 :: BITS ) as u64 ) . wrapping_sub ( 1 ) ;
79- * self = ( * self & mask) | ( * value & ! mask) ;
77+ let mask = nzmask64 ( condition) ;
78+ * self = ( * self & ! mask) | ( * value & mask) ;
8079 }
8180
8281 #[ inline]
8382 fn cmovz ( & mut self , value : & Self , condition : Condition ) {
84- let mask = ( 1 ^ bitnz ! ( condition, u8 :: BITS ) as u64 ) . wrapping_sub ( 1 ) ;
83+ let mask = nzmask64 ( condition) ;
8584 * self = ( * self & mask) | ( * value & !mask) ;
8685 }
8786}
@@ -99,3 +98,40 @@ impl CmovEq for u64 {
9998 output. cmovnz ( & input, ne ^ 1 ) ;
10099 }
101100}
101+
102+ /// Return a [`u32::MAX`] mask if `condition` is non-zero, otherwise return zero for a zero input.
103+ pub fn nzmask32 ( condition : Condition ) -> u32 {
104+ bitnz ! ( condition as u32 , u32 :: BITS ) . wrapping_neg ( )
105+ }
106+
107+ /// Return a [`u64::MAX`] mask if `condition` is non-zero, otherwise return zero for a zero input.
108+ pub fn nzmask64 ( condition : Condition ) -> u64 {
109+ bitnz ! ( condition as u64 , u64 :: BITS ) . wrapping_neg ( )
110+ }
111+
112+ #[ cfg( test) ]
113+ mod tests {
114+ #[ test]
115+ fn bitnz ( ) {
116+ assert_eq ! ( bitnz!( 0u8 , u8 :: BITS ) , 0 ) ;
117+ for i in 1 ..=u8:: MAX {
118+ assert_eq ! ( bitnz!( i, u8 :: BITS ) , 1 ) ;
119+ }
120+ }
121+
122+ #[ test]
123+ fn nzmask32 ( ) {
124+ assert_eq ! ( super :: nzmask32( 0 ) , 0 ) ;
125+ for i in 1 ..=u8:: MAX {
126+ assert_eq ! ( super :: nzmask32( i) , u32 :: MAX ) ;
127+ }
128+ }
129+
130+ #[ test]
131+ fn nzmask64 ( ) {
132+ assert_eq ! ( super :: nzmask64( 0 ) , 0 ) ;
133+ for i in 1 ..=u8:: MAX {
134+ assert_eq ! ( super :: nzmask64( i) , u64 :: MAX ) ;
135+ }
136+ }
137+ }
0 commit comments