Skip to content

Commit 88ff607

Browse files
authored
APFloat: Fix maxnum and minnum with sNaN (#112854)
See: #112852 Fixes: #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.
1 parent 5d404d7 commit 88ff607

File tree

2 files changed

+96
-7
lines changed

2 files changed

+96
-7
lines changed

llvm/include/llvm/ADT/APFloat.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,11 +1543,16 @@ inline APFloat neg(APFloat X) {
15431543
return X;
15441544
}
15451545

1546-
/// Implements IEEE-754 2019 minimumNumber semantics. Returns the smaller of the
1547-
/// 2 arguments if both are not NaN. If either argument is a NaN, returns the
1548-
/// other argument. -0 is treated as ordered less than +0.
1546+
/// Implements IEEE-754 2008 minNum semantics. Returns the smaller of the
1547+
/// 2 arguments if both are not NaN. If either argument is a qNaN, returns the
1548+
/// other argument. If either argument is sNaN, return a qNaN.
1549+
/// -0 is treated as ordered less than +0.
15491550
LLVM_READONLY
15501551
inline APFloat minnum(const APFloat &A, const APFloat &B) {
1552+
if (A.isSignaling())
1553+
return A.makeQuiet();
1554+
if (B.isSignaling())
1555+
return B.makeQuiet();
15511556
if (A.isNaN())
15521557
return B;
15531558
if (B.isNaN())
@@ -1557,11 +1562,16 @@ inline APFloat minnum(const APFloat &A, const APFloat &B) {
15571562
return B < A ? B : A;
15581563
}
15591564

1560-
/// Implements IEEE-754 2019 maximumNumber semantics. Returns the larger of the
1561-
/// 2 arguments if both are not NaN. If either argument is a NaN, returns the
1562-
/// other argument. +0 is treated as ordered greater than -0.
1565+
/// Implements IEEE-754 2008 maxNum semantics. Returns the larger of the
1566+
/// 2 arguments if both are not NaN. If either argument is a qNaN, returns the
1567+
/// other argument. If either argument is sNaN, return a qNaN.
1568+
/// +0 is treated as ordered greater than -0.
15631569
LLVM_READONLY
15641570
inline APFloat maxnum(const APFloat &A, const APFloat &B) {
1571+
if (A.isSignaling())
1572+
return A.makeQuiet();
1573+
if (B.isSignaling())
1574+
return B.makeQuiet();
15651575
if (A.isNaN())
15661576
return B;
15671577
if (B.isNaN())

llvm/unittests/ADT/APFloatTest.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,46 @@ TEST(APFloatTest, MinNum) {
582582
APFloat zp(0.0);
583583
APFloat zn(-0.0);
584584
EXPECT_EQ(-0.0, minnum(zp, zn).convertToDouble());
585-
EXPECT_EQ(-0.0, minnum(zn, zp).convertToDouble());
585+
586+
APInt intPayload_89ab(64, 0x89ab);
587+
APInt intPayload_cdef(64, 0xcdef);
588+
APFloat nan_0123[2] = {APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123),
589+
APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123)};
590+
APFloat mnan_4567[2] = {APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567),
591+
APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567)};
592+
APFloat nan_89ab[2] = {
593+
APFloat::getSNaN(APFloat::IEEEdouble(), false, &intPayload_89ab),
594+
APFloat::getNaN(APFloat::IEEEdouble(), false, 0x89ab)};
595+
APFloat mnan_cdef[2] = {
596+
APFloat::getSNaN(APFloat::IEEEdouble(), true, &intPayload_cdef),
597+
APFloat::getNaN(APFloat::IEEEdouble(), true, 0xcdef)};
598+
599+
for (APFloat n : {nan_0123[0], mnan_4567[0]})
600+
for (APFloat f : {f1, f2, zn, zp}) {
601+
APFloat res = minnum(f, n);
602+
EXPECT_FALSE(res.isNaN());
603+
EXPECT_TRUE(res.bitwiseIsEqual(f));
604+
res = minnum(n, f);
605+
EXPECT_FALSE(res.isNaN());
606+
EXPECT_TRUE(res.bitwiseIsEqual(f));
607+
}
608+
for (auto n : {nan_89ab, mnan_cdef})
609+
for (APFloat f : {f1, f2, zn, zp}) {
610+
APFloat res = minnum(f, n[0]);
611+
EXPECT_TRUE(res.isNaN());
612+
EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
613+
res = minnum(n[0], f);
614+
EXPECT_TRUE(res.isNaN());
615+
EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
616+
}
617+
618+
// When NaN vs NaN, we should keep payload/sign of either one.
619+
for (auto n1 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef})
620+
for (auto n2 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef}) {
621+
APFloat res = minnum(n1[0], n2[0]);
622+
EXPECT_TRUE(res.bitwiseIsEqual(n1[1]) || res.bitwiseIsEqual(n2[1]));
623+
EXPECT_FALSE(res.isSignaling());
624+
}
586625
}
587626

