Skip to content

rustc 1.48.0+ generates branchier and less compact code for integer division w/ boundary checks #99961

Closed as not planned
@mqudsi

Description

@mqudsi

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
    }
}

Godbolt comparison link

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-codegenArea: Code generationC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions