Missed optimization: When debuginfo is on, is_power_of_two does not imply nonzero.
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the Godbolt examples with rustc 1.87.0-nightly, comparing -Copt-level=3 with -Cdebuginfo=2 and -Cdebuginfo=0. Trace how assert_unchecked, is_power_of_two, and LLVM optimization interact in the compiler's debuginfo path. Done means the optimized assembly remains equivalent when debuginfo is enabled, including both foo and bar.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100