-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[IR] LangRef: state explicitly that floats generally behave according to IEEE-754 #102140
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
Changes from 1 commit
d643f2c
648d3ce
d107aa0
cd80e84
7d4deb8
29f5c14
f909f35
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3572,6 +3572,29 @@ or ``syncscope("<target-scope>")`` *synchronizes with* and participates in the | |
seq\_cst total orderings of other operations that are not marked | ||
``syncscope("singlethread")`` or ``syncscope("<target-scope>")``. | ||
|
||
.. _floatsem: | ||
|
||
Floating-Point Semantics | ||
------------------------ | ||
|
||
LLVM floating-point types fall into two categories: | ||
|
||
- half, float, double, and fp128, which correspond to the binary16, binary32, | ||
binary64, and binary128 formats described in the IEEE-754 specification. | ||
- The remaining types, which do not directly correspond to a standard IEEE | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also the denormal exception There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the denormal exception? Is this about what happens when Given that IEEE says that denormals are not flushed and LLVM assumes the same by default, I don't think this is an exception from "IR float ops behave according to IEEE". |
||
format. | ||
|
||
For types that do correspond to an IEEE format, LLVM IR float operations behave | ||
like the corresponding operations in IEEE-754, with two exceptions: LLVM makes | ||
:ref:`specific assumptions about the state of the floating-point environment | ||
<floatenv>` and it implements :ref:`different rules for operations that return | ||
NaN values <floatnan>`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm struggling to come up with good wordsmithing here. It's not the case that there are two exceptions to IEEE-754 here. As @arsenm notes, we don't necessarily agree with IEEE 754 on denormal values. Also, we (rather explicitly) don't guarantee the side-effect on flags or exceptions of IEEE 754 semantics. The more we try to fine-tune the text to make "it's exactly IEEE 754 BUT", the more I think we obscure what the actual thing we're trying to state is. This is a quick attempt I have of a direction that makes more sense to me:
(This still doesn't cover denormal behavior, because that's non-default floating-point environment, but I'm not sure I have a firm grip on what the denormal guarantees we want to make in the first place are!) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I gave it a shot, based on your suggestion but structuring things a bit differently. |
||
|
||
This means that optimizations and backends cannot change the precision of these | ||
operations (unless there are fast-math flags), and frontends can rely on these | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean by "floating-point instruction" here? Is sqrt included? I understand that the main point here is to say that without further IR constructs an instruction like fdiv is assumed to be correctly rounded. IEEE-754 also assumes this of sqrt. I believe the latest version specifies that other math functions should also return correctly rounded results. That's why I think it needs to be explicit here which ones you mean. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant all the operations that have an equivalent IEEE-754 operation. So yes that would include sqrt, though I was under the impression that it does not include transcendental functions. I am not sure what is the best way to say that. Having a list seems awkward? Should each such operation have a comment, like "This corresponds to <op> in IEEE-754, so if the argument is an IEEE float format then the :ref: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is something that is hard to come up with a good term for. IEEE 754 has a core list of operations in section 5 which is a good starting point, but these omit the minimum/maximum operations (which are section 9.6). Section 9 is "recommended operations", and 9.2 is the main list of transcendental functions you're thinking of; IEEE 754 requires that they be correctly rounded, but C explicitly disclaims that requirement in Annex F. There's also a few functions in C that aren't in IEEE 754, notably ldexp and frexp. (Note too that it was recently brought up in the Discourse forums that the libm intrinsics are meant to correspond to libm semantics, not IEEE 754 semantics.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minimum/maximum don't do any rounding, and already seem to unambiguously describe their semantics in the existing docs, making this clarification much less relevant. So maybe we should just say that this is about the core operations listed in section 5? |
||
operations deterministically providing perfectly rounded results as described | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to specify "all machines that support IEEE-754 arithmetic"? I don't know if we support any targets that don't support IEEE-754, but it seems like there should be some provision for that. The C standard, for instance, talks about some transformations that are legal on "IEC 60559 machines." Or are we saying that architectures that don't support IEEE-754 should indicate the differences in the IR or use a different type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now, LLVM assumes that all backends implement IEEE-754 arithmetic, and will miscompile code if the backend doesn't do that. One example of a target that does not implement IEEE-754 arithmetic is x86 without SSE, and #89885 has examples of code that gets micompiled due to that. The point of this PR is to make that more explicit. If instead the goal is to make LLVM work with backends and targets that do not implement IEEE-754 arithmetic, that will require changes to optimization passes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're already at the point where we expect The only hardware deviation from IEEE 754 that we're prepared to accept at this point is denormal handling. I'm reluctant to offer too many guarantees on denormal handling because I'm not up to speed on the diversity of common FP hardware with respect to denormals, but I'm pretty sure there is hardware in use that mandates denormal flushing (e.g., the AVX512-BF16 stuff is unconditionally default RM+DAZ+FTZ, with changing MXCSR having no effect). In short, we already require that hardware supporting LLVM be IEEE 754-ish; this is tightening up the definition in the LangRef to cover what we already agree to be the case. In the putative future that we start talking about cases where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Even there, the pass that causes trouble in #89885 would lead to miscompilations. So non-standard denormal handling is only supported with an explicit marker, which works very similar to the markers required for non-default FP exception handling. |
||
in the standard (except when a NaN is returned). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would add "This also means that backends are not allowed to implement floating-point instructions using larger floating-point types unless they take care to consistently narrow the results back to the original range without inducing double-rounding." or some similar text that makes it clear that mapping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO that is covered by "backends cannot change the precision of these operations". If we start listing all the consequences of that statement, we'll never be done... |
||
|
||
.. _floatenv: | ||
|
||
Floating-Point Environment | ||
|
@@ -3608,10 +3631,11 @@ are not "floating-point math operations": ``fneg``, ``llvm.fabs``, and | |
``llvm.copysign``. These operations act directly on the underlying bit | ||
representation and never change anything except possibly for the sign bit. | ||
|
||
For floating-point math operations, unless specified otherwise, the following | ||
rules apply when a NaN value is returned: the result has a non-deterministic | ||
sign; the quiet bit and payload are non-deterministically chosen from the | ||
following set of options: | ||
Floating-point math operations that return a NaN are an exception from the | ||
general principle that LLVM implements IEEE-754 semantics. Unless specified | ||
otherwise, the following rules apply when a NaN value is returned: the result | ||
has a non-deterministic sign; the quiet bit and payload are | ||
non-deterministically chosen from the following set of options: | ||
|
||
- The quiet bit is set and the payload is all-zero. ("Preferred NaN" case) | ||
- The quiet bit is set and the payload is copied from any input operand that is | ||
|
Uh oh!
There was an error while loading. Please reload this page.