Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --rust-num/num-bigint The code prints the output below and exits successfully. The code prints the output below and panics. <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --:
Here's some reproduction on Godbolt. The problem seems unrelated to i64 and it's entirely the u64 -f32 conversion that's buggy. The fact that we use the floating point numbers as some sort of address makes it seem like we are loading the value from a lookup table and there might be a bug in Windows' table:
Took me way too long, but I figured it out. The fact that FPU instructions are used means that it runs into problems with the FPU accuracy. By default the control word is set to 0x27f on Windows and 0x37f on Linux. In particular the 0x3 vs 0x2 is the precision control setting of the FPU. 01 = Not used 10 = 53 bits (REAL8) 11 = 64 bits (REAL10) So on Windows it's in 53-bits mode whereas on Linux it's in 64-bits mode. Running the following code therefore fixes the problem on Windows: This probably is an LLVM bug where LLVM assumes the FPU is configured like on Linux instead of like on Windows. MSVC for example just emits a call to instead, which is probably the correct thing to do. (Also it's a little surprising to me the FPU is used at all, when i686 afaik even has SSE2 available by default).
The function that lowers the uint to float cast is in . There's basically a bunch of checks to generate shorter versions if various conditions are met, but all of them fail and it has to resort to using the FPU. There actually is one case in there where they treat Windows differently, I'm guessing something similar can be done to not fall into the FPU default case here as well. In particular because both SSE2 and a builtin function that does exactly this cast exist.
I tested it with some other code and thought it was resolved.
This was patched upstream (thanks icedrocket!) but it seems like they reverted the patch, as unfortunately it broke Chrome's build: I don't know if it is more profitable to work around this on our end by emitting the relevant call? It looks like there's an intention to use another fix:
A new fix has been commited to upstream: llvm/llvm-project

Discussion:
#[test] fn download_ci_llvm() { <ins> if crate::native::is_ci_llvm_modified(&parse("")) { eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); return; } </ins> let parse_llvm = |s| parse(s).llvm_from_ci; let if_available = parse_llvm("llvm.download-ci-llvm = "if-available"");

} } <del> if CiEnv::is_ci() { </del> <ins> if is_ci_llvm_modified(config) { eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); return false; } true } /// Returns true if we're running in CI with modified LLVM (and thus can't download it) pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { CiEnv::is_ci() && { </ins> // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); let head_sha = output(config.git().arg("rev-parse").arg("HEAD")); let head_sha = head_sha.trim(); <del> if llvm_sha == head_sha { eprintln!( "Detected LLVM as non-available: running in CI and modified LLVM in this change" ); return false; } </del> <ins> llvm_sha == head_sha </ins> } <del> true </del> } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]

<del> Subproject commit 477e7285b12f876ad105188cfcfc8adda7dc29aa </del> <ins> Subproject commit fd949f3034f8a422ecfffa889c2823485dde4bdd </ins>

<ins> // run-pass // only-x86 // min-system-llvm-version: 16 // compile-flags: -Ctarget-feature=+sse2 use std::hint::black_box; fn main() { let n: i64 = black_box(0x3fffffdfffffff); let r = f32::from_bits(0x5a7fffff); assert_ne!((n as f64) as f32, n as f32); // FIXME: these assertions fail if only x87 is enabled assert_eq!(n as i64 as f32, r); assert_eq!(n as u64 as f32, r); } </ins>