Palli
November 13, 2025, 4:17pm
1
I noticed:
opened 12:42PM - 05 Sep 23 UTC
C-tracking-issue
A-floating-point
A-ABI
O-x86_32
On x86 (32bit) targets, returning a floating-point number from a "C" ABI functi… on by-value can change the bits of their NaN payloads. (Specifically, the quiet bit gets set.) This is caused by using x87 registers to pass return values, as mandated by the ABI for this target.
This is a known and long-standing problem, and very hard to fix. The purpose of this issue mostly is to document its existence and to give it a URL that can be referenced.
A proper fix would require patching LLVM to use different code to load float return values into an x87 register -- specifically, it has to be done in a way that NaN payloads are fully preserved.
Related issues:
- https://github.com/llvm/llvm-project/issues/66803: the same bug on the LLVM side.
- https://github.com/rust-lang/rust/issues/114479: that's a different problem, also affecting x86-32 but concerning the actual FP computations, not the NaN bits of return values.
Prior issues:
- https://github.com/rust-lang/rust/issues/73288
- https://github.com/rust-lang/rust/issues/46948
opened 06:46PM - 04 Aug 23 UTC
P-medium
I-unsound
C-tracking-issue
A-floating-point
O-x86_32
I-miscompile
On x86 (32bit) targets that cannot use SSE2 instructions (this includes the tier… 1 i686 targets with flags that disable SSE2 support, such as `-C target-cpu=pentium`), floating-point operation can return results that are rounded in different ways than they should, and results can be "inconsistent": depending on whether const-propagation happened, the same computation can produce different results, leading to a program that seemingly contradicts itself. This is caused by using x87 instructions to perform floating-point arithmetic, which do not accurately implement IEEE floating-point semantics (not with the right precision, anyway). The test `tests/ui/numbers-arithmetic/issue-105626.rs` has an example of such a problem.
Worse, LLVM can use x87 register to store values it thinks are floats, which resets the signaling bit and thus alters the value -- leading to [miscompilations](https://github.com/rust-lang/rust/issues/114479#issuecomment-2072052116).
This is an LLVM bug: rustc is generating LLVM IR with the intended semantics, but LLVM does not compile that code in the way that the LLVM LangRef describes. This is a known and long-standing problem, and very hard to fix. The affected targets are so niche these days that that is nobody's priority. Note that this problem affects all binaries built without SSE2 being globally enabled, even if these binaries are later used on systems that do have SSE2 -- the only way to avoid the problem is to not use the x87 FPU at all, i.e., generate binaries that require SSE2. The purpose of this issue mostly is to document its existence and to give it a URL that can be referenced.
Some ideas that have been floated for fixing this problem:
- We could emit different instruction sequences for floating-point operations that emulate the expected rounding behavior using x87 instructions. This will likely require changes deep in LLVM's x86 backend. This is [what Java does](https://open-std.org/JTC1/SC22/JSG/docs/m3/docs/jsgn326.pdf).
- We could use softfloats.
- ~~We could set the FPU control register to 64bit precision for Rust programs, and require other code to set the register in that way before calling into a Rust library.~~ [this does not work](https://github.com/rust-lang/rust/issues/114479#issuecomment-1808507590)
Related issues:
- https://github.com/llvm/llvm-project/issues/44218: basically the same bug on the LLVM side, and pointing out the potential for soundness issues
- https://github.com/rust-lang/rust/issues/115567: that's a different problem, also affecting x86-32 but unrelated to what happens when an FP operation is executed; it is about the behavior of NaN bits as they get returned from a function
Prior issues:
- https://github.com/rust-lang/rust/issues/72327
This is an LLVM bug: rustc is generating LLVM IR with the intended semantics
This is about Rust, but might translate to Julia (and more) since both use LLVM?!
Both have tier 1 support for 32-bit on Windows, and them on Linux too (we tier 2). [And they are now ahead with tier 1 support for ARM64 on Windows too, us tier 2 only, tier 1 for macOS though, and this is off-topic. I suppose all ARM just work for floating point.]
32-bit x86 uses floating point stack, at least for Rust, if I recall implicated. I think 64-bit doesn’t usse it (but could), neither for us, do we use it for 32-bit?