Skip to content

Removing trailing zeros of a NonZero #138497

Open
@leonardo-m

Description

@leonardo-m

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions