[libc-commits] [libc] 987fac7 - [libc] Match x86 long double NaN classification with that of the compiler.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Mon Jun 22 23:02:45 PDT 2020


Author: Siva Chandra Reddy
Date: 2020-06-22T23:02:05-07:00
New Revision: 987fac79c9a951806cbda6b178b05fcb5145fde8

URL: https://github.com/llvm/llvm-project/commit/987fac79c9a951806cbda6b178b05fcb5145fde8
DIFF: https://github.com/llvm/llvm-project/commit/987fac79c9a951806cbda6b178b05fcb5145fde8.diff

LOG: [libc] Match x86 long double NaN classification with that of the compiler.

Reviewers: asteinhauser

Differential Revision: https://reviews.llvm.org/D82330

Added: 
    libc/test/utils/CMakeLists.txt
    libc/test/utils/FPUtil/CMakeLists.txt
    libc/test/utils/FPUtil/x86_long_double_test.cpp

Modified: 
    libc/test/CMakeLists.txt
    libc/utils/FPUtil/LongDoubleBitsX86.h

Removed: 
    


################################################################################
diff  --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt
index aa77dcd2727f..500b294ad386 100644
--- a/libc/test/CMakeLists.txt
+++ b/libc/test/CMakeLists.txt
@@ -3,3 +3,4 @@ add_custom_target(check-libc)
 add_subdirectory(config)
 add_subdirectory(loader)
 add_subdirectory(src)
+add_subdirectory(utils)

diff  --git a/libc/test/utils/CMakeLists.txt b/libc/test/utils/CMakeLists.txt
new file mode 100644
index 000000000000..90ff4bbdab23
--- /dev/null
+++ b/libc/test/utils/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(FPUtil)

diff  --git a/libc/test/utils/FPUtil/CMakeLists.txt b/libc/test/utils/FPUtil/CMakeLists.txt
new file mode 100644
index 000000000000..65cb677e22d3
--- /dev/null
+++ b/libc/test/utils/FPUtil/CMakeLists.txt
@@ -0,0 +1,10 @@
+if((${LIBC_TARGET_OS} STREQUAL "linux") AND (${LIBC_TARGET_MACHINE} MATCHES "i386|x86_64"))
+  add_libc_unittest(
+    x86_long_double_test
+    SRCS
+      x86_long_double_test.cpp
+    DEPENDS
+      libc.include.math
+      libc.utils.FPUtil.fputil
+  )
+endif()

diff  --git a/libc/test/utils/FPUtil/x86_long_double_test.cpp b/libc/test/utils/FPUtil/x86_long_double_test.cpp
new file mode 100644
index 000000000000..d4fb8707f2bf
--- /dev/null
+++ b/libc/test/utils/FPUtil/x86_long_double_test.cpp
@@ -0,0 +1,85 @@
+//===-- Unittests for x86 long double -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "utils/FPUtil/FPBits.h"
+#include "utils/UnitTest/Test.h"
+
+using FPBits = __llvm_libc::fputil::FPBits<long double>;
+
+TEST(X86LongDoubleTest, isNaN) {
+  // In the nan checks below, we use the macro isnan from math.h to ensure that
+  // a number is actually a NaN. The isnan macro resolves to the compiler
+  // builtin function. Hence, matching LLVM-libc's notion of NaN with the
+  // isnan result ensures that LLVM-libc's behavior matches the compiler's
+  // behavior.
+
+  FPBits bits(0.0l);
+  bits.exponent = FPBits::maxExponent;
+  for (unsigned int i = 0; i < 1000000; ++i) {
+    // If exponent has the max value and the implicit bit is 0,
+    // then the number is a NaN for all values of mantissa.
+    bits.mantissa = i;
+    long double nan = bits;
+    ASSERT_NE(isnan(nan), 0);
+    ASSERT_TRUE(bits.isNaN());
+  }
+
+  bits.implicitBit = 1;
+  for (unsigned int i = 1; i < 1000000; ++i) {
+    // If exponent has the max value and the implicit bit is 1,
+    // then the number is a NaN for all non-zero values of mantissa.
+    // Note the initial value of |i| of 1 to avoid a zero mantissa.
+    bits.mantissa = i;
+    long double nan = bits;
+    ASSERT_NE(isnan(nan), 0);
+    ASSERT_TRUE(bits.isNaN());
+  }
+
+  bits.exponent = 1;
+  bits.implicitBit = 0;
+  for (unsigned int i = 0; i < 1000000; ++i) {
+    // If exponent is non-zero and also not max, and the implicit bit is 0,
+    // then the number is a NaN for all values of mantissa.
+    bits.mantissa = i;
+    long double nan = bits;
+    ASSERT_NE(isnan(nan), 0);
+    ASSERT_TRUE(bits.isNaN());
+  }
+
+  bits.exponent = 1;
+  bits.implicitBit = 1;
+  for (unsigned int i = 0; i < 1000000; ++i) {
+    // If exponent is non-zero and also not max, and the implicit bit is 1,
+    // then the number is normal value for all values of mantissa.
+    bits.mantissa = i;
+    long double valid = bits;
+    ASSERT_EQ(isnan(valid), 0);
+    ASSERT_FALSE(bits.isNaN());
+  }
+
+  bits.exponent = 0;
+  bits.implicitBit = 1;
+  for (unsigned int i = 0; i < 1000000; ++i) {
+    // If exponent is zero, then the number is a valid but denormal value.
+    bits.mantissa = i;
+    long double valid = bits;
+    ASSERT_EQ(isnan(valid), 0);
+    ASSERT_FALSE(bits.isNaN());
+  }
+
+  bits.exponent = 0;
+  bits.implicitBit = 0;
+  for (unsigned int i = 0; i < 1000000; ++i) {
+    // If exponent is zero, then the number is a valid but denormal value.
+    bits.mantissa = i;
+    long double valid = bits;
+    ASSERT_EQ(isnan(valid), 0);
+    ASSERT_FALSE(bits.isNaN());
+  }
+}

diff  --git a/libc/utils/FPUtil/LongDoubleBitsX86.h b/libc/utils/FPUtil/LongDoubleBitsX86.h
index 1e92dba4383d..3d7f455ff22c 100644
--- a/libc/utils/FPUtil/LongDoubleBitsX86.h
+++ b/libc/utils/FPUtil/LongDoubleBitsX86.h
@@ -62,9 +62,18 @@ template <> struct __attribute__((packed)) FPBits<long double> {
     return exponent == maxExponent && mantissa == 0 && implicitBit == 1;
   }
 
-  bool isNaN() const { return exponent == maxExponent && mantissa != 0; }
+  bool isNaN() const {
+    if (exponent == maxExponent) {
+      return (implicitBit == 0) || mantissa != 0;
+    } else if (exponent != 0) {
+      return implicitBit == 0;
+    }
+    return false;
+  }
 
-  bool isInfOrNaN() const { return exponent == maxExponent; }
+  bool isInfOrNaN() const {
+    return (exponent == maxExponent) || (exponent != 0 && implicitBit == 0);
+  }
 
   // Methods below this are used by tests.
 


        


More information about the libc-commits mailing list