Description
The following code, which correctly bypasses overflow and divide by zero conditions, generates branchier and less optimal machine code (under x86_64) when compiled under rustc 1.48.0+ as compared to rustc 1.46.0 and below:
pub fn checked_div_i64(dividend: i64, divisor: i64) -> Option<i64> {
if dividend > i64::min_value() && divisor != 0 {
Some(dividend / divisor)
} else {
None
}
}
The assembly generated in 1.46.0:
example::checked_div_i64:
xor eax, eax
movabs rcx, -9223372036854775808
cmp rdi, rcx
je .LBB0_3
test rsi, rsi
je .LBB0_3
mov rax, rdi
cqo
idiv rsi
mov rdx, rax
mov eax, 1
.LBB0_3:
ret
vs in 1.48.0:
example::checked_div_i64:
xor eax, eax
movabs rcx, -9223372036854775808
cmp rdi, rcx
je .LBB0_6
test rsi, rsi
je .LBB0_6
mov rax, rdi
or rax, rsi
shr rax, 32
je .LBB0_3
mov rax, rdi
cqo
idiv rsi
mov rdx, rax
jmp .LBB0_5
.LBB0_3:
mov eax, edi
xor edx, edx
div esi
mov edx, eax
.LBB0_5:
mov eax, 1
.LBB0_6:
ret
The astute will observe that rustc 1.47.0 was skipped in the good/bad demarcation above. That's because rustc 1.47.0 introduced an incorrect checked division w/ panic (which is now happening again). My gut feeling is that whatever fixed 1.47's dismal codegen resulted in a still-suboptimal solution as compared to what we had before.
The problem still persists in the latest nightlies, but is obscured by #99960.
@rustbot label +regression-from-stable-to-stable +A-codegen +A-llvm +T-compiler