rust-lang / rust-lang/rust

Unable to induce constant float folding via `assert_eq!(x, 0.0)`

Open
#147,646 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-codegen A-floating-point A-LLVM C-optimization T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I have a performance-sensitive pipeline that accepts data of a shape where some of the floating point elements are known (to me) to currently always be zero, but I don't want to remove the operations from the code lest that change in the future. I was hoping to be able to assert_eq!() my way into getting the compiler to perform constant folding on the mathematical operation but found that it does not work as expected.

A test case that reproduces the issue:

#[no_mangle]
pub extern "C" fn one(x: f32, y: f32, z: f32) -> f32 {
    unsafe { std::hint::assert_unchecked(y == 0.0); }
    x*9.0 + y*8.0 + z
}

#[no_mangle]
pub extern "C" fn two(x: f32, y: f32, z: f32) -> f32 {
    let y = 0.0;
    x*9.0 + y*8.0 + z
}

giving the following x86_64 (optimized) assembly:

.LCPI0_0:
        .long   0x41100000
.LCPI0_1:
        .long   0x41000000
one:
        vmulss  xmm0, xmm0, dword ptr [rip + .LCPI0_0]
        vmulss  xmm1, xmm1, dword ptr [rip + .LCPI0_1]
        vaddss  xmm0, xmm0, xmm1
        vaddss  xmm0, xmm2, xmm0
        ret

.LCPI1_0:
        .long   0x41100000
two:
        vmulss  xmm0, xmm0, dword ptr [rip + .LCPI1_0]
        vxorps  xmm1, xmm1, xmm1
        vaddss  xmm0, xmm0, xmm1
        vaddss  xmm0, xmm0, xmm2
        ret

and a link to the godbolt disassembly

I am using assert_unchecked() rather than assert_eq!() just to simplify the assembly output for diagnostic purposes, but the intent is to test whether or not the compiler can elide the mul with a "constant" zero. The codegen from one() does not benefit from the assert_unchecked(y == 0.0) call, and performs the same codegen with or without it, while the code in two() demonstrates that, in the general case, rust is able to fold away the multiplication with a constant, but that for $reasons, it currently isn't able to do so after asserting the value.

The obvious workaround would be to use something like the following:

assert_eq!(y, 0.0);
let y = 0.0;

Tested with 1.90.0 stable and rustc 1.89.0-nightly (573a01569 2025-06-12)

@rustbot label +A-codegen +T-compiler

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by compiling the one and two functions from the issue in optimized mode and compare their x86_64 assembly using the linked Godbolt reproduction. Trace the compiler codegen path for assert_unchecked(y == 0.0) and floating-point constant propagation; done means the asserted case receives the intended optimized codegen or the limitation is documented with a focused regression test.

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
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.