Skip to content

Commit 6369279

Browse files
authored
Revert "Revert "LangRef: Clarify llvm.minnum and llvm.maxnum about sNaN and signed zero (#112852)"" (#170067)
Reverts #168838 Justification is confused and this did not receive adequate discussion, particularly during a holiday week
1 parent 7494f3d commit 6369279

File tree

2 files changed

+71
-59
lines changed

2 files changed

+71
-59
lines changed

llvm/docs/LangRef.rst

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17298,9 +17298,8 @@ LLVM Implementation:
1729817298
""""""""""""""""""""
1729917299

1730017300
LLVM implements all ISO C flavors as listed in this table, except in the
17301-
default floating-point environment exceptions are ignored and return value
17302-
is non-deterministic if one or both inputs are sNaN. The constrained
17303-
versions of the intrinsics respect the exception behavior and sNaN.
17301+
default floating-point environment exceptions are ignored. The constrained
17302+
versions of the intrinsics respect the exception behavior.
1730417303

1730517304
.. list-table::
1730617305
:header-rows: 1
@@ -17332,7 +17331,7 @@ versions of the intrinsics respect the exception behavior and sNaN.
1733217331
- qNaN, invalid exception
1733317332

1733417333
* - ``+0.0 vs -0.0``
17335-
- either one
17334+
- +0.0(max)/-0.0(min)
1733617335
- +0.0(max)/-0.0(min)
1733717336
- +0.0(max)/-0.0(min)
1733817337

@@ -17376,22 +17375,30 @@ type.
1737617375

1737717376
Semantics:
1737817377
""""""""""
17378+
Follows the semantics of minNum in IEEE-754-2008, except that -0.0 < +0.0 for the purposes
17379+
of this intrinsic. As for signaling NaNs, per the minNum semantics, if either operand is sNaN,
17380+
the result is qNaN. This matches the recommended behavior for the libm
17381+
function ``fmin``, although not all implementations have implemented these recommended behaviors.
17382+
17383+
If either operand is a qNaN, returns the other non-NaN operand. Returns NaN only if both operands are
17384+
NaN or if either operand is sNaN. Note that arithmetic on an sNaN doesn't consistently produce a qNaN,
17385+
so arithmetic feeding into a minnum can produce inconsistent results. For example,
17386+
``minnum(fadd(sNaN, -0.0), 1.0)`` can produce qNaN or 1.0 depending on whether ``fadd`` is folded.
1737917387

17380-
Follows the IEEE-754-2008 semantics for minNum, except for handling of
17381-
signaling NaNs. This matches the behavior of libm's fmin.
17388+
IEEE-754-2008 defines minNum, and it was removed in IEEE-754-2019. As the replacement, IEEE-754-2019
17389+
defines :ref:`minimumNumber <i_minimumnum>`.
1738217390

17383-
If either operand is a NaN, returns the other non-NaN operand. Returns
17384-
NaN only if both operands are NaN. If the operands compare equal,
17385-
returns either one of the operands. For example, this means that
17386-
fmin(+0.0, -0.0) non-deterministically returns either operand (-0.0
17387-
or 0.0).
17391+
If the intrinsic is marked with the nsz attribute, then the effect is as in the definition in C
17392+
and IEEE-754-2008: the result of ``minnum(-0.0, +0.0)`` may be either -0.0 or +0.0.
1738817393

17389-
Unlike the IEEE-754-2008 behavior, this does not distinguish between
17390-
signaling and quiet NaN inputs. If a target's implementation follows
17391-
the standard and returns a quiet NaN if either input is a signaling
17392-
NaN, the intrinsic lowering is responsible for quieting the inputs to
17393-
correctly return the non-NaN input (e.g. by using the equivalent of
17394-
``llvm.canonicalize``).
17394+
Some architectures, such as ARMv8 (FMINNM), LoongArch (fmin), MIPSr6 (min.fmt), PowerPC/VSX (xsmindp),
17395+
have instructions that match these semantics exactly; thus it is quite simple for these architectures.
17396+
Some architectures have similar ones while they are not exact equivalent. Such as x86 implements ``MINPS``,
17397+
which implements the semantics of C code ``a<b?a:b``: NUM vs qNaN always return qNaN. ``MINPS`` can be used
17398+
if ``nsz`` and ``nnan`` are given.
17399+
17400+
For existing libc implementations, the behaviors of fmin may be quite different on sNaN and signed zero behaviors,
17401+
even in the same release of a single libm implementation.
1739517402

1739617403
.. _i_maxnum:
1739717404

@@ -17428,21 +17435,30 @@ type.
1742817435

1742917436
Semantics:
1743017437
""""""""""
17431-
Follows the IEEE-754-2008 semantics for maxNum except for the handling of
17432-
signaling NaNs. This matches the behavior of libm's fmax.
17438+
Follows the semantics of maxNum in IEEE-754-2008, except that -0.0 < +0.0 for the purposes
17439+
of this intrinsic. As for signaling NaNs, per the maxNum semantics, if either operand is sNaN,
17440+
the result is qNaN. This matches the recommended behavior for the libm
17441+
function ``fmax``, although not all implementations have implemented these recommended behaviors.
17442+
17443+
If either operand is a qNaN, returns the other non-NaN operand. Returns NaN only if both operands are
17444+
NaN or if either operand is sNaN. Note that arithmetic on an sNaN doesn't consistently produce a qNaN,
17445+
so arithmetic feeding into a maxnum can produce inconsistent results. For example,
17446+
``maxnum(fadd(sNaN, -0.0), 1.0)`` can produce qNaN or 1.0 depending on whether ``fadd`` is folded.
1743317447

17434-
If either operand is a NaN, returns the other non-NaN operand. Returns
17435-
NaN only if both operands are NaN. If the operands compare equal,
17436-
returns either one of the operands. For example, this means that
17437-
fmax(+0.0, -0.0) non-deterministically returns either operand (-0.0
17438-
or 0.0).
17448+
IEEE-754-2008 defines maxNum, and it was removed in IEEE-754-2019. As the replacement, IEEE-754-2019
17449+
defines :ref:`maximumNumber <i_maximumnum>`.
1743917450

17440-
Unlike the IEEE-754-2008 behavior, this does not distinguish between
17441-
signaling and quiet NaN inputs. If a target's implementation follows
17442-
the standard and returns a quiet NaN if either input is a signaling
17443-
NaN, the intrinsic lowering is responsible for quieting the inputs to
17444-
correctly return the non-NaN input (e.g. by using the equivalent of
17445-
``llvm.canonicalize``).
17451+
If the intrinsic is marked with the nsz attribute, then the effect is as in the definition in C
17452+
and IEEE-754-2008: the result of maxnum(-0.0, +0.0) may be either -0.0 or +0.0.
17453+
17454+
Some architectures, such as ARMv8 (FMAXNM), LoongArch (fmax), MIPSr6 (max.fmt), PowerPC/VSX (xsmaxdp),
17455+
have instructions that match these semantics exactly; thus it is quite simple for these architectures.
17456+
Some architectures have similar ones while they are not exact equivalent. Such as x86 implements ``MAXPS``,
17457+
which implements the semantics of C code ``a>b?a:b``: NUM vs qNaN always return qNaN. ``MAXPS`` can be used
17458+
if ``nsz`` and ``nnan`` are given.
17459+
17460+
For existing libc implementations, the behaviors of fmin may be quite different on sNaN and signed zero behaviors,
17461+
even in the same release of a single libm implementation.
1744617462

1744717463
.. _i_minimum:
1744817464

@@ -20326,12 +20342,8 @@ The '``llvm.vector.reduce.fmax.*``' intrinsics do a floating-point
2032620342
matches the element-type of the vector input.
2032720343

2032820344
This instruction has the same comparison semantics as the '``llvm.maxnum.*``'
20329-
intrinsic. That is, the result will always be a number unless all elements of
20330-
the vector are NaN. For a vector with maximum element magnitude 0.0 and
20331-
containing both +0.0 and -0.0 elements, the sign of the result is unspecified.
20332-
20333-
If the intrinsic call has the ``nnan`` fast-math flag, then the operation can
20334-
assume that NaNs are not present in the input vector.
20345+
intrinsic. If the intrinsic call has the ``nnan`` fast-math flag, then the
20346+
operation can assume that NaNs are not present in the input vector.
2033520347

2033620348
Arguments:
2033720349
""""""""""
@@ -20359,12 +20371,8 @@ The '``llvm.vector.reduce.fmin.*``' intrinsics do a floating-point
2035920371
matches the element-type of the vector input.
2036020372

2036120373
This instruction has the same comparison semantics as the '``llvm.minnum.*``'
20362-
intrinsic. That is, the result will always be a number unless all elements of
20363-
the vector are NaN. For a vector with minimum element magnitude 0.0 and
20364-
containing both +0.0 and -0.0 elements, the sign of the result is unspecified.
20365-
20366-
If the intrinsic call has the ``nnan`` fast-math flag, then the operation can
20367-
assume that NaNs are not present in the input vector.
20374+
intrinsic. If the intrinsic call has the ``nnan`` fast-math flag, then the
20375+
operation can assume that NaNs are not present in the input vector.
2036820376

2036920377
Arguments:
2037020378
""""""""""
@@ -22751,7 +22759,7 @@ This is an overloaded intrinsic.
2275122759
Overview:
2275222760
"""""""""
2275322761

22754-
Predicated floating-point IEEE-754 minNum of two vectors of floating-point values.
22762+
Predicated floating-point IEEE-754-2008 minNum of two vectors of floating-point values.
2275522763

2275622764

2275722765
Arguments:
@@ -22800,7 +22808,7 @@ This is an overloaded intrinsic.
2280022808
Overview:
2280122809
"""""""""
2280222810

22803-
Predicated floating-point IEEE-754 maxNum of two vectors of floating-point values.
22811+
Predicated floating-point IEEE-754-2008 maxNum of two vectors of floating-point values.
2280422812

2280522813

2280622814
Arguments:
@@ -24099,10 +24107,7 @@ result type. If only ``nnan`` is set then the neutral value is ``-Infinity``.
2409924107

2410024108
This instruction has the same comparison semantics as the
2410124109
:ref:`llvm.vector.reduce.fmax <int_vector_reduce_fmax>` intrinsic (and thus the
24102-
'``llvm.maxnum.*``' intrinsic). That is, the result will always be a number
24103-
unless all elements of the vector and the starting value are ``NaN``. For a
24104-
vector with maximum element magnitude ``0.0`` and containing both ``+0.0`` and
24105-
``-0.0`` elements, the sign of the result is unspecified.
24110+
'``llvm.maxnum.*``' intrinsic).
2410624111

2410724112
To ignore the start value, the neutral value can be used.
2410824113

@@ -24169,10 +24174,7 @@ result type. If only ``nnan`` is set then the neutral value is ``+Infinity``.
2416924174

2417024175
This instruction has the same comparison semantics as the
2417124176
:ref:`llvm.vector.reduce.fmin <int_vector_reduce_fmin>` intrinsic (and thus the
24172-
'``llvm.minnum.*``' intrinsic). That is, the result will always be a number
24173-
unless all elements of the vector and the starting value are ``NaN``. For a
24174-
vector with maximum element magnitude ``0.0`` and containing both ``+0.0`` and
24175-
``-0.0`` elements, the sign of the result is unspecified.
24177+
'``llvm.minnum.*``' intrinsic).
2417624178

2417724179
To ignore the start value, the neutral value can be used.
2417824180

@@ -29044,7 +29046,7 @@ The third argument specifies the exception behavior as described above.
2904429046
Semantics:
2904529047
""""""""""
2904629048

29047-
This function follows the IEEE-754 semantics for maxNum.
29049+
This function follows the IEEE-754-2008 semantics for maxNum.
2904829050

2904929051

2905029052
'``llvm.experimental.constrained.minnum``' Intrinsic
@@ -29076,7 +29078,7 @@ The third argument specifies the exception behavior as described above.
2907629078
Semantics:
2907729079
""""""""""
2907829080

