[llvm] LangRef: Clarify llvm.minnum and llvm.maxnum about sNaN (PR #112852)
YunQiang Su via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 20 18:11:52 PDT 2024
https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/112852
>From dc09e4bdb3374f2efa43737a114a12d99e7e825f Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Fri, 18 Oct 2024 16:16:43 +0800
Subject: [PATCH 1/5] LangRef: Clarify llvm.minnum and llvm.maxnum about sNaN
The documents claims that it ignores sNaN, while in the code it may
be different.
- as the finally callback, it use libc call fmin(3)/fmax(3).
while C23 clarify that fmin(3)/fmax(3) should return NaN for sNaN vs NUM.
- on some architectures, such as aarch64, it converts to `fmaxnm`,
which returns qNaN for sNaN vs NUM.
- on RISC-V (SPEC 2019+), it converts to `fmax`, which returns NUM
for sNaN vs NUM.
Since we have introduced llvm.minimumnum and llvm.maximumnum, which
follow IEEE 754-2019's minimumNumber/maximumNumber.
So, it's time for use to clarify llvm.minnum and llvm.maxnum.
Let's define it to the libc's defination.
---
llvm/docs/LangRef.rst | 75 ++++++++++++++++++-------------------------
1 file changed, 31 insertions(+), 44 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 566d0d4e4e81a3..e0ea81ae8a2d10 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16464,21 +16464,13 @@ type.
Semantics:
""""""""""
+Follows the IEEE754 2008 semantics for minNum, except for handling of
++0.0 vs -0.0. This matches the behavior of libm's fmin.
-Follows the IEEE-754 semantics for minNum, except for handling of
-signaling NaNs. This match's the behavior of libm's fmin.
-
-If either operand is a NaN, returns the other non-NaN operand. Returns
-NaN only if both operands are NaN. If the operands compare equal,
-returns either one of the operands. For example, this means that
-fmin(+0.0, -0.0) returns either operand.
-
-Unlike the IEEE-754 2008 behavior, this does not distinguish between
-signaling and quiet NaN inputs. If a target's implementation follows
-the standard and returns a quiet NaN if either input is a signaling
-NaN, the intrinsic lowering is responsible for quieting the inputs to
-correctly return the non-NaN input (e.g. by using the equivalent of
-``llvm.canonicalize``).
+If either operand is a qNaN, returns the other non-NaN operand. Returns
+NaN only if both operands are NaN or either operand is sNaN.
+If the operands compare equal, returns either one of the operands.
+For example, this means that fmin(+0.0, -0.0) returns either operand.
.. _i_maxnum:
@@ -16515,20 +16507,13 @@ type.
Semantics:
""""""""""
-Follows the IEEE-754 semantics for maxNum except for the handling of
-signaling NaNs. This matches the behavior of libm's fmax.
+Follows the IEEE754 2008 semantics for maxNum, except for handling of
++0.0 vs -0.0. This matches the behavior of libm's fmax.
If either operand is a NaN, returns the other non-NaN operand. Returns
-NaN only if both operands are NaN. If the operands compare equal,
-returns either one of the operands. For example, this means that
-fmax(+0.0, -0.0) returns either -0.0 or 0.0.
-
-Unlike the IEEE-754 2008 behavior, this does not distinguish between
-signaling and quiet NaN inputs. If a target's implementation follows
-the standard and returns a quiet NaN if either input is a signaling
-NaN, the intrinsic lowering is responsible for quieting the inputs to
-correctly return the non-NaN input (e.g. by using the equivalent of
-``llvm.canonicalize``).
+NaN only if both operands are NaN or either operand is sNaN.
+If the operands compare equal, returns either one of the operands.
+For example, this means that fmin(+0.0, -0.0) returns either operand.
.. _i_minimum:
@@ -19407,12 +19392,12 @@ The '``llvm.vector.reduce.fmax.*``' intrinsics do a floating-point
matches the element-type of the vector input.
This instruction has the same comparison semantics as the '``llvm.maxnum.*``'
-intrinsic. That is, the result will always be a number unless all elements of
-the vector are NaN. For a vector with maximum element magnitude 0.0 and
-containing both +0.0 and -0.0 elements, the sign of the result is unspecified.
+intrinsic. If the intrinsic call has the ``nnan`` fast-math flag, then the
+operation can assume that NaNs are not present in the input vector.
-If the intrinsic call has the ``nnan`` fast-math flag, then the operation can
-assume that NaNs are not present in the input vector.
+It is deprecated, since the different order of inputs may produce different
+outputs, and it is hard to optimize with Vector or SIMD extensions.
+Use '``llvm.vector.reduce.fmaximum``' or '``llvm.vector.reduce.fmaximumnum``' instead.
Arguments:
""""""""""
@@ -19440,12 +19425,12 @@ The '``llvm.vector.reduce.fmin.*``' intrinsics do a floating-point
matches the element-type of the vector input.
This instruction has the same comparison semantics as the '``llvm.minnum.*``'
-intrinsic. That is, the result will always be a number unless all elements of
-the vector are NaN. For a vector with minimum element magnitude 0.0 and
-containing both +0.0 and -0.0 elements, the sign of the result is unspecified.
+intrinsic. If the intrinsic call has the ``nnan`` fast-math flag, then the
+operation can assume that NaNs are not present in the input vector.
-If the intrinsic call has the ``nnan`` fast-math flag, then the operation can
-assume that NaNs are not present in the input vector.
+It is deprecated, since the different order of inputs may produce different
+outputs, and it is hard to optimize with Vector or SIMD extensions.
+Use '``llvm.vector.reduce.fminimum``' or '``llvm.vector.reduce.fminimumnum``' instead.
Arguments:
""""""""""
@@ -22994,13 +22979,14 @@ result type. If only ``nnan`` is set then the neutral value is ``-Infinity``.
This instruction has the same comparison semantics as the
:ref:`llvm.vector.reduce.fmax <int_vector_reduce_fmax>` intrinsic (and thus the
-'``llvm.maxnum.*``' intrinsic). That is, the result will always be a number
-unless all elements of the vector and the starting value are ``NaN``. For a
-vector with maximum element magnitude ``0.0`` and containing both ``+0.0`` and
-``-0.0`` elements, the sign of the result is unspecified.
+'``llvm.maxnum.*``' intrinsic).
To ignore the start value, the neutral value can be used.
+It is deprecated, since the different order of inputs may produce different
+outputs, and it is hard to optimize with Vector or SIMD extensions.
+Use '``llvm.vp.vector.reduce.fmaximum``' or '``llvm.vp.vector.reduce.fmaximumnum``' instead.
+
Examples:
"""""""""
@@ -23064,13 +23050,14 @@ result type. If only ``nnan`` is set then the neutral value is ``+Infinity``.
This instruction has the same comparison semantics as the
:ref:`llvm.vector.reduce.fmin <int_vector_reduce_fmin>` intrinsic (and thus the
-'``llvm.minnum.*``' intrinsic). That is, the result will always be a number
-unless all elements of the vector and the starting value are ``NaN``. For a
-vector with maximum element magnitude ``0.0`` and containing both ``+0.0`` and
-``-0.0`` elements, the sign of the result is unspecified.
+'``llvm.minnum.*``' intrinsic).
To ignore the start value, the neutral value can be used.
+It is deprecated, since the different order of inputs may produce different
+outputs, and it is hard to optimize with Vector or SIMD extensions.
+Use '``llvm.vp.vector.reduce.fminimum``' or '``llvm.vp.vector.reduce.fminimumnum``' instead.
+
Examples:
"""""""""
>From fb6b8203c85429ea5c3469621dd32ed6f6850404 Mon Sep 17 00:00:00 2001
From: YunQiang Su <wzssyqa at gmail.com>
Date: Sat, 19 Oct 2024 01:33:13 +0800
Subject: [PATCH 2/5] minNum doesn't care about +0 vs -0
---
llvm/docs/LangRef.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e0ea81ae8a2d10..f3e2954aa0621d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16464,8 +16464,8 @@ type.
Semantics:
""""""""""
-Follows the IEEE754 2008 semantics for minNum, except for handling of
-+0.0 vs -0.0. This matches the behavior of libm's fmin.
+Follows the IEEE754 2008 semantics for minNum.
+This also matches the behavior of libm's fmin.
If either operand is a qNaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
@@ -16507,8 +16507,8 @@ type.
Semantics:
""""""""""
-Follows the IEEE754 2008 semantics for maxNum, except for handling of
-+0.0 vs -0.0. This matches the behavior of libm's fmax.
+Follows the IEEE754 2008 semantics for maxNum.
+This also matches the behavior of libm's fmax.
If either operand is a NaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
>From f8b9bba9b51b50b511ea04c8fbc0d71b98c7df2b Mon Sep 17 00:00:00 2001
From: YunQiang Su <syq at debian.org>
Date: Sun, 20 Oct 2024 12:13:21 +0800
Subject: [PATCH 3/5] add history about libm
---
llvm/docs/LangRef.rst | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index f3e2954aa0621d..6efb1ec64d05da 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16465,7 +16465,11 @@ type.
Semantics:
""""""""""
Follows the IEEE754 2008 semantics for minNum.
-This also matches the behavior of libm's fmin.
+This also matches the current (C23) behavior of libm's fmin.
+
+Historically, libc returns NUM for NUM vs (sNaN or qNaN), and may return
+sNaN for qNaN vs sNaN. Withe recent libc versions, libc follows IEEE754-2008:
+NUM vs sNaN -> qNaN; NUM vs qNaN -> NUM; qNaN vs sNaN -> qNaN; sNaN vs sNaN -> qNaN.
If either operand is a qNaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
@@ -16508,7 +16512,11 @@ type.
Semantics:
""""""""""
Follows the IEEE754 2008 semantics for maxNum.
-This also matches the behavior of libm's fmax.
+This also matches the current (C23) behavior of libm's fmax.
+
+Historically, libc returns NUM for NUM vs (sNaN or qNaN), and may return
+sNaN for qNaN vs sNaN. Withe recent libc versions, libc follows IEEE754-2008:
+NUM vs sNaN -> qNaN; NUM vs qNaN -> NUM; qNaN vs sNaN -> qNaN; sNaN vs sNaN -> qNaN.
If either operand is a NaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
>From 70b90f1d2d1f5db99ffe025f2242b19a28465a79 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Oct 2024 08:56:22 +0800
Subject: [PATCH 4/5] fmin requires +0>-0
---
llvm/docs/LangRef.rst | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 6efb1ec64d05da..1d091038fad290 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16420,7 +16420,7 @@ versions of the intrinsics respect the exception behavior.
- qNaN, invalid exception
* - ``+0.0 vs -0.0``
- - either one
+ - +0.0(max)/-0.0(min)
- +0.0(max)/-0.0(min)
- +0.0(max)/-0.0(min)
@@ -16464,8 +16464,14 @@ type.
Semantics:
""""""""""
-Follows the IEEE754 2008 semantics for minNum.
-This also matches the current (C23) behavior of libm's fmin.
+Follows the IEEE754 2008 semantics for minNum with +0.0>-0.0.
+This is more strict than current (C23) behavior of libm's fmin.
+Some applications like Clang, can call '``llvm.minnum.*``' with '``nsz``' attribute
+to archive the same behaivor of libm's fmin.
+
+For some architecturs, such as ARMv8, LoongArch, MIPSr6, PowerPC/VSX, they have the
+strict same instructions; thus it is quite simple for these architectures.
+For other architectures, the custom or expand methods may provide '``nsz``' flavor.
Historically, libc returns NUM for NUM vs (sNaN or qNaN), and may return
sNaN for qNaN vs sNaN. Withe recent libc versions, libc follows IEEE754-2008:
@@ -16511,12 +16517,14 @@ type.
Semantics:
""""""""""
-Follows the IEEE754 2008 semantics for maxNum.
-This also matches the current (C23) behavior of libm's fmax.
+Follows the IEEE754 2008 semantics for maxNum with +0.0>-0.0.
+This is more strict than current (C23) behavior of libm's fmax.
+Some applications like Clang, can call '``llvm.maxnum.*``' with '``nsz``' attribute
+to archive the same behaivor of libm's fmax.
-Historically, libc returns NUM for NUM vs (sNaN or qNaN), and may return
-sNaN for qNaN vs sNaN. Withe recent libc versions, libc follows IEEE754-2008:
-NUM vs sNaN -> qNaN; NUM vs qNaN -> NUM; qNaN vs sNaN -> qNaN; sNaN vs sNaN -> qNaN.
+For some architecturs, such as ARMv8, LoongArch, MIPSr6, PowerPC/VSX, they have the
+strict same instructions; thus it is quite simple for these architectures.
+For other architectures, the custom or expand methods may provide '``nsz``' flavor.
If either operand is a NaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
>From 3cf9e55c626baeb963d5e98afb38f57909444ebd Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Oct 2024 09:11:35 +0800
Subject: [PATCH 5/5] some fix
---
llvm/docs/LangRef.rst | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 1d091038fad290..3211559cd97681 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -16470,17 +16470,16 @@ Some applications like Clang, can call '``llvm.minnum.*``' with '``nsz``' attrib
to archive the same behaivor of libm's fmin.
For some architecturs, such as ARMv8, LoongArch, MIPSr6, PowerPC/VSX, they have the
-strict same instructions; thus it is quite simple for these architectures.
+strictly same instructions; thus it is quite simple for these architectures.
For other architectures, the custom or expand methods may provide '``nsz``' flavor.
Historically, libc returns NUM for NUM vs (sNaN or qNaN), and may return
-sNaN for qNaN vs sNaN. Withe recent libc versions, libc follows IEEE754-2008:
+sNaN for qNaN vs sNaN. With the recent libc versions, libc follows IEEE754-2008:
NUM vs sNaN -> qNaN; NUM vs qNaN -> NUM; qNaN vs sNaN -> qNaN; sNaN vs sNaN -> qNaN.
If either operand is a qNaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
If the operands compare equal, returns either one of the operands.
-For example, this means that fmin(+0.0, -0.0) returns either operand.
.. _i_maxnum:
@@ -16523,13 +16522,16 @@ Some applications like Clang, can call '``llvm.maxnum.*``' with '``nsz``' attrib
to archive the same behaivor of libm's fmax.
For some architecturs, such as ARMv8, LoongArch, MIPSr6, PowerPC/VSX, they have the
-strict same instructions; thus it is quite simple for these architectures.
+strictly same instructions; thus it is quite simple for these architectures.
For other architectures, the custom or expand methods may provide '``nsz``' flavor.
+Historically, libc returns NUM for NUM vs (sNaN or qNaN), and may return
+sNaN for qNaN vs sNaN. With the recent libc versions, libc follows IEEE754-2008:
+NUM vs sNaN -> qNaN; NUM vs qNaN -> NUM; qNaN vs sNaN -> qNaN; sNaN vs sNaN -> qNaN.
+
If either operand is a NaN, returns the other non-NaN operand. Returns
NaN only if both operands are NaN or either operand is sNaN.
If the operands compare equal, returns either one of the operands.
-For example, this means that fmin(+0.0, -0.0) returns either operand.
.. _i_minimum:
More information about the llvm-commits
mailing list