[llvm] 88ff607 - APFloat: Fix maxnum and minnum with sNaN (#112854)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 26 22:16:37 PST 2025
Author: YunQiang Su
Date: 2025-02-27T14:16:33+08:00
New Revision: 88ff6070a5211e0eebe9b614efbeae8082866d1a
URL: https://github.com/llvm/llvm-project/commit/88ff6070a5211e0eebe9b614efbeae8082866d1a
DIFF: https://github.com/llvm/llvm-project/commit/88ff6070a5211e0eebe9b614efbeae8082866d1a.diff
LOG: APFloat: Fix maxnum and minnum with sNaN (#112854)
See: https://github.com/llvm/llvm-project/pull/112852
Fixes: https://github.com/llvm/llvm-project/issues/111991
We have reclarify llvm.maxnum and llvm.minnum to follow IEEE-754 2008's
maxNum and minNum with +0.0>-0.0.
So let's make APFloat::maxnum and APFloat::minnum to follow it, too.
Added:
Modified:
llvm/include/llvm/ADT/APFloat.h
llvm/unittests/ADT/APFloatTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index 3bff205e7aa9e..70fbf2059841e 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1543,11 +1543,16 @@ inline APFloat neg(APFloat X) {
return X;
}
-/// Implements IEEE-754 2019 minimumNumber semantics. Returns the smaller of the
-/// 2 arguments if both are not NaN. If either argument is a NaN, returns the
-/// other argument. -0 is treated as ordered less than +0.
+/// Implements IEEE-754 2008 minNum semantics. Returns the smaller of the
+/// 2 arguments if both are not NaN. If either argument is a qNaN, returns the
+/// other argument. If either argument is sNaN, return a qNaN.
+/// -0 is treated as ordered less than +0.
LLVM_READONLY
inline APFloat minnum(const APFloat &A, const APFloat &B) {
+ if (A.isSignaling())
+ return A.makeQuiet();
+ if (B.isSignaling())
+ return B.makeQuiet();
if (A.isNaN())
return B;
if (B.isNaN())
@@ -1557,11 +1562,16 @@ inline APFloat minnum(const APFloat &A, const APFloat &B) {
return B < A ? B : A;
}
-/// Implements IEEE-754 2019 maximumNumber semantics. Returns the larger of the
-/// 2 arguments if both are not NaN. If either argument is a NaN, returns the
-/// other argument. +0 is treated as ordered greater than -0.
+/// Implements IEEE-754 2008 maxNum semantics. Returns the larger of the
+/// 2 arguments if both are not NaN. If either argument is a qNaN, returns the
+/// other argument. If either argument is sNaN, return a qNaN.
+/// +0 is treated as ordered greater than -0.
LLVM_READONLY
inline APFloat maxnum(const APFloat &A, const APFloat &B) {
+ if (A.isSignaling())
+ return A.makeQuiet();
+ if (B.isSignaling())
+ return B.makeQuiet();
if (A.isNaN())
return B;
if (B.isNaN())
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index f291c814886d3..c2d99f3312b88 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -582,7 +582,46 @@ TEST(APFloatTest, MinNum) {
APFloat zp(0.0);
APFloat zn(-0.0);
EXPECT_EQ(-0.0, minnum(zp, zn).convertToDouble());
- EXPECT_EQ(-0.0, minnum(zn, zp).convertToDouble());
+
+ APInt intPayload_89ab(64, 0x89ab);
+ APInt intPayload_cdef(64, 0xcdef);
+ APFloat nan_0123[2] = {APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123),
+ APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123)};
+ APFloat mnan_4567[2] = {APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567),
+ APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567)};
+ APFloat nan_89ab[2] = {
+ APFloat::getSNaN(APFloat::IEEEdouble(), false, &intPayload_89ab),
+ APFloat::getNaN(APFloat::IEEEdouble(), false, 0x89ab)};
+ APFloat mnan_cdef[2] = {
+ APFloat::getSNaN(APFloat::IEEEdouble(), true, &intPayload_cdef),
+ APFloat::getNaN(APFloat::IEEEdouble(), true, 0xcdef)};
+
+ for (APFloat n : {nan_0123[0], mnan_4567[0]})
+ for (APFloat f : {f1, f2, zn, zp}) {
+ APFloat res = minnum(f, n);
+ EXPECT_FALSE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(f));
+ res = minnum(n, f);
+ EXPECT_FALSE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(f));
+ }
+ for (auto n : {nan_89ab, mnan_cdef})
+ for (APFloat f : {f1, f2, zn, zp}) {
+ APFloat res = minnum(f, n[0]);
+ EXPECT_TRUE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
+ res = minnum(n[0], f);
+ EXPECT_TRUE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
+ }
+
+ // When NaN vs NaN, we should keep payload/sign of either one.
+ for (auto n1 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef})
+ for (auto n2 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef}) {
+ APFloat res = minnum(n1[0], n2[0]);
+ EXPECT_TRUE(res.bitwiseIsEqual(n1[1]) || res.bitwiseIsEqual(n2[1]));
+ EXPECT_FALSE(res.isSignaling());
+ }
}
TEST(APFloatTest, MaxNum) {
@@ -599,6 +638,46 @@ TEST(APFloatTest, MaxNum) {
APFloat zn(-0.0);
EXPECT_EQ(0.0, maxnum(zp, zn).convertToDouble());
EXPECT_EQ(0.0, maxnum(zn, zp).convertToDouble());
+
+ APInt intPayload_89ab(64, 0x89ab);
+ APInt intPayload_cdef(64, 0xcdef);
+ APFloat nan_0123[2] = {APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123),
+ APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123)};
+ APFloat mnan_4567[2] = {APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567),
+ APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567)};
+ APFloat nan_89ab[2] = {
+ APFloat::getSNaN(APFloat::IEEEdouble(), false, &intPayload_89ab),
+ APFloat::getNaN(APFloat::IEEEdouble(), false, 0x89ab)};
+ APFloat mnan_cdef[2] = {
+ APFloat::getSNaN(APFloat::IEEEdouble(), true, &intPayload_cdef),
+ APFloat::getNaN(APFloat::IEEEdouble(), true, 0xcdef)};
+
+ for (APFloat n : {nan_0123[0], mnan_4567[0]})
+ for (APFloat f : {f1, f2, zn, zp}) {
+ APFloat res = maxnum(f, n);
+ EXPECT_FALSE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(f));
+ res = maxnum(n, f);
+ EXPECT_FALSE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(f));
+ }
+ for (auto n : {nan_89ab, mnan_cdef})
+ for (APFloat f : {f1, f2, zn, zp}) {
+ APFloat res = maxnum(f, n[0]);
+ EXPECT_TRUE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
+ res = maxnum(n[0], f);
+ EXPECT_TRUE(res.isNaN());
+ EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
+ }
+
+ // When NaN vs NaN, we should keep payload/sign of either one.
+ for (auto n1 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef})
+ for (auto n2 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef}) {
+ APFloat res = maxnum(n1[0], n2[0]);
+ EXPECT_TRUE(res.bitwiseIsEqual(n1[1]) || res.bitwiseIsEqual(n2[1]));
+ EXPECT_FALSE(res.isSignaling());
+ }
}
TEST(APFloatTest, Minimum) {
More information about the llvm-commits
mailing list