-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “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? Sign in to your account
Tracking issue for float_bits_conv feature #40470
Comments
Add functions to safely transmute float to int The safe subset of Rust tries to be as powerful as possible. While it is very powerful already, its currently impossible to safely transmute integers to floats. While crates exist that provide a safe interface, most prominently the `iee754` crate (which also inspired naming of the added functions), they themselves only use the unsafe `mem::transmute` function to accomplish this task. Also, including an entire crate for just two lines of unsafe code seems quite wasteful. That's why this PR adds functions to safely transmute integers to floats and vice versa, currently gated by the newly added `float_bits_conv` feature. The functions added are no niche case. Not just `ieee754` [currently implements](https://github.com/huonw/ieee754/blob/master/src/lib.rs#L441) float to int transmutation via unsafe code but also the [very popular `byteorder` crate](https://github.com/BurntSushi/byteorder/blob/1.0.0/src/lib.rs#L258). This functionality of byteorder is in turn used by higher level crates. I only give two examples out of many: [chor](https://github.com/pyfisch/cbor/blob/a7363ea9aaf372e3d24b52414b5c76552ecc91c8/src/ser.rs#L227) and [bincode](https://github.com/TyOverby/bincode/blob/f06a4cfcb5b194e54d4997c200c75b88b6c3fba4/src/serde/reader.rs#L218). One alternative would be to manually use functions like pow or multiplication by 1 to get a similar result, but they only work in the int -> float direction, and are not bit exact, and much slower (also, most likely the optimizer will never optimize it to a transmute because the conversion is not bit exact while the transmute is). Tracking issue: #40470
Add functions to safely transmute float to int The safe subset of Rust tries to be as powerful as possible. While it is very powerful already, its currently impossible to safely transmute integers to floats. While crates exist that provide a safe interface, most prominently the `iee754` crate (which also inspired naming of the added functions), they themselves only use the unsafe `mem::transmute` function to accomplish this task. Also, including an entire crate for just two lines of unsafe code seems quite wasteful. That's why this PR adds functions to safely transmute integers to floats and vice versa, currently gated by the newly added `float_bits_conv` feature. The functions added are no niche case. Not just `ieee754` [currently implements](https://github.com/huonw/ieee754/blob/master/src/lib.rs#L441) float to int transmutation via unsafe code but also the [very popular `byteorder` crate](https://github.com/BurntSushi/byteorder/blob/1.0.0/src/lib.rs#L258). This functionality of byteorder is in turn used by higher level crates. I only give two examples out of many: [chor](https://github.com/pyfisch/cbor/blob/a7363ea9aaf372e3d24b52414b5c76552ecc91c8/src/ser.rs#L227) and [bincode](https://github.com/TyOverby/bincode/blob/f06a4cfcb5b194e54d4997c200c75b88b6c3fba4/src/serde/reader.rs#L218). One alternative would be to manually use functions like pow or multiplication by 1 to get a similar result, but they only work in the int -> float direction, and are not bit exact, and much slower (also, most likely the optimizer will never optimize it to a transmute because the conversion is not bit exact while the transmute is). Tracking issue: #40470
Hmm, seems this feature has broken the ieee754 crate:
Apparently you can't shadow functions with a trait: https://is.gd/oKiVZH (the first assert works, but the second fails) |
Is the issue above something we have to fix, or rather something the |
@est31 RFC 1105 laid out that adding inherent methods is a minor change so it's up to the team(s) to decide whether we're okay with the practical impact of the change. |
cc #43025 --- with this merged, could we get this feature stabilized in Rust 1.20? |
Team member @BurntSushi has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
@rfcbot reviewed |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period is now complete. |
1 similar comment
The final comment period is now complete. |
Stabilize float_bits_conv for Rust 1.21 Stabilizes the `float_bits_conv` lib feature for the 1.20 release of Rust. I've initially implemented the feature in #39271 and later made PR #43025 to output quiet NaNs even on platforms with different encodings, which seems to have been the only unresolved issue of the API. Due to PR #43025 being only applied to master this stabilisation can't happen for Rust 1.19 through the usual "stabilisation on beta" system that is being done for library APIs. r? @BurntSushi closes #40470.
Really late to this party. As I note here, the NaN masking is unnecessary from LLVM's perspective. I'm not totally clear on the platform-specific-NaN-reprs issue, but at least on x86/x64, we can just make If we wish to do so, this just leaves the following question: do we ignore the existence of non-2008-compliant hardware (transmute on all platforms) or do we allow behaviour to be platform-specific (transmute only on definitely-2008-compliant hardware)? |
I'm certainly on board with just transmuting on architectures we know are okay. |
Transmuting should be safe on ARM & AArch64. The only issue is whether a sNaN can cause a trap when it is used. By default floating-point exception are masked on ARM/AArch64, but can be enabled by setting some bits in the These bits also allow enabling exceptions for situations like inexact floating-point rounding, float division by zero, etc. These operations are all supported in safe Rust, so I suggest that the official Rust policy be something along the lines: "Rust assumes that all floating-point operations do not trap." |
I don't think we really care if the operation traps, right? It's not unsafe to do so. |
We do care if the trap is considered an "observable side-effect" of the operation, since this affects optimization. This would impact dead code elimination for example: you would still have to trigger the trap even if the result of the operation is not used. |
Ah sure that makes sense. |
very interesting! We need more people like you :). I am personally okay with anything (the documentation was made vague purposefully!), but before we commit to anything that we can't reverse (e.g. making docs super clear that it is only a transmute), I'd love to get @gankro 's LLVM patch merged upstream so that it has been reviewed by LLVM reviewers and deemed okay. |
Unfortunately, it is still necessary from LLVM's perspective; see https://github.com/llvm-mirror/llvm/blob/master/lib/Analysis/InstructionSimplify.cpp#L4142 for example. I support changing LLVM's behavior here, but this isn't just a case of fixing mistaken documentation; it's changing the policy, so we need to be careful. |
Interesting. That transformation is justified by sNaN being bad, but in fact doesn't look for sNaN. Rather it looks for undef, and up to this point we've fairly conservatively considered doing ~anything with undef to be UB for Rust (because undef is poorly defined and we don't want to couple with LLVM semantics anyway). As such, the existence of that transformation shouldn't actually be a barrier to us making this change? (we should still fix llvm as well) |
FWIW, that change originally came from here: llvm-mirror/llvm@50b2ca4 |
@gankro That's a good point. Allowing Rust to produce sNaNs in more places doesn't break those kinds of optimizations. And I'm not aware of any optimizations that explicitly check for sNaNs, and I've checked all the usual suspects. So this change seems ok. |
Make float::from_bits transmute See commit message for details. See also this discussion here: #40470 (comment) (may require libs team discussion before merging)
Make float::from_bits transmute See commit message for details. See also this discussion here: #40470 (comment) (may require libs team discussion before merging)
cc #46246 |
Lower the priority of unstable methods when picking a candidate. Previously, when searching for the impl of a method, we do not consider the stability of the impl. This leads to lots of insta-inference-regressions due to method ambiguity when a popular name is chosen. This has happened multiple times in Rust's history e.g. * `f64::from_bits` #40470 * `Ord::{min, max}` #42496 * `Ord::clamp` #44095 (eventually got reverted due to these breakages) * `Iterator::flatten` #48115 (recently added) This PR changes the probing order so that unstable items are considered last. If a stable item is found, the unstable items will not be considered (but a future-incompatible warning will still be emitted), thus allowing stable code continue to function without using qualified names. Once the unstable feature is stabilized, the ambiguity error will still be emitted, but the user can also use newly stable std methods, while the current situation is that downstream user is forced to update the code without any immediate benefit. (I hope that we could bring back `Ord::clamp` if this PR is merged.)
Tracking issue for the conversion
float_bits_conv
feature, added by PR #39271.The main topic during the PR's thread has been about how to handle signaling NaNs, and the final decision was to silently mask them, especially as LLVM behaviour regarding them is not well specified.
Another issue raised by @dwrensha was that sNaNs are not encoded consistently. IEEE 754-2008 (section 8.2.1 in the latest draft) specifies quiet NaNs to have their first bit of the trailing significand field set to 1, for signaling NaNs it should be set to 0. Some MIPS based platforms have it reversed. Should they be cfg'd out?
The text was updated successfully, but these errors were encountered: