Skip to content

Commit a8a6624

Browse files
authored
[IR] LangRef: state explicitly that floats generally behave according to IEEE-754 (llvm#102140)
Fixes llvm#60942: IEEE semantics is likely what many frontends want (it definitely is what Rust wants), and it is what LLVM passes already assume when they use APFloat to propagate float operations. This does not reflect what happens on x87, but what happens there is just plain unsound (llvm#89885, llvm#44218); there is no coherent specification that will describe this behavior correctly -- the backend in combination with standard LLVM passes is just fundamentally buggy in a hard-to-fix-way. There's also the questions around flushing subnormals to zero, but [this discussion](https://discourse.llvm.org/t/questions-about-llvm-canonicalize/79378) seems to indicate a general stance of: this is specific non-standard hardware behavior, and generally needs LLVM to be told that basic float ops do not return the standard result. Just naively running LLVM-compiled code on hardware configured to flush subnormals will lead to llvm#89885-like issues. AFAIK this is also what Alive2 implements (@nunoplopes please correct me if I am wrong).
1 parent 4b3f251 commit a8a6624

File tree

1 file changed

+53
-17
lines changed

1 file changed

+53
-17
lines changed

llvm/docs/LangRef.rst

+53-17
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,8 @@ example:
24272427
function which has an ``ssp`` or ``sspstrong`` attribute, the calling
24282428
function's attribute will be upgraded to ``sspreq``.
24292429

2430+
.. _strictfp:
2431+
24302432
``strictfp``
24312433
This attribute indicates that the function was called from a scope that
24322434
requires strict floating-point semantics. LLVM will not attempt any
@@ -3604,11 +3606,12 @@ status flags are not observable. Therefore, floating-point math operations do
36043606
not have side effects and may be speculated freely. Results assume the
36053607
round-to-nearest rounding mode, and subnormals are assumed to be preserved.
36063608

3607-
Running LLVM code in an environment where these assumptions are not met can lead
3608-
to undefined behavior. The ``strictfp`` and ``denormal-fp-math`` attributes as
3609-
well as :ref:`Constrained Floating-Point Intrinsics <constrainedfp>` can be used
3610-
to weaken LLVM's assumptions and ensure defined behavior in non-default
3611-
floating-point environments; see their respective documentation for details.
3609+
Running LLVM code in an environment where these assumptions are not met
3610+
typically leads to undefined behavior. The ``strictfp`` and ``denormal-fp-math``
3611+
attributes as well as :ref:`Constrained Floating-Point Intrinsics
3612+
<constrainedfp>` can be used to weaken LLVM's assumptions and ensure defined
3613+
behavior in non-default floating-point environments; see their respective
3614+
documentation for details.
36123615

36133616
.. _floatnan:
36143617

@@ -3630,10 +3633,11 @@ are not "floating-point math operations": ``fneg``, ``llvm.fabs``, and
36303633
``llvm.copysign``. These operations act directly on the underlying bit
36313634
representation and never change anything except possibly for the sign bit.
36323635

3633-
For floating-point math operations, unless specified otherwise, the following
3634-
rules apply when a NaN value is returned: the result has a non-deterministic
3635-
sign; the quiet bit and payload are non-deterministically chosen from the
3636-
following set of options:
3636+
Floating-point math operations that return a NaN are an exception from the
3637+
general principle that LLVM implements IEEE-754 semantics. Unless specified
3638+
otherwise, the following rules apply whenever the IEEE-754 semantics say that a
3639+
NaN value is returned: the result has a non-deterministic sign; the quiet bit
3640+
and payload are non-deterministically chosen from the following set of options:
36373641

36383642
- The quiet bit is set and the payload is all-zero. ("Preferred NaN" case)
36393643
- The quiet bit is set and the payload is copied from any input operand that is
@@ -3679,6 +3683,40 @@ specification on some architectures:
36793683
LLVM does not correctly represent this. See `issue #60796
36803684
<https://github.com/llvm/llvm-project/issues/60796>`_.
36813685

3686+
.. _floatsem:
3687+
3688+
Floating-Point Semantics
3689+
------------------------
3690+
3691+
This section defines the semantics for core floating-point operations on types
3692+
that use a format specified by IEEE-745. These types are: ``half``, ``float``,
3693+
``double``, and ``fp128``, which correspond to the binary16, binary32, binary64,
3694+
and binary128 formats, respectively. The "core" operations are those defined in
3695+
section 5 of IEEE-745, which all have corresponding LLVM operations.
3696+
3697+
The value returned by those operations matches that of the corresponding
3698+
IEEE-754 operation executed in the :ref:`default LLVM floating-point environment
3699+
<floatenv>`, except that the behavior of NaN results is instead :ref:`as
3700+
specified here <floatnan>`. In particular, such a floating-point instruction
3701+
returning a non-NaN value is guaranteed to always return the same bit-identical
3702+
result on all machines and optimization levels.
3703+
3704+
This means that optimizations and backends may not change the observed bitwise
3705+
result of these operations in any way (unless NaNs are returned), and frontends
3706+
can rely on these operations providing correctly rounded results as described in
3707+
the standard.
3708+
3709+
(Note that this is only about the value returned by these operations; see the
3710+
:ref:`floating-point environment section <floatenv>` regarding flags and
3711+
exceptions.)
3712+
3713+
Various flags, attributes, and metadata can alter the behavior of these
3714+
operations and thus make them not bit-identical across machines and optimization
3715+
levels any more: most notably, the :ref:`fast-math flags <fastmath>` as well as
3716+
the :ref:`strictfp <strictfp>` and :ref:`denormal-fp-math <denormal_fp_math>`
3717+
attributes and :ref:`!fpmath metadata <fpmath-metadata>`. See their
3718+
corresponding documentation for details.
3719+
36823720
.. _fastmath:
36833721

36843722
Fast-Math Flags
@@ -3975,7 +4013,7 @@ Floating-Point Types
39754013
- Description
39764014

39774015
* - ``half``
3978-
- 16-bit floating-point value
4016+
- 16-bit floating-point value (IEEE-754 binary16)
39794017

39804018
* - ``bfloat``
39814019
- 16-bit "brain" floating-point value (7-bit significand). Provides the
@@ -3984,24 +4022,20 @@ Floating-Point Types
39844022
extensions and Arm's ARMv8.6-A extensions, among others.
39854023

39864024
* - ``float``
3987-
- 32-bit floating-point value
4025+
- 32-bit floating-point value (IEEE-754 binary32)
39884026

39894027
* - ``double``
3990-
- 64-bit floating-point value
4028+
- 64-bit floating-point value (IEEE-754 binary64)
39914029

39924030
* - ``fp128``
3993-
- 128-bit floating-point value (113-bit significand)
4031+
- 128-bit floating-point value (IEEE-754 binary128)
39944032

39954033
* - ``x86_fp80``
39964034
- 80-bit floating-point value (X87)
39974035

39984036
* - ``ppc_fp128``
39994037
- 128-bit floating-point value (two 64-bits)
40004038

4001-
The binary format of half, float, double, and fp128 correspond to the
4002-
IEEE-754-2008 specifications for binary16, binary32, binary64, and binary128
4003-
respectively.
4004-
40054039
X86_amx Type
40064040
""""""""""""
40074041

@@ -6957,6 +6991,8 @@ For example,
69576991
%2 = load float, ptr %c, align 4, !alias.scope !6
69586992
store float %0, ptr %arrayidx.i, align 4, !noalias !7
69596993

6994+
.. _fpmath-metadata:
6995+
69606996
'``fpmath``' Metadata
69616997
^^^^^^^^^^^^^^^^^^^^^
69626998

0 commit comments

Comments
 (0)