How to inform the optimizer that NonZeroU32::get will never return zero?

Viewed 229

Here's the code sample where I ran into the problem:

pub fn div(x: u32, y: u32) -> u32 {
    x / y
}
pub fn safe_div(x: u32, y: std::num::NonZeroU32) -> u32 {
    x / y.get() // an unchecked division expected
}

Godbolt's rustc 1.47.0 -O generates the same assembly for both functions:

example::div:
        push    rax
        test    esi, esi
        je      .LBB0_2
        mov     eax, edi
        xor     edx, edx
        div     esi
        pop     rcx
        ret
.LBB0_2:
        lea     rdi, [rip + str.0]
        lea     rdx, [rip + .L__unnamed_1]
        mov     esi, 25
        call    qword ptr [rip + core::panicking::panic@GOTPCREL]
        ud2

example::safe_div:
        push    rax
        test    esi, esi
        je      .LBB1_2
        mov     eax, edi
        xor     edx, edx
        div     esi
        pop     rcx
        ret
.LBB1_2:
        lea     rdi, [rip + str.0]
        lea     rdx, [rip + .L__unnamed_2]
        mov     esi, 25
        call    qword ptr [rip + core::panicking::panic@GOTPCREL]
        ud2

However, it is statically known that checking NonZeroU32::get's result against zero is pointless. Can I somehow make the optimizer believe it (maybe with creating new structs for this) in an unsafeless way?

Related GitHub issue #49572

1 Answers

After I saw your question, I added the needed impls to std, so now the nightly release (and the upcoming 1.51 stable release) supports this!

Godbolt for

pub fn div(x: u32, y: u32) -> u32 {
    x / y
}

pub fn safe_div(x: u32, y: std::num::NonZeroU32) -> u32 {
    x / y
}

pub fn safe_rem(x: u32, y: std::num::NonZeroU32) -> u32 {
    x % y
}

Produces the expected assembly:

example::div:
        push    rax
        test    esi, esi
        je      .LBB0_2
        mov     eax, edi
        xor     edx, edx
        div     esi
        pop     rcx
        ret
.LBB0_2:
        lea     rdi, [rip + str.0]
        lea     rdx, [rip + .L__unnamed_1]
        mov     esi, 25
        call    qword ptr [rip + core::panicking::panic@GOTPCREL]
        ud2

example::safe_div:
        mov     eax, edi
        xor     edx, edx
        div     esi
        ret

example::safe_rem:
        mov     eax, edi
        xor     edx, edx
        div     esi
        mov     eax, edx
        ret
Related