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