-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
retand 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 (573a015 2025-06-12)
@rustbot label +A-codegen +T-compiler