-
Notifications
You must be signed in to change notification settings - Fork 13.3k
mul_add
on *-pc-windows-gnu
returns incorrect results
#140515
New issue
Have a question about this project? No Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “No Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? No Sign in to your account
Comments
@rustbot label +I-unsound +O-windows-gnu +A-floating-point |
Can it lead to actually unsound optimisations in practice or is this more a theoretical? |
The fix for scalar evolution of functions which aren't guaranteed correctly rounded (llvm/llvm-project#90942) fixed the issue by just not doing scalar evolution on any libcalls which return floating-point numbers (relevant code), so scalar evolution won't be an issue in practice at the moment. I don't know if there are any other optimisations that depend on FMA having correct results. |
This will also affect Miri when run on a |
For that target could we just override the provided cc @tgross35 |
As beetrees noted on Zulip we'll lose any LLVM optimizations, but that seems tolerable. This could be a (It would be convenient if LLVM had a mechanism to change fallback libcall names without losing optimizations) |
Didn't betrees say that we already don't get the LLVM optimizations, since they are inhibited any time a libcall is used? Also, they referred only to scalar evolution -- I assume we'd still get all the basic operations, in particular const-folding. |
If compiler-builtins provides the |
If we call I don't think we have a way to provide the actual symbol |
The only optimisation that's inhibited for FMA (and other LLVM intrinsics) by LLVM at the moment is scalar evolution. FMA is still const-folded etc., and LLVM can re-arrange code on the assumption it doesn't have any side-effects. |
I don't think we need weak linkage we just need to provide the symbol, no? Usually the linker can't find the symbol so it goes looking in native libraries. If we provide it instead then it won't go looking elsewhere for it. |
I was thinking the mingw toolchain didn’t pick the right one for some reason, but must be misremembering. You’re right, it should just work. Any reason not to remove windows-gnu from the list of exceptions at https://github.com/rust-lang/compiler-builtins/blob/f456aa8baf0b108208332dc4bed63b6e70639b67/compiler-builtins/src/math/mod.rs#L41-L77 and use our versions for that whole list? |
I mean I have no particular objection to that but I also don't know how our implementations compare to MinGW's. cc @mati865 |
Per [1], MinGW has an incorrect fma implementation. This showed up in tests run with cranelift after adding float math operations to `core`. Presumably we hadn't noticed this when running tests with LLVM because LLVM was constant folding the result away. Rust issue: rust-lang#140515 [1]: https://sourceforge.net/p/mingw-w64/bugs/848/
Per [1], MinGW has an incorrect fma implementation. This showed up in tests run with cranelift after adding float math operations to `core`. Presumably we hadn't noticed this when running tests with LLVM because LLVM was constant folding the result away. Rust issue: rust-lang#140515 [1]: https://sourceforge.net/p/mingw-w64/bugs/848/
Faulty mingw-w64 implementation is used only with MSVCR* system C libraries which lack that function. UCRT provides that function, so it should work fine: The only sensible reason for sticking with MSVCRT is backward compatibility: Rust distributes the rust-mingw component (only on Enough talk, let's verify that.
Then with GCC + mingw-w64 targeting UCRT available in PATH:
I believe no changes to Rust code are necessary; users should really use UCRT C toolchains, and that's it (there are many other issues with MSVCRT, other math functions, locales, and so on). Someday Rust should also migrate |
Is running CI with UCRT something we can/should do, or did you mean that by migrating |
Migrating CI from the MSVCRT toolchain to the UCRT one will also affect rust-mingw, although a workaround is possible. MinGW-w64 provides libmsvcrt.a, which is the default CRT, so either MSVCRT or UCRT (the naming is unfortunate, but that's what you get for retaining compatibility; it used to mean MSCVRT). But also libmsvcrt-os.a that is always MSCVRT and libucrt.a that is always UCRT. But all DLLs shipped by Rust (like std-xxx.dll) would then use UCRT. |
To clarify - are you suggesting that workaround is something we should actually eventually do? Unless there is a better workaround, I'm tempted to say we should switch to our libm for now and plan to switch back after we start linking to a known good version, either with the CRT change or with an upstream fix. |
Kind of, yes. I'd recommend making it official: state that MSVCRT will still work, but is not fully supported—results may vary (quite literally as you can see). The libm workaround may be viable for the time being. What are its downsides? Perhaps I should have mentioned this before. MSYS2 made the UCRT toolchain its default on 2022-10-29 (you can find the news entry at https://www.msys2.org/news/). Mingw-w64 did the same eight months later: mingw-w64/mingw-w64@82b8edc. That change was released with version v12 on 2024-05-29. |
There shouldn't be any downsides except, possibly, perf. I don't know how well optimised our implementations are. I mean, assuming it's not breaking the calling convention anywhere (which is sometimes a hazard if hand-rolling assembly). |
Add Windows-GNU to the group of targets that gets our version of basic libm symbols available through compiler-builtins. This is done to avoid bugs in the platform `fma`, see [1]. [1]: rust-lang/rust#140515
Perf is pretty close to musl in most cases and I assume others are roughly comparable, though we do lose dynamic linking. rust-lang/compiler-builtins#896 will help significantly for fma in particular, at least on modern CPUs. I would be interested to see some benchmarks in any case. Anyway, a patch to do this is at rust-lang/compiler-builtins#900. |
This is a known problem in the MinGW fmaf implementation, identified at [1]. Make sure our implementation passes this edge case. [1]: rust-lang/rust#140515
This is a known problem in the MinGW fmaf implementation, identified at [1]. Make sure our implementation passes this edge case. [1]: rust-lang/rust#140515
I tried this code (test case taken from this comment):
I expected to see this happen: The correct result should be printed as
mul_add
is guaranteed to return the correctly rounded result, which is -4167095.8.Instead, this happened: On both
i686-pc-windows-gnu
andx86_64-pc-windows-gnu
, -4167095.5 is printed instead. This is due to the FMA implementation in MinGW being incorrect (upstream bug report). This is unsound as LLVM is allowed to rely on FMA returning correct results when optimising.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: