¿Cómo informar al optimizador que NonZeroU32 :: get nunca devolverá cero?

Nov 16 2020

Aquí está el ejemplo de código donde encontré el problema:

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
}

Rustc 1.47.0 de Godbolt -Ogenera el mismo ensamblaje para ambas funciones:

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

Sin embargo, se sabe estáticamente que NonZeroU32::getla comparación del resultado con cero no tiene sentido. ¿Puedo de alguna manera hacer que el optimizador lo crea (tal vez creando nuevos correos structelectrónicos para esto) de una unsafemanera menos?

Problema relacionado de GitHub # 49572

Respuestas

1 Ohad Dec 29 2020 at 14:46

Después de ver su pregunta, agregué los impls necesarios a std, ¡así que ahora el lanzamiento nocturno (y el próximo lanzamiento estable 1.51) lo admite!

Godbolt para

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
}

Produce el montaje esperado:

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