[libc] Resolve NaN/implementation-defined behavior of floating-point tests
authorDominic Chen <ddchen@apple.com>
Thu, 29 Sep 2022 21:57:56 +0000 (14:57 -0700)
committerDominic Chen <ddchen@apple.com>
Fri, 7 Oct 2022 04:11:47 +0000 (21:11 -0700)
Differential Revision: https://reviews.llvm.org/D134917

22 files changed:
libc/CMakeLists.txt
libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
libc/src/__support/FPUtil/FPBits.h
libc/src/__support/FPUtil/generic/FMod.h
libc/src/__support/FPUtil/generic/sqrt.h
libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
libc/src/__support/str_to_float.h
libc/src/math/generic/atanf.cpp
libc/src/math/generic/atanhf.cpp
libc/test/src/math/FDimTest.h
libc/test/src/math/FmaTest.h
libc/test/src/math/HypotTest.h
libc/test/src/math/ILogbTest.h
libc/test/src/math/LdExpTest.h
libc/test/src/math/NextAfterTest.h
libc/test/src/math/RIntTest.h
libc/test/src/math/RemQuoTest.h
libc/test/src/math/RoundToIntegerTest.h
libc/test/src/math/atanf_test.cpp
libc/test/src/math/atanhf_test.cpp
libc/utils/UnitTest/FPMatcher.h

index 2c403b9..eff5e00 100644 (file)
@@ -49,7 +49,7 @@ else()
 endif()
 
 option(LLVM_LIBC_FULL_BUILD "Build and test LLVM libc as if it is the full libc" OFF)
-
+option(LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR "Build LLVM libc tests assuming our implementation-defined behavior" ON)
 option(LLVM_LIBC_ENABLE_LINTING "Enables linting of libc source files" OFF)
 
 if(LLVM_LIBC_CLANG_TIDY)