588627
TEST(APFloatTest, MaxNum) {
@@ -599,6 +638,46 @@ TEST(APFloatTest, MaxNum) {
599638
APFloat zn(-0.0);
600639
EXPECT_EQ(0.0, maxnum(zp, zn).convertToDouble());
601640
EXPECT_EQ(0.0, maxnum(zn, zp).convertToDouble());
641+
642+
APInt intPayload_89ab(64, 0x89ab);
643+
APInt intPayload_cdef(64, 0xcdef);
644+
APFloat nan_0123[2] = {APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123),
645+
APFloat::getNaN(APFloat::IEEEdouble(), false, 0x0123)};
646+
APFloat mnan_4567[2] = {APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567),
647+
APFloat::getNaN(APFloat::IEEEdouble(), true, 0x4567)};
648+
APFloat nan_89ab[2] = {
649+
APFloat::getSNaN(APFloat::IEEEdouble(), false, &intPayload_89ab),
650+
APFloat::getNaN(APFloat::IEEEdouble(), false, 0x89ab)};
651+
APFloat mnan_cdef[2] = {
652+
APFloat::getSNaN(APFloat::IEEEdouble(), true, &intPayload_cdef),
653+
APFloat::getNaN(APFloat::IEEEdouble(), true, 0xcdef)};
654+
655+
for (APFloat n : {nan_0123[0], mnan_4567[0]})
656+
for (APFloat f : {f1, f2, zn, zp}) {
657+
APFloat res = maxnum(f, n);
658+
EXPECT_FALSE(res.isNaN());
659+
EXPECT_TRUE(res.bitwiseIsEqual(f));
660+
res = maxnum(n, f);
661+
EXPECT_FALSE(res.isNaN());
662+
EXPECT_TRUE(res.bitwiseIsEqual(f));
663+
}
664+
for (auto n : {nan_89ab, mnan_cdef})
665+
for (APFloat f : {f1, f2, zn, zp}) {
666+
APFloat res = maxnum(f, n[0]);
667+
EXPECT_TRUE(res.isNaN());
668+
EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
669+
res = maxnum(n[0], f);
670+
EXPECT_TRUE(res.isNaN());
671+
EXPECT_TRUE(res.bitwiseIsEqual(n[1]));
672+
}
673+
674+
// When NaN vs NaN, we should keep payload/sign of either one.
675+
for (auto n1 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef})
676+
for (auto n2 : {nan_0123, mnan_4567, nan_89ab, mnan_cdef}) {
677+
APFloat res = maxnum(n1[0], n2[0]);
678+
EXPECT_TRUE(res.bitwiseIsEqual(n1[1]) || res.bitwiseIsEqual(n2[1]));
679+
EXPECT_FALSE(res.isSignaling());
680+
}
602681
}
603682

604683
TEST(APFloatTest, Minimum) {

0 commit comments

Comments
 (0)