-
Notifications
You must be signed in to change notification settings - Fork 14.3k
APFloat: Add minimumnum and maximumnum #96304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-adt Author: YunQiang Su (wzssyqa) ChangesThey implements IEEE754-2019 minimumNumber and maximumNumber semantics. Newer libc also has these 2 function with name We are planning add minimumnum and maximumnum intrinsic. This is a step to the goal. Full diff: https://github.com/llvm/llvm-project/pull/96304.diff 2 Files Affected:
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index c24eae8da3797..db2fa480655c6 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -1483,6 +1483,19 @@ inline APFloat minimum(const APFloat &A, const APFloat &B) {
return B < A ? B : A;
}
+/// Implements IEEE 754-2019 minimumNumber semantics. Returns the smaller
+/// of 2 arguments, not propagating NaNs and treating -0 as less than +0.
+LLVM_READONLY
+inline APFloat minimumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? A : B;
+ return B < A ? B : A;
+}
+
/// Implements IEEE 754-2019 maximum semantics. Returns the larger of 2
/// arguments, propagating NaNs and treating -0 as less than +0.
LLVM_READONLY
@@ -1496,6 +1509,19 @@ inline APFloat maximum(const APFloat &A, const APFloat &B) {
return A < B ? B : A;
}
+/// Implements IEEE 754-2019 maximumNumber semantics. Returns the larger
+/// of 2 arguments, not propagating NaNs and treating -0 as less than +0.
+LLVM_READONLY
+inline APFloat maximumnum(const APFloat &A, const APFloat &B) {
+ if (A.isNaN())
+ return B.isNaN() ? B.makeQuiet() : B;
+ if (B.isNaN())
+ return A;
+ if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
+ return A.isNegative() ? B : A;
+ return A < B ? B : A;
+}
+
// We want the following functions to be available in the header for inlining.
// We cannot define them inline in the class definition of `DoubleAPFloat`
// because doing so would instantiate `std::unique_ptr<APFloat[]>` before
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index f6af4b0e5f651..a105cd81d7431 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -631,6 +631,54 @@ TEST(APFloatTest, Maximum) {
EXPECT_TRUE(std::isnan(maximum(nan, f1).convertToDouble()));
}
+TEST(APFloatTest, MinimumNumber) {
+ APFloat f1(1.0);
+ APFloat f2(2.0);
+ APFloat zp(0.0);
+ APFloat zn(-0.0);
+ APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
+ APFloat snan = APFloat::getSNaN(APFloat::IEEEdouble());
+
+ EXPECT_EQ(1.0, minimumnum(f1, f2).convertToDouble());
+ EXPECT_EQ(1.0, minimumnum(f2, f1).convertToDouble());
+ EXPECT_EQ(-0.0, minimumnum(zp, zn).convertToDouble());
+ EXPECT_EQ(-0.0, minimumnum(zn, zp).convertToDouble());
+ EXPECT_TRUE(minimumnum(zn, zp).isNegative());
+ EXPECT_TRUE(minimumnum(zp, zn).isNegative());
+ EXPECT_TRUE(minimumnum(zn, zn).isNegative());
+ EXPECT_FALSE(minimumnum(zp, zp).isNegative());
+ EXPECT_FALSE(std::isnan(minimumnum(f1, nan).convertToDouble()));
+ EXPECT_FALSE(std::isnan(minimumnum(nan, f1).convertToDouble()));
+ EXPECT_FALSE(std::isnan(minimumnum(f1, snan).convertToDouble()));
+ EXPECT_FALSE(std::isnan(minimumnum(snan, f1).convertToDouble()));
+ EXPECT_FALSE(minimumnum(snan, nan).isSignaling());
+ EXPECT_FALSE(minimumnum(snan, snan).isSignaling());
+}
+
+TEST(APFloatTest, MaximumNumber) {
+ APFloat f1(1.0);
+ APFloat f2(2.0);
+ APFloat zp(0.0);
+ APFloat zn(-0.0);
+ APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
+ APFloat snan = APFloat::getSNaN(APFloat::IEEEdouble());
+
+ EXPECT_EQ(2.0, maximumnum(f1, f2).convertToDouble());
+ EXPECT_EQ(2.0, maximumnum(f2, f1).convertToDouble());
+ EXPECT_EQ(0.0, maximumnum(zp, zn).convertToDouble());
+ EXPECT_EQ(0.0, maximumnum(zn, zp).convertToDouble());
+ EXPECT_FALSE(maximumnum(zn, zp).isNegative());
+ EXPECT_FALSE(maximumnum(zp, zn).isNegative());
+ EXPECT_TRUE(maximumnum(zn, zn).isNegative());
+ EXPECT_FALSE(maximumnum(zp, zp).isNegative());
+ EXPECT_FALSE(std::isnan(maximumnum(f1, nan).convertToDouble()));
+ EXPECT_FALSE(std::isnan(maximumnum(nan, f1).convertToDouble()));
+ EXPECT_FALSE(std::isnan(maximumnum(f1, snan).convertToDouble()));
+ EXPECT_FALSE(std::isnan(maximumnum(snan, f1).convertToDouble()));
+ EXPECT_FALSE(maximumnum(snan, nan).isSignaling());
+ EXPECT_FALSE(maximumnum(snan, snan).isSignaling());
+}
+
TEST(APFloatTest, Denormal) {
APFloat::roundingMode rdmd = APFloat::rmNearestTiesToEven;
|
llvm/unittests/ADT/APFloatTest.cpp
Outdated
EXPECT_FALSE(std::isnan(minimumnum(nan, f1).convertToDouble())); | ||
EXPECT_FALSE(std::isnan(minimumnum(f1, snan).convertToDouble())); | ||
EXPECT_FALSE(std::isnan(minimumnum(snan, f1).convertToDouble())); | ||
EXPECT_FALSE(minimumnum(snan, nan).isSignaling()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also test the commuted case. Also test some snan + non-nan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For snan+non-nan, I tested minimumnum(snan, f1=1.0). Do we need more f1 values?
And what is commuted
case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean mininimumnum(1.0f, snan) too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean mininimumnum(1.0f, snan) too
Just swap? If so, I think that we already have it.
Or you mean single precision one?
Thanks for splitting it out. I let the float experts review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with nit
They implements IEEE754-2019 minimumNumber and maximumNumber semantics. Newer libc also has these 2 function with name fminimum_num fmaximum_num We are planning add minimumnum and maximumnum intrinsic. This is a step for them.
a97d702
to
57681e8
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/35/builds/374 Here is the relevant piece of the build log for the reference:
|
Ohh, I think that I need help for it. |
They implements IEEE754-2019 minimumNumber and maximumNumber semantics. Newer libc also has these 2 functions with names fminimum_num fmaximum_num We are planning add minimumnum and maximumnum intrinsic. This is a step to the goal.
They implements IEEE754-2019 minimumNumber and maximumNumber semantics.
Newer libc also has these 2 functions with names
fminimum_num
fmaximum_num
We are planning add minimumnum and maximumnum intrinsic. This is a step to the goal.