Skip to content

Commit 8016846

Browse files
authored
Rollup merge of #81107 - scottmcm:nonzero-is_power_of_two, r=kennytm
Add NonZeroUn::is_power_of_two This saves instructions on both new and old machines <https://rust.godbolt.org/z/4fjTMz> - On the default x64 target (with no fancy instructions available) it saves a few instructions by not needing to also check for zero. - On newer targets (with BMI1) it uses `BLSR` for super-short assembly. This can be used for things like checks against alignments stored in `NonZeroUsize`.
2 parents 7e2425a + 3e16e92 commit 8016846

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

library/core/src/num/nonzero.rs

+40
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,43 @@ nonzero_integers_div! {
286286
NonZeroU128(u128);
287287
NonZeroUsize(usize);
288288
}
289+
290+
macro_rules! nonzero_unsigned_is_power_of_two {
291+
( $( $Ty: ident )+ ) => {
292+
$(
293+
impl $Ty {
294+
295+
/// Returns `true` if and only if `self == (1 << k)` for some `k`.
296+
///
297+
/// On many architectures, this function can perform better than `is_power_of_two()`
298+
/// on the underlying integer type, as special handling of zero can be avoided.
299+
///
300+
/// # Examples
301+
///
302+
/// Basic usage:
303+
///
304+
/// ```
305+
/// #![feature(nonzero_is_power_of_two)]
306+
///
307+
#[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
308+
/// assert!(eight.is_power_of_two());
309+
#[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
310+
/// assert!(!ten.is_power_of_two());
311+
/// ```
312+
#[unstable(feature = "nonzero_is_power_of_two", issue = "81106")]
313+
#[inline]
314+
pub const fn is_power_of_two(self) -> bool {
315+
// LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
316+
// On the basic x86-64 target, this saves 3 instructions for the zero check.
317+
// On x86_64 with BMI1, being nonzero lets it codegen to `BLSR`, which saves an instruction
318+
// compared to the `POPCNT` implementation on the underlying integer type.
319+
320+
intrinsics::ctpop(self.get()) < 2
321+
}
322+
323+
}
324+
)+
325+
}
326+
}
327+
328+
nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize }

0 commit comments

Comments
 (0)