Come informare l'ottimizzatore che NonZeroU32 :: get non restituirà mai zero?

Nov 16 2020

Ecco il codice di esempio in cui mi sono imbattuto nel 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 di Godbolt -Ogenera lo stesso assembly per entrambe le funzioni:

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

Tuttavia, è staticamente noto che il controllo NonZeroU32::getdel risultato di contro zero è inutile. Posso in qualche modo far credere all'ottimizzatore (magari creando nuovi messaggi structper questo) in un unsafemodo minore?

Problema GitHub correlato # 49572

Risposte

1 Ohad Dec 29 2020 at 14:46

Dopo aver visto la tua domanda, ho aggiunto le impls necessarie a std, quindi ora il rilascio notturno (e la prossima versione stabile 1.51) lo supporta!

Godbolt per

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 l'assemblaggio previsto:

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