index 6af682c..6a55525 100644 (file)
@@ -30,7 +30,7 @@ static inline T remquo(T x, T y, int &q) {
   if (ybits.is_nan())
     return y;
   if (xbits.is_inf() || ybits.is_zero())
-    return FPBits<T>::build_nan(1);
+    return FPBits<T>::build_quiet_nan(1);
 
   if (xbits.is_zero()) {
     q = 0;
index af6891d..fd62a79 100644 (file)
@@ -170,6 +170,10 @@ template <typename T> struct FPBits {
     return T(bits);
   }
 
+  static constexpr T build_quiet_nan(UIntType v) {
+    return build_nan(FloatProp::QUIET_NAN_MASK | v);
+  }
+
   // The function convert integer number and unbiased exponent to proper float
   // T type:
   //   Result = number * 2^(ep+1 - exponent_bias)
index 8362382..c20bd89 100644 (file)
@@ -124,7 +124,7 @@ template <typename T> struct FModExceptionalInputHandler {
 
   static bool PreCheck(T x, T y, T &out) {
     using FPB = fputil::FPBits<T>;
-    const T quiet_NaN = FPB::build_nan(FPB::FloatProp::QUIET_NAN_MASK);
+    const T quiet_NaN = FPB::build_quiet_nan(0);
     FPB sx(x), sy(y);
     if (likely(!sy.is_zero() && !sy.is_inf_or_nan() && !sx.is_inf_or_nan())) {
       return false;
index a6c1e64..125d864 100644 (file)
@@ -79,7 +79,7 @@ static inline cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
     if (bits.is_inf_or_nan()) {
       if (bits.get_sign() && (bits.get_mantissa() == 0)) {
         // sqrt(-Inf) = NaN
-        return FPBits<T>::build_nan(ONE >> 1);
+        return FPBits<T>::build_quiet_nan(ONE >> 1);
       } else {
         // sqrt(NaN) = NaN
         // sqrt(+Inf) = +Inf
@@ -91,7 +91,7 @@ static inline cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
       return x;
     } else if (bits.get_sign()) {
       // sqrt( negative numbers ) = NaN
-      return FPBits<T>::build_nan(ONE >> 1);
+      return FPBits<T>::build_quiet_nan(ONE >> 1);
     } else {
       int x_exp = bits.get_exponent();
       UIntType x_mant = bits.get_mantissa();
index 2943c7d..cf3b2e4 100644 (file)
@@ -44,7 +44,7 @@ static inline long double sqrt(long double x) {
   if (bits.is_inf_or_nan()) {
     if (bits.get_sign() && (bits.get_mantissa() == 0)) {
       // sqrt(-Inf) = NaN
-      return FPBits<long double>::build_nan(ONE >> 1);
+      return FPBits<long double>::build_quiet_nan(ONE >> 1);
     } else {
       // sqrt(NaN) = NaN
       // sqrt(+Inf) = +Inf
@@ -56,7 +56,7 @@ static inline long double sqrt(long double x) {
     return x;
   } else if (bits.get_sign()) {
     // sqrt( negative numbers ) = NaN
-    return FPBits<long double>::build_nan(ONE >> 1);
+    return FPBits<long double>::build_quiet_nan(ONE >> 1);
   } else {
     int x_exp = bits.get_exponent();
     UIntType x_mant = bits.get_mantissa();
index 6992000..57e1923 100644 (file)
@@ -185,6 +185,10 @@ template <> struct FPBits<long double> {
     return bits;
   }
 
+  static long double build_quiet_nan(UIntType v) {
+    return build_nan(FloatProp::QUIET_NAN_MASK | v);
+  }
+
   inline static FPBits<long double>
   create_value(bool sign, UIntType unbiased_exp, UIntType mantissa) {
     FPBits<long double> result;
index 4f952bc..bc0d574 100644 (file)
@@ -971,11 +971,11 @@ static inline T strtofloatingpoint(const char *__restrict src,
       }
       nan_mantissa |= fputil::FloatProperties<T>::QUIET_NAN_MASK;
       if (result.get_sign()) {
-        result = fputil::FPBits<T>(result.build_nan(nan_mantissa));
+        result = fputil::FPBits<T>(result.build_quiet_nan(nan_mantissa));
         result.set_sign(true);
       } else {
         result.set_sign(false);
-        result = fputil::FPBits<T>(result.build_nan(nan_mantissa));
+        result = fputil::FPBits<T>(result.build_quiet_nan(nan_mantissa));
       }
     }
   } else if ((*src | 32) == 'i') { // INF
index 490a77c..d27db59 100644 (file)
@@ -23,7 +23,7 @@ LLVM_LIBC_FUNCTION(float, atanf, (float x)) {
     if (xbits.is_inf())
       return opt_barrier(sign ? -M_MATH_PI_2 : M_MATH_PI_2);
     else
-      return x + 1.0f;
+      return x;
   }
   // |x| == 0.06905200332403183
   if (unlikely(xbits.uintval() == 0x3d8d6b23U)) {
index 0d01510..7f39e99 100644 (file)
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(float, atanhf, (float x)) {
   // |x| >= 1.0
   if (unlikely(x_abs >= 0x3F80'0000U)) {
     if (xbits.is_nan()) {
-      return x + 1.0f;
+      return x;
     }
     // |x| == 0
     if (x_abs == 0x3F80'0000U) {
index 587913a..5763e04 100644 (file)
@@ -74,7 +74,7 @@ public:
 private:
   // constexpr does not work on FPBits yet, so we cannot have these constants as
   // static.
-  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_nan(1));
+  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_quiet_nan(1));
   const T inf = T(__llvm_libc::fputil::FPBits<T>::inf());
   const T neg_inf = T(__llvm_libc::fputil::FPBits<T>::neg_inf());
   const T zero = T(__llvm_libc::fputil::FPBits<T>::zero());
index 959c4e8..4726267 100644 (file)
@@ -23,7 +23,7 @@ private:
   using Func = T (*)(T, T, T);
   using FPBits = __llvm_libc::fputil::FPBits<T>;
   using UIntType = typename FPBits::UIntType;
-  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_nan(1));
+  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_quiet_nan(1));
   const T inf = T(__llvm_libc::fputil::FPBits<T>::inf());
   const T neg_inf = T(__llvm_libc::fputil::FPBits<T>::neg_inf());
   const T zero = T(__llvm_libc::fputil::FPBits<T>::zero());
index 57abef8..b110bce 100644 (file)
@@ -24,7 +24,7 @@ private:
   using Func = T (*)(T, T);
   using FPBits = __llvm_libc::fputil::FPBits<T>;
   using UIntType = typename FPBits::UIntType;
-  const T nan = T(FPBits::build_nan(1));
+  const T nan = T(FPBits::build_quiet_nan(1));
   const T inf = T(FPBits::inf());
   const T neg_inf = T(FPBits::neg_inf());
   const T zero = T(FPBits::zero());
index e2de14d..b026b05 100644 (file)
@@ -26,7 +26,7 @@ public:
     EXPECT_EQ(FP_ILOGB0, func(T(__llvm_libc::fputil::FPBits<T>::neg_zero())));
 
     EXPECT_EQ(FP_ILOGBNAN,
-              func(T(__llvm_libc::fputil::FPBits<T>::build_nan(1))));
+              func(T(__llvm_libc::fputil::FPBits<T>::build_quiet_nan(1))));
 
     EXPECT_EQ(INT_MAX, func(T(__llvm_libc::fputil::FPBits<T>::inf())));
     EXPECT_EQ(INT_MAX, func(T(__llvm_libc::fputil::FPBits<T>::neg_inf())));
index ca9f33f..5830fc3 100644 (file)
@@ -32,7 +32,7 @@ class LdExpTestTemplate : public __llvm_libc::testing::Test {
   const T neg_zero = T(__llvm_libc::fputil::FPBits<T>::neg_zero());
   const T inf = T(__llvm_libc::fputil::FPBits<T>::inf());
   const T neg_inf = T(__llvm_libc::fputil::FPBits<T>::neg_inf());
-  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_nan(1));
+  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_quiet_nan(1));
 
 public:
   typedef T (*LdExpFunc)(T, int);
index fcc2c43..12c9bb9 100644 (file)
@@ -30,7 +30,7 @@ class NextAfterTestTemplate : public __llvm_libc::testing::Test {
   const T neg_zero = T(FPBits::neg_zero());
   const T inf = T(FPBits::inf());
   const T neg_inf = T(FPBits::neg_inf());
-  const T nan = T(FPBits::build_nan(1));
+  const T nan = T(FPBits::build_quiet_nan(1));
   const UIntType min_subnormal = FPBits::MIN_SUBNORMAL;
   const UIntType max_subnormal = FPBits::MAX_SUBNORMAL;
   const UIntType min_normal = FPBits::MIN_NORMAL;
index 90945fe..de5652b 100644 (file)
@@ -37,7 +37,7 @@ private:
   const T neg_zero = T(FPBits::neg_zero());
   const T inf = T(FPBits::inf());
   const T neg_inf = T(FPBits::neg_inf());
-  const T nan = T(FPBits::build_nan(1));
+  const T nan = T(FPBits::build_quiet_nan(1));
 
   static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) {
     switch (mode) {
index 5903760..3428f8d 100644 (file)
@@ -27,7 +27,7 @@ class RemQuoTestTemplate : public __llvm_libc::testing::Test {
   const T neg_zero = T(__llvm_libc::fputil::FPBits<T>::neg_zero());
   const T inf = T(__llvm_libc::fputil::FPBits<T>::inf());
   const T neg_inf = T(__llvm_libc::fputil::FPBits<T>::neg_inf());
-  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_nan(1));
+  const T nan = T(__llvm_libc::fputil::FPBits<T>::build_quiet_nan(1));
 
 public:
   typedef T (*RemQuoFunc)(T, T, int *);
index 27a19e1..a7627b2 100644 (file)
@@ -36,7 +36,7 @@ private:
   const F neg_zero = F(__llvm_libc::fputil::FPBits<F>::neg_zero());
   const F inf = F(__llvm_libc::fputil::FPBits<F>::inf());
   const F neg_inf = F(__llvm_libc::fputil::FPBits<F>::neg_inf());
-  const F nan = F(__llvm_libc::fputil::FPBits<F>::build_nan(1));
+  const F nan = F(__llvm_libc::fputil::FPBits<F>::build_quiet_nan(1));
   static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1);
   static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
 
@@ -84,7 +84,10 @@ public:
   void do_infinity_and_na_n_test(RoundToIntegerFunc func) {
     test_one_input(func, inf, INTEGER_MAX, true);
     test_one_input(func, neg_inf, INTEGER_MIN, true);
+#if LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR
+    // Result is not well-defined, we always returns INTEGER_MAX
     test_one_input(func, nan, INTEGER_MAX, true);
+#endif
   }
 
   void testInfinityAndNaN(RoundToIntegerFunc func) {
index 8dc61bb..28c5fcd 100644 (file)
@@ -28,7 +28,7 @@ TEST(LlvmLibcAtanfTest, SpecialNumbers) {
   errno = 0;
   __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
   EXPECT_FP_EQ(aNaN, __llvm_libc::atanf(aNaN));
-  EXPECT_FP_EXCEPTION(FE_INVALID);
+  EXPECT_FP_EXCEPTION(0);
   EXPECT_MATH_ERRNO(0);
 
   __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
index 306fc19..ad6d56d 100644 (file)
@@ -26,7 +26,7 @@ TEST(LlvmLibcAtanhfTest, SpecialNumbers) {
   errno = 0;
   __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
   EXPECT_FP_EQ(aNaN, __llvm_libc::atanhf(aNaN));
-  EXPECT_FP_EXCEPTION(FE_INVALID);
+  EXPECT_FP_EXCEPTION(0);
   EXPECT_MATH_ERRNO(0);
 
   __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
index 0dd9754..1c2b540 100644 (file)
@@ -72,7 +72,7 @@ FPMatcher<T, C> getMatcher(T expectedValue) {
   using UIntType = typename FPBits::UIntType;                                  \
   const T zero = T(FPBits::zero());                                            \
   const T neg_zero = T(FPBits::neg_zero());                                    \
-  const T aNaN = T(FPBits::build_nan(1));                                      \
+  const T aNaN = T(FPBits::build_quiet_nan(1));                                \
   const T inf = T(FPBits::inf());                                              \
   const T neg_inf = T(FPBits::neg_inf());