[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