29079-
This function follows the IEEE-754 semantics for minNum.
29081+
This function follows the IEEE-754-2008 semantics for minNum.
2908029082

2908129083

2908229084
'``llvm.experimental.constrained.maximum``' Intrinsic

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,13 +1048,20 @@ enum NodeType {
10481048
LRINT,
10491049
LLRINT,
10501050

1051-
/// FMINNUM/FMAXNUM - Perform floating-point minimum or maximum on two
1052-
/// values.
1051+
/// FMINNUM/FMAXNUM - Perform floating-point minimum maximum on two values,
1052+
/// following IEEE-754 definitions except for signed zero behavior.
10531053
///
1054-
/// In the case where a single input is a NaN (either signaling or quiet),
1055-
/// the non-NaN input is returned.
1054+
/// If one input is a signaling NaN, returns a quiet NaN. This matches
1055+
/// IEEE-754 2008's minNum/maxNum behavior for signaling NaNs (which differs
1056+
/// from 2019).
10561057
///
1057-
/// The return value of (FMINNUM 0.0, -0.0) could be either 0.0 or -0.0.
1058+
/// These treat -0 as ordered less than +0, matching the behavior of IEEE-754
1059+
/// 2019's minimumNumber/maximumNumber.
1060+
///
1061+
/// Note that that arithmetic on an sNaN doesn't consistently produce a qNaN,
1062+
/// so arithmetic feeding into a minnum/maxnum can produce inconsistent
1063+
/// results. FMAXIMUN/FMINIMUM or FMAXIMUMNUM/FMINIMUMNUM may be better choice
1064+
/// for non-distinction of sNaN/qNaN handling.
10581065
FMINNUM,
10591066
FMAXNUM,
10601067

@@ -1068,6 +1075,9 @@ enum NodeType {
10681075
///
10691076
/// These treat -0 as ordered less than +0, matching the behavior of IEEE-754
10701077
/// 2019's minimumNumber/maximumNumber.
1078+
///
1079+
/// Deprecated, and will be removed soon, as FMINNUM/FMAXNUM have the same
1080+
/// semantics now.
10711081
FMINNUM_IEEE,
10721082
FMAXNUM_IEEE,
10731083

0 commit comments

Comments
 (0)