Repository navigation
Tracking Issue for float_semantics RFC 3514 #128288
Copy link
Copy link
Open
Labels
B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCF-float_semantics`#![feature(float_semantics)]``#![feature(float_semantics)]`T-langRelevant to the language teamRelevant to the language team
Description
This is a tracking issue for RFC 3514:
The feature gate for the issue is #![feature(float_semantics)].
About tracking issues
Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
- Accept an RFC.
- Update library documentation.
- Stabilize.
- Add documentation to the reference.
- In particular, inline asm interactions still need to be documented.
Unresolved Questions
- Should we be concerned that LLVM does not actually document that it uses IEEE float semantics? It does assume IEEE semantics in its own optimization passes.
- Are there any other targets with floating-point trouble?
- We will treat these as target-specific bugs when they show up
- What exactly is the set of "extra" NaNs for all remaining targets?
- Add target-specific NaN payloads for the missing tier 2 targets #138870 covers all tier 2 targets
- To what extend does this specification apply to platform intrinsics? On the one hand, it seems reasonable to expect platform intrinsics to have the behavior of the platform instructions. On the other hand, we implement some platform intrinsics with the portable LLVM
simdintrinsics, and those are subject to the NaN-non-determinism described above. So the current de-facto semantics of at least some platform intrinsics is that they do not match what the platform does.
Related
TODO.
cc @RalfJung @rust-lang/lang
Reacted by Diana and Ryze
Reacted by ben, kennytm, Diana and Evgeniy Dushistov
Metadata
Metadata
Assignees
Labels
B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCF-float_semantics`#![feature(float_semantics)]``#![feature(float_semantics)]`T-langRelevant to the language teamRelevant to the language team
Activity
RalfJung commentedon Jul 29, 2024
The RFC largely documents how rustc and Miri already behave. So the main task here is to write suitable documentation -- not sure where the discussion of which NaNs can be generated would even go. Probably somewhere in the reference, but ideally mentioned in the
f32/f64type docs as well, or so?The other main outcome of this is that can we proceed with stabilization of #57241.
Rollup merge of rust-lang#128596 - RalfJung:const_fn_floating_point_a…
Rollup merge of rust-lang#128596 - RalfJung:const_fn_floating_point_a…
Unrolled build for rust-lang#128596
Rollup merge of #128596 - RalfJung:const_fn_floating_point_arithmetic…
Rollup merge of rust-lang#129559 - RalfJung:float-nan-semantics, r=th…
Rollup merge of rust-lang#129559 - RalfJung:float-nan-semantics, r=th…
Unrolled build for rust-lang#129559
Rollup merge of #129559 - RalfJung:float-nan-semantics, r=thomcc
RalfJung commentedon Oct 5, 2024
With #129559 having landed, is there anything else left to do here?
RalfJung commentedon Oct 11, 2024
As of llvm/llvm-project#102140, LLVM now also properly documents the guarantees that we promise to our users -- just in time for the release. :D
bstrie commentedon Mar 22, 2025
Going over the checkmarks listed in the issue:
I don't think this issue needs to consider updating the reference. The specific guarantees around floating-point semantics are well-documented in the library API docs, and the reference doesn't tend to concern itself with library specifics.
If the reference contained any language suggesting that const evaluation is deterministic in all cases, then we'd need to correct that, but I can't find any language to that effect. To be clear, the reference probably should talk about the semantic guarantees of const evaluation, but the lack of that is a broader issue, not specific to this feature.
This isn't an actionable question because we the list of targets is unbounded. If there are such troubles then those are likely soundness bugs, and since this feature is already stable, those should be filed as separate issues, there's nothing to block closing this.
The library docs already make a best-effort attempt at this. If they can be fleshed out further in the future, that can be tracked in separate issues.
I'm unclear regarding the desired result of asking this question. Intrinsics are perma-unstable, so their behavior can be changed at any time. If some of the wrapper functions that we use to provide stable interfaces to intrinsics are impacted by such a decision, then that's a concern for the documentation of those wrapper functions, but AFAIK the stdlib makes few (no?) strong guarantees about what intrinsics it lowers to, and if it wants to clarify those guarantees, that's a separate issue from this one.
So ultimately I think there's nothing left to do here and a member of the lang team can close this.
RalfJung commentedon Mar 22, 2025
The "platform intrinsics" point refers to the operations in
core::arch, many of which are stable.Regarding the "extra" NaN patterns, it'd be good to figure this out at least for powerpc and s390x, to cover our tier 2 targets with host tools. To cover all tier 2 targets we also need loongarch64 and nvptx64.
bstrie commentedon Mar 23, 2025
core::arch is staggeringly huge, can we get a concrete example? Also, even if they're stable, they're not/will never be const-stable, correct?
Shall we make it an explicit tier requirement for targets to document this before they can be promoted? At the same time, the documentation is explicit that unmentioned targets may have any NaN payload, which is something that we can trivially relax at any point in the future. And I'm actually somewhat wary of documenting these values because we can't control whether the targets will have a change of heart and decide to add more possible payloads in the future.
bstrie commentedon Mar 23, 2025
Regarding updating the reference, I'd like to ask whether or not the docs for inline assembly are considered sufficiently precise to capture the language in the RFC. There's plenty of stuff in the docs about preserving FP registers, but maybe it would be useful to state the requirements plainly as the RFC does.
RalfJung commentedon Mar 24, 2025
Just anything that performs float arithmetic will do. I am sure those intrinsics exist there, I just don't know how they will be called. :)
And specifically ARM NEON does not follow the spec we have laid down for scalar operations, see #129880. I assume in this case we want to say the intrinsics behave like the vendor intended, not like "normal" Rust float ops?
Probably not, but that doesn't relief us from defining their semantics.
I think it is enough to document what we can find out about our existing tier 2 targets, as your PR does. As you said, newly promoted targets will be correct by default, and if anyone cares they can file an issue.
What specifically are you referring to here?
bstrie commentedon Mar 30, 2025
The RFC's section "Assumptions about floating-point environment" includes language like "when leaving the inline assembly block, the floating-point control bits must be in exactly the same state as when the inline assembly block was entered". The reference's section on inline assembly ( https://doc.rust-lang.org/nightly/reference/inline-assembly.html ) doesn't have general language to this effect, instead it has stuff like "These flags registers must be restored upon exiting the assembly code if the preserves_flags option is set [lists some specific FP flags for some specific platforms, among others]", or "On x86, the x87 floating-point register stack must remain unchanged unless [...]". It seems to be more concerned with specifics and have more implied exceptions than the blanket statement in the RFC would suggest, at least to me.
RalfJung commentedon Mar 31, 2025
Ah, good point. Yes, all parts of the "FP control machinery" must be left unchanged or restored to their original value. Also, the initial state of the "FP control machinery" (e.g. exception flags) when the asm block starts is entirely unspecified and not correlated with what previous Rust code or previous inline asm blocks did in any way.
@Amanieu what would be the best way to specify this? I lack the low-level knowledge to properly express this.
programmerjake commentedon Mar 31, 2025
fp flags generally have two parts: control bits (current rounding mode, if fp exceptions cause interrupts or are ignored, things like enabling treating denormals as zero, etc.) and status bits (if a underflow occurred, if a division by zero occurred, etc.). generally any rust code isn't permitted to change the control bits from the defaults, and llvm is allowed to arbitrarily change the status bits and ignores whatever values the status bits have.
therefore, i think it's reasonable for inline asm to (unless marked with
preserves_flags) change the status however it likes, but the control bits must be restored to their default values before exiting any inline asm block (this includes calling other functions from in inline asm) if the control bits were changed in inline asm.Amanieu commentedon Mar 31, 2025
Essentially this boils down to properly specifying the calling convention. Specifically, what the FPU control mode should be set to on entry to a function and what it is set to on exit. Since inline asm is fundamentally just an FFI call, we just need to specify this as part of the asm "calling convention". This is also relevant for
extern "C"where C code needs to be careful to call Rust code with the proper FPU control mode.This would have to be specified separately for each architecture, for example:
On x86:
On ARM:
DemiMarie commentedon Apr 2, 2025
See #139277: There are platforms and use-cases on which supporting denormal numbers is impractial, either because it breaks real-time guarantees (which are required by the application), requires OS support that is not present, or is (in the case of at least some GPUs) simply not possible. Audio DSP on x86-64 is one example of such a use-case. Writing Metal shaders in Rust is another.
Rollup merge of rust-lang#138870 - beetrees:tier-2-nans, r=RalfJung
Rollup merge of rust-lang#138870 - beetrees:tier-2-nans, r=RalfJung
Unrolled build for rust-lang#138870
Rollup merge of rust-lang#138870 - beetrees:tier-2-nans, r=RalfJung
im-0 commentedon Sep 20, 2025
If anybody is interested in a benchmark for a subnormal numbers, I made one: https://github.com/im-0/rust-denormals-bench
It demonstrates a 50x performance degradation on a modern Intel CPU.