Skip to content

Commit b75e26b

Browse files
asbSterling-Augustine
authored andcommitted
[APFloat] Correct semantics of minimum/maximum for signaling NaN arguments (llvm#109976)
The minimum and maximum operations were introduced in https://reviews.llvm.org/D52764 alongside the intrinsics. The question of NaN propagation was discussed at the time, but the resulting semantics don't seem to match what was ultimately agreed in IEEE754-2019 or the description we now have in the LangRef at <https://llvm.org/docs/LangRef.html#llvm-min-intrinsics-comparation>. Essentially, the APFloat implementation doesn't quiet a signaling NaN input when it should in order to match the LangRef and IEEE spec.
1 parent aa7cc47 commit b75e26b

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

llvm/include/llvm/ADT/APFloat.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,13 +1483,14 @@ inline APFloat maxnum(const APFloat &A, const APFloat &B) {
14831483
}
14841484

14851485
/// Implements IEEE 754-2019 minimum semantics. Returns the smaller of 2
1486-
/// arguments, propagating NaNs and treating -0 as less than +0.
1486+
/// arguments, returning a quiet NaN if an argument is a NaN and treating -0
1487+
/// as less than +0.
14871488
LLVM_READONLY
14881489
inline APFloat minimum(const APFloat &A, const APFloat &B) {
14891490
if (A.isNaN())
1490-
return A;
1491+
return A.makeQuiet();
14911492
if (B.isNaN())
1492-
return B;
1493+
return B.makeQuiet();
14931494
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
14941495
return A.isNegative() ? A : B;
14951496
return B < A ? B : A;
@@ -1509,13 +1510,14 @@ inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
15091510
}
15101511

15111512
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
1512-
/// arguments, propagating NaNs and treating -0 as less than +0.
1513+
/// arguments, returning a quiet NaN if an argument is a NaN and treating -0
1514+
/// as less than +0.
15131515
LLVM_READONLY
15141516
inline APFloat maximum(const APFloat &A, const APFloat &B) {
15151517
if (A.isNaN())
1516-
return A;
1518+
return A.makeQuiet();
15171519
if (B.isNaN())
1518-
return B;
1520+
return B.makeQuiet();
15191521
if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
15201522
return A.isNegative() ? B : A;
15211523
return A < B ? B : A;

llvm/unittests/ADT/APFloatTest.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,13 +607,18 @@ TEST(APFloatTest, Minimum) {
607607
APFloat zp(0.0);
608608
APFloat zn(-0.0);
609609
APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
610+
APFloat snan = APFloat::getSNaN(APFloat::IEEEdouble());
610611

611612
EXPECT_EQ(1.0, minimum(f1, f2).convertToDouble());
612613
EXPECT_EQ(1.0, minimum(f2, f1).convertToDouble());
613614
EXPECT_EQ(-0.0, minimum(zp, zn).convertToDouble());
614615
EXPECT_EQ(-0.0, minimum(zn, zp).convertToDouble());
615616
EXPECT_TRUE(std::isnan(minimum(f1, nan).convertToDouble()));
616617
EXPECT_TRUE(std::isnan(minimum(nan, f1).convertToDouble()));
618+
EXPECT_TRUE(maximum(snan, f1).isNaN());
619+
EXPECT_TRUE(maximum(f1, snan).isNaN());
620+
EXPECT_FALSE(maximum(snan, f1).isSignaling());
621+
EXPECT_FALSE(maximum(f1, snan).isSignaling());
617622
}
618623

619624
TEST(APFloatTest, Maximum) {
@@ -622,13 +627,18 @@ TEST(APFloatTest, Maximum) {
622627
APFloat zp(0.0);
623628
APFloat zn(-0.0);
624629
APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
630+
APFloat snan = APFloat::getSNaN(APFloat::IEEEdouble());
625631

626632
EXPECT_EQ(2.0, maximum(f1, f2).convertToDouble());
627633
EXPECT_EQ(2.0, maximum(f2, f1).convertToDouble());
628634
EXPECT_EQ(0.0, maximum(zp, zn).convertToDouble());
629635
EXPECT_EQ(0.0, maximum(zn, zp).convertToDouble());
630636
EXPECT_TRUE(std::isnan(maximum(f1, nan).convertToDouble()));
631637
EXPECT_TRUE(std::isnan(maximum(nan, f1).convertToDouble()));
638+
EXPECT_TRUE(maximum(snan, f1).isNaN());
639+
EXPECT_TRUE(maximum(f1, snan).isNaN());
640+
EXPECT_FALSE(maximum(snan, f1).isSignaling());
641+
EXPECT_FALSE(maximum(f1, snan).isSignaling());
632642
}
633643

634644
TEST(APFloatTest, MinimumNumber) {

0 commit comments

Comments
 (0)