Skip to content

Missed optimization: When debuginfo is on, is_power_of_two does not imply nonzero. #137359

Open
@theemathas

Description

@theemathas

I compiled the following code (Godbolt):

use std::hint::assert_unchecked;

#[no_mangle]
unsafe fn foo(x: u32) -> bool {
    assert_unchecked(x.is_power_of_two());
    x == 0
}

With -Copt-level=3 -Cdebuginfo=2, I got this assembly:

foo:
        test    edi, edi
        sete    al
        ret

In the above assembly, the compiler doesn't realize that x being a power of two implies that it is not zero.

However, with -Copt-level=3 -Cdebuginfo=0, I got this assembly:

foo:
        xor     eax, eax
        ret

That is, the compiler correctly optimizes the code to always returning false.

I expect debuginfo to not impact the amount of optimization, so I'm assuming that this is a bug.

Additional context

This was discovered while checking whether x % y is optimized when y is known to be a power of two.

I compiled the following code (Godbolt):

use std::hint::assert_unchecked;

#[no_mangle]
unsafe fn foo(x: u32, y: u32) -> u32 {
    assert_unchecked(y.is_power_of_two());
    x % y
}

#[no_mangle]
unsafe fn bar(x: u32, y: u32) -> u32 {
    assert_unchecked(y != 0 && y.is_power_of_two());
    x % y
}

With -Copt-level=3 -Cdebuginfo=2, I got this assembly:

foo:
        test    esi, esi
        je      .LBB0_2
        mov     eax, edi
        xor     edx, edx
        div     esi
        mov     eax, edx
        ret
.LBB0_2:
        push    rax
        lea     rdi, [rip + .L__unnamed_1]
        call    qword ptr [rip + core::panicking::panic_const::panic_const_rem_by_zero::h39e69d103ed030d2@GOTPCREL]

bar:
        lea     eax, [rsi - 1]
        and     eax, edi
        ret

.L__unnamed_2:
        .ascii  "/app/example.rs"

.L__unnamed_1:
        .quad   .L__unnamed_2
        .asciz  "\017\000\000\000\000\000\000\000\006\000\000\000\005\000\000"

However, with -Copt-level=3 -Cdebuginfo=0, I got this assembly:

foo:
        lea     eax, [rsi - 1]
        and     eax, edi
        ret

bar:
        lea     eax, [rsi - 1]
        and     eax, edi
        ret

This seems to imply that LLVM can make use of the fact that is_power_of_two returns true to do optimizations. However, for some reason, when debuginfo is on, it can't figure out that is_power_of_two implies that the number is not zero.

Meta

The issue is reproducible on Godbolt with version info:

rustc 1.87.0-nightly (f280acf4c 2025-02-19)
binary: rustc
commit-hash: f280acf4c743806abbbbcfe65050ac52ec4bdec0
commit-date: 2025-02-19
host: x86_64-unknown-linux-gnu
release: 1.87.0-nightly
LLVM version: 20.1.0
Internal compiler ID: nightly

@rustbot labels +C-optimization +A-debuginfo

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)C-bugCategory: This is a bug.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions