Open
Description
If a u8 or u64 is non zero, then removing all its trailing zeros should still always produce a non zero value. It seems LLVM isn't able to see that:
use std::num::NonZero;
#[inline(never)]
pub fn remove_trailing_zeros(x: NonZero<u8>) -> NonZero<u8> {
NonZero::new(x.get() >> x.trailing_zeros()).unwrap()
}
fn main() {
for i in 1_u8 ..= 255 {
let nzi = NonZero::new(i).unwrap();
println!("{:?}", remove_trailing_zeros(nzi));
}
}
rustc 1.87.0-nightly (6650252 2025-03-11) generates:
remove_trailing_zeros:
tzcnt rax, rdi
shrx rax, rdi, rax
test rax, rax
je .LBB0_2
ret
.LBB0_2:
push rax
lea rdi, [rip + .Lanon.3bf69852bd0f87f34a431b46baed8d35.1]
call qword ptr [rip + core::option::unwrap_failed::h2026bc009ac871c4@GOTPCREL]
I'd like rustc to remove the unwrap_failed test, or perhaps better to add NonZero::remove_trailing_zeros methods.