[llvm] LangRef: Clarify llvm.minnum and llvm.maxnum about sNaN (PR #112852)
YunQiang Su via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 31 18:05:49 PDT 2024
================
@@ -16464,21 +16464,32 @@ type.
Semantics:
""""""""""
+Follows the IEEE-754 semantics for minNum, except that -0.0 < +0.0 for the purposes
+of this intrinsic. As for signaling NaNs, per the IEEE-754 semantics, if either operand
+is an sNaN, the result is always a qNaN. This matches the recommended behavior for the libm
+function fmin, although not all implementations have implemented these recommended behaviors.
+
+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.
-Follows the IEEE-754 semantics for minNum, except for handling of
-signaling NaNs. This match's the behavior of libm's fmin.
+If the operands compare equal, returns either one of the operands.
-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.
+Returns -0.0 for +0.0 vs -0.0. libm doesn't require it, so that
+some applications like Clang, can call '``llvm.minnum.*``' with '``nsz``' attribute
+to archive the required behaivors of libm's fmin.
-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``).
+Some architecturs, such as ARMv8, LoongArch, MIPSr6, PowerPC/VSX, have the
+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.
+
+Note that that arithmetic on an sNaN doesn't consistently produce a qNaN,
+so arithmetic feeding into a minnum can produce inconsistent results.
+Such as `fmin(sNaN+0.0, 1.0)` can produce qNaN or 1.0 depending on whether `+0.0`
+is optimized out.
----------------
wzssyqa wrote:
```
This behavior is more strict than the definition in C and IEEE 754, where either zero may be returned.
To achieve the same permissiveness, the backend may implement the nsz attribute, and one may use the nsz
attribute on the intrinsic call.
```
https://github.com/llvm/llvm-project/pull/112852
More information about the llvm-commits
mailing list