[libc] Consolidate floating point utils into a single utils library.
authorSiva Chandra Reddy <sivachandra@google.com>
Fri, 8 May 2020 06:19:09 +0000 (23:19 -0700)
committerSiva Chandra Reddy <sivachandra@google.com>
Fri, 15 May 2020 18:08:41 +0000 (11:08 -0700)
A new utils library named 'fputil' is added. This library is used in
math tests and the MPFR wrapper. The math implementations will be
modified to use this library in a later round.

Reviewers: phosek

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

13 files changed:
libc/test/src/math/CMakeLists.txt
libc/test/src/math/cosf_test.cpp
libc/test/src/math/float.h [deleted file]
libc/test/src/math/sdcomp26094.h
libc/test/src/math/sincosf_test.cpp
libc/test/src/math/sinf_test.cpp
libc/utils/CMakeLists.txt
libc/utils/FPUtil/BitPatterns.h [new file with mode: 0644]
libc/utils/FPUtil/CMakeLists.txt [new file with mode: 0644]
libc/utils/FPUtil/FloatOperations.h [new file with mode: 0644]
libc/utils/FPUtil/FloatProperties.h [new file with mode: 0644]
libc/utils/MPFRWrapper/CMakeLists.txt
libc/utils/MPFRWrapper/MPFRUtils.cpp

index 8f701f6..3790a47 100644 (file)
@@ -23,12 +23,6 @@ function(add_math_unittest name)
   endif()
 endfunction(add_math_unittest)
 
-add_header_library(
-  float_utils
-  HDRS
-    float.h
-)
-
 add_math_unittest(
   cosf_test
   NEED_MPFR
@@ -39,9 +33,10 @@ add_math_unittest(
   HDRS
     sdcomp26094.h
   DEPENDS
-    .float_utils
+    libc.include.errno
     libc.src.math.cosf
     libc.utils.CPP.standalone_cpp
+    libc.utils.FPUtil.fputil
 )
 
 add_math_unittest(
@@ -54,9 +49,10 @@ add_math_unittest(
   HDRS
     sdcomp26094.h
   DEPENDS
-    .float_utils
+    libc.include.errno
     libc.src.math.sinf
     libc.utils.CPP.standalone_cpp
+    libc.utils.FPUtil.fputil
 )
 
 add_math_unittest(
@@ -69,7 +65,8 @@ add_math_unittest(
   HDRS
     sdcomp26094.h
   DEPENDS
-    .float_utils
+    libc.include.errno
     libc.src.math.sincosf
     libc.utils.CPP.standalone_cpp
+    libc.utils.FPUtil.fputil
 )
index 54bba16..f9fc9c2 100644 (file)
@@ -6,22 +6,27 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "include/errno.h"
 #include "include/math.h"
 #include "src/errno/llvmlibc_errno.h"
 #include "src/math/cosf.h"
-#include "src/math/math_utils.h"
-#include "test/src/math/float.h"
 #include "test/src/math/sdcomp26094.h"
 #include "utils/CPP/Array.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 #include "utils/UnitTest/Test.h"
 
 #include <stdint.h>
 
-using __llvm_libc::as_float;
-using __llvm_libc::as_uint32_bits;
+using __llvm_libc::fputil::isNegativeQuietNaN;
+using __llvm_libc::fputil::isQuietNaN;
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
 
-using __llvm_libc::testing::FloatBits;
 using __llvm_libc::testing::sdcomp26094Values;
 
 namespace mpfr = __llvm_libc::testing::mpfr;
@@ -34,38 +39,37 @@ static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
 TEST(CosfTest, SpecialNumbers) {
   llvmlibc_errno = 0;
 
-  EXPECT_TRUE(FloatBits::isQNan(
-      as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::QNan)))));
+  EXPECT_TRUE(
+      isQuietNaN(__llvm_libc::cosf(valueFromBits(BitPatterns::aQuietNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_TRUE(FloatBits::isNegQNan(
-      as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegQNan)))));
+  EXPECT_TRUE(isNegativeQuietNaN(
+      __llvm_libc::cosf(valueFromBits(BitPatterns::aNegativeQuietNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_TRUE(FloatBits::isQNan(
-      as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::SNan)))));
+  EXPECT_TRUE(isQuietNaN(
+      __llvm_libc::cosf(valueFromBits(BitPatterns::aSignallingNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_TRUE(FloatBits::isNegQNan(
-      as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegSNan)))));
+  EXPECT_TRUE(isNegativeQuietNaN(
+      __llvm_libc::cosf(valueFromBits(BitPatterns::aNegativeSignallingNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_EQ(FloatBits::One,
-            as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::Zero))));
+  EXPECT_EQ(BitPatterns::one,
+            valueAsBits(__llvm_libc::cosf(valueFromBits(BitPatterns::zero))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_EQ(FloatBits::One,
-            as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegZero))));
+  EXPECT_EQ(BitPatterns::one, valueAsBits(__llvm_libc::cosf(
+                                  valueFromBits(BitPatterns::negZero))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
   llvmlibc_errno = 0;
-  EXPECT_TRUE(FloatBits::isQNan(
-      as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::Inf)))));
+  EXPECT_TRUE(isQuietNaN(__llvm_libc::cosf(valueFromBits(BitPatterns::inf))));
   EXPECT_EQ(llvmlibc_errno, EDOM);
 
   llvmlibc_errno = 0;
-  EXPECT_TRUE(FloatBits::isNegQNan(
-      as_uint32_bits(__llvm_libc::cosf(as_float(FloatBits::NegInf)))));
+  EXPECT_TRUE(isNegativeQuietNaN(
+      __llvm_libc::cosf(valueFromBits(BitPatterns::negInf))));
   EXPECT_EQ(llvmlibc_errno, EDOM);
 }
 
@@ -73,7 +77,7 @@ TEST(CosfTest, InFloatRange) {
   constexpr uint32_t count = 1000000;
   constexpr uint32_t step = UINT32_MAX / count;
   for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
-    float x = as_float(v);
+    float x = valueFromBits(v);
     if (isnan(x) || isinf(x))
       continue;
     ASSERT_MPFR_MATCH(mpfr::OP_Cos, x, __llvm_libc::cosf(x), tolerance);
@@ -82,22 +86,22 @@ TEST(CosfTest, InFloatRange) {
 
 // For small values, cos(x) is 1.
 TEST(CosfTest, SmallValues) {
-  float x = as_float(0x17800000);
+  float x = valueFromBits(0x17800000U);
   float result = __llvm_libc::cosf(x);
   EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result, tolerance);
-  EXPECT_EQ(FloatBits::One, as_uint32_bits(result));
+  EXPECT_EQ(BitPatterns::one, valueAsBits(result));
 
-  x = as_float(0x0040000);
+  x = valueFromBits(0x0040000U);
   result = __llvm_libc::cosf(x);
   EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result, tolerance);
-  EXPECT_EQ(FloatBits::One, as_uint32_bits(result));
+  EXPECT_EQ(BitPatterns::one, valueAsBits(result));
 }
 
 // SDCOMP-26094: check cosf in the cases for which the range reducer
 // returns values furthest beyond its nominal upper bound of pi/4.
 TEST(CosfTest, SDCOMP_26094) {
   for (uint32_t v : sdcomp26094Values) {
-    float x = as_float(v);
+    float x = valueFromBits(v);
     ASSERT_MPFR_MATCH(mpfr::OP_Cos, x, __llvm_libc::cosf(x), tolerance);
   }
 }
diff --git a/libc/test/src/math/float.h b/libc/test/src/math/float.h
deleted file mode 100644 (file)
index bfa15a1..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- Single precision floating point test utils --------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_TEST_SRC_MATH_FLOAT_H
-#define LLVM_LIBC_TEST_SRC_MATH_FLOAT_H
-
-#include "src/math/math_utils.h"
-
-namespace __llvm_libc {
-namespace testing {
-
-struct FloatBits {
-  // The various NaN bit patterns here are just one of the many possible
-  // patterns. The functions isQNan and isNegQNan can help understand why.
-
-  static const uint32_t QNan = 0x7fc00000;
-  static const uint32_t NegQNan = 0xffc00000;
-
-  static const uint32_t SNan = 0x7f800001;
-  static const uint32_t NegSNan = 0xff800001;
-
-  static bool isQNan(float f) {
-    uint32_t bits = as_uint32_bits(f);
-    return ((0x7fc00000 & bits) != 0) && ((0x80000000 & bits) == 0);
-  }
-
-  static bool isNegQNan(float f) {
-    uint32_t bits = as_uint32_bits(f);
-    return 0xffc00000 & bits;
-  }
-
-  static constexpr uint32_t Zero = 0x0;
-  static constexpr uint32_t NegZero = 0x80000000;
-
-  static constexpr uint32_t Inf = 0x7f800000;
-  static constexpr uint32_t NegInf = 0xff800000;
-
-  static constexpr uint32_t One = 0x3f800000;
-};
-
-} // namespace testing
-} // namespace __llvm_libc
-
-#endif // LLVM_LIBC_TEST_SRC_MATH_FLOAT_H
index 7ebcd60..7e47753 100644 (file)
 #define LLVM_LIBC_TEST_SRC_MATH_SDCOMP26094_H
 
 #include "utils/CPP/Array.h"
+#include "utils/FPUtil/BitPatterns.h"
 
 namespace __llvm_libc {
 namespace testing {
 
-static constexpr __llvm_libc::cpp::Array<uint32_t, 10> sdcomp26094Values{
-    0x46427f1b, 0x4647e568, 0x46428bac, 0x4647f1f9, 0x4647fe8a,
-    0x45d8d7f1, 0x45d371a4, 0x45ce0b57, 0x45d35882, 0x45cdf235,
-};
+static constexpr __llvm_libc::cpp::Array<fputil::BitPatterns<float>::BitsType,
+                                         10>
+    sdcomp26094Values{
+        0x46427f1b, 0x4647e568, 0x46428bac, 0x4647f1f9, 0x4647fe8a,
+        0x45d8d7f1, 0x45d371a4, 0x45ce0b57, 0x45d35882, 0x45cdf235,
+    };
 
 } // namespace testing
 } // namespace __llvm_libc
index 93b827a..9a87e2c 100644 (file)
@@ -6,25 +6,31 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "include/errno.h"
 #include "include/math.h"
 #include "src/errno/llvmlibc_errno.h"
-#include "src/math/math_utils.h"
 #include "src/math/sincosf.h"
-#include "test/src/math/float.h"
 #include "test/src/math/sdcomp26094.h"
 #include "utils/CPP/Array.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 #include "utils/UnitTest/Test.h"
 
 #include <stdint.h>
 
-using __llvm_libc::as_float;
-using __llvm_libc::as_uint32_bits;
+using __llvm_libc::fputil::isNegativeQuietNaN;
+using __llvm_libc::fputil::isQuietNaN;
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
 
-using __llvm_libc::testing::FloatBits;
 using __llvm_libc::testing::sdcomp26094Values;
 
 namespace mpfr = __llvm_libc::testing::mpfr;
+
 // 12 additional bits of precision over the base precision of a |float|
 // value.
 static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
@@ -34,46 +40,48 @@ TEST(SinCosfTest, SpecialNumbers) {
   llvmlibc_errno = 0;
   float sin, cos;
 
-  __llvm_libc::sincosf(as_float(FloatBits::QNan), &sin, &cos);
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::aQuietNaN), &sin, &cos);
+  EXPECT_TRUE(isQuietNaN(cos));
+  EXPECT_TRUE(isQuietNaN(sin));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  __llvm_libc::sincosf(as_float(FloatBits::NegQNan), &sin, &cos);
-  EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(cos)));
-  EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(sin)));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::aNegativeQuietNaN), &sin,
+                       &cos);
+  EXPECT_TRUE(isNegativeQuietNaN(cos));
+  EXPECT_TRUE(isNegativeQuietNaN(sin));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  __llvm_libc::sincosf(as_float(FloatBits::SNan), &sin, &cos);
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::aSignallingNaN), &sin, &cos);
+  EXPECT_TRUE(isQuietNaN(cos));
+  EXPECT_TRUE(isQuietNaN(sin));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  __llvm_libc::sincosf(as_float(FloatBits::NegSNan), &sin, &cos);
-  EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(cos)));
-  EXPECT_TRUE(FloatBits::isNegQNan(as_uint32_bits(sin)));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::aNegativeSignallingNaN), &sin,
+                       &cos);
+  EXPECT_TRUE(isNegativeQuietNaN(cos));
+  EXPECT_TRUE(isNegativeQuietNaN(sin));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  __llvm_libc::sincosf(as_float(FloatBits::Zero), &sin, &cos);
-  EXPECT_EQ(FloatBits::One, as_uint32_bits(cos));
-  EXPECT_EQ(FloatBits::Zero, as_uint32_bits(sin));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::zero), &sin, &cos);
+  EXPECT_EQ(BitPatterns::one, valueAsBits(cos));
+  EXPECT_EQ(BitPatterns::zero, valueAsBits(sin));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  __llvm_libc::sincosf(as_float(FloatBits::NegZero), &sin, &cos);
-  EXPECT_EQ(FloatBits::One, as_uint32_bits(cos));
-  EXPECT_EQ(FloatBits::NegZero, as_uint32_bits(sin));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::negZero), &sin, &cos);
+  EXPECT_EQ(BitPatterns::one, valueAsBits(cos));
+  EXPECT_EQ(BitPatterns::negZero, valueAsBits(sin));
   EXPECT_EQ(llvmlibc_errno, 0);
 
   llvmlibc_errno = 0;
-  __llvm_libc::sincosf(as_float(FloatBits::Inf), &sin, &cos);
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::inf), &sin, &cos);
+  EXPECT_TRUE(isQuietNaN(cos));
+  EXPECT_TRUE(isQuietNaN(sin));
   EXPECT_EQ(llvmlibc_errno, EDOM);
 
   llvmlibc_errno = 0;
-  __llvm_libc::sincosf(as_float(FloatBits::NegInf), &sin, &cos);
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(cos)));
-  EXPECT_TRUE(FloatBits::isQNan(as_uint32_bits(sin)));
+  __llvm_libc::sincosf(valueFromBits(BitPatterns::negInf), &sin, &cos);
+  EXPECT_TRUE(isQuietNaN(cos));
+  EXPECT_TRUE(isQuietNaN(sin));
   EXPECT_EQ(llvmlibc_errno, EDOM);
 }
 
@@ -81,7 +89,7 @@ TEST(SinCosfTest, InFloatRange) {
   constexpr uint32_t count = 1000000;
   constexpr uint32_t step = UINT32_MAX / count;
   for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
-    float x = as_float(v);
+    float x = valueFromBits(v);
     if (isnan(x) || isinf(x))
       continue;
 
@@ -95,28 +103,28 @@ TEST(SinCosfTest, InFloatRange) {
 // For small values, cos(x) is 1 and sin(x) is x.
 TEST(SinCosfTest, SmallValues) {
   uint32_t bits = 0x17800000;
-  float x = as_float(bits);
+  float x = valueFromBits(bits);
   float result_cos, result_sin;
   __llvm_libc::sincosf(x, &result_sin, &result_cos);
   EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result_cos, tolerance);
   EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result_sin, tolerance);
-  EXPECT_EQ(FloatBits::One, as_uint32_bits(result_cos));
-  EXPECT_EQ(bits, as_uint32_bits(result_sin));
+  EXPECT_EQ(BitPatterns::one, valueAsBits(result_cos));
+  EXPECT_EQ(bits, valueAsBits(result_sin));
 
   bits = 0x00400000;
-  x = as_float(bits);
+  x = valueFromBits(bits);
   __llvm_libc::sincosf(x, &result_sin, &result_cos);
   EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, result_cos, tolerance);
   EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result_sin, tolerance);
-  EXPECT_EQ(FloatBits::One, as_uint32_bits(result_cos));
-  EXPECT_EQ(bits, as_uint32_bits(result_sin));
+  EXPECT_EQ(BitPatterns::one, valueAsBits(result_cos));
+  EXPECT_EQ(bits, valueAsBits(result_sin));
 }
 
 // SDCOMP-26094: check sinf in the cases for which the range reducer
 // returns values furthest beyond its nominal upper bound of pi/4.
 TEST(SinCosfTest, SDCOMP_26094) {
   for (uint32_t v : sdcomp26094Values) {
-    float x = as_float(v);
+    float x = valueFromBits(v);
     float sin, cos;
     __llvm_libc::sincosf(x, &sin, &cos);
     EXPECT_MPFR_MATCH(mpfr::OP_Cos, x, cos, tolerance);
index c0ce075..e0821c6 100644 (file)
@@ -6,22 +6,27 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "include/errno.h"
 #include "include/math.h"
 #include "src/errno/llvmlibc_errno.h"
-#include "src/math/math_utils.h"
 #include "src/math/sinf.h"
-#include "test/src/math/float.h"
 #include "test/src/math/sdcomp26094.h"
 #include "utils/CPP/Array.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 #include "utils/UnitTest/Test.h"
 
 #include <stdint.h>
 
-using __llvm_libc::as_float;
-using __llvm_libc::as_uint32_bits;
+using __llvm_libc::fputil::isNegativeQuietNaN;
+using __llvm_libc::fputil::isQuietNaN;
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
 
-using __llvm_libc::testing::FloatBits;
 using __llvm_libc::testing::sdcomp26094Values;
 
 namespace mpfr = __llvm_libc::testing::mpfr;
@@ -34,38 +39,37 @@ static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 12,
 TEST(SinfTest, SpecialNumbers) {
   llvmlibc_errno = 0;
 
-  EXPECT_TRUE(FloatBits::isQNan(
-      as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::QNan)))));
+  EXPECT_TRUE(
+      isQuietNaN(__llvm_libc::sinf(valueFromBits(BitPatterns::aQuietNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_TRUE(FloatBits::isNegQNan(
-      as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegQNan)))));
+  EXPECT_TRUE(isNegativeQuietNaN(
+      __llvm_libc::sinf(valueFromBits(BitPatterns::aNegativeQuietNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_TRUE(FloatBits::isQNan(
-      as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::SNan)))));
+  EXPECT_TRUE(isQuietNaN(
+      __llvm_libc::sinf(valueFromBits(BitPatterns::aSignallingNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_TRUE(FloatBits::isNegQNan(
-      as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegSNan)))));
+  EXPECT_TRUE(isNegativeQuietNaN(
+      __llvm_libc::sinf(valueFromBits(BitPatterns::aNegativeSignallingNaN))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_EQ(FloatBits::Zero,
-            as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::Zero))));
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::sinf(valueFromBits(BitPatterns::zero))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
-  EXPECT_EQ(FloatBits::NegZero,
-            as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegZero))));
+  EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::sinf(
+                                      valueFromBits(BitPatterns::negZero))));
   EXPECT_EQ(llvmlibc_errno, 0);
 
   llvmlibc_errno = 0;
-  EXPECT_TRUE(FloatBits::isQNan(
-      as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::Inf)))));
+  EXPECT_TRUE(isQuietNaN(__llvm_libc::sinf(valueFromBits(BitPatterns::inf))));
   EXPECT_EQ(llvmlibc_errno, EDOM);
 
   llvmlibc_errno = 0;
-  EXPECT_TRUE(FloatBits::isNegQNan(
-      as_uint32_bits(__llvm_libc::sinf(as_float(FloatBits::NegInf)))));
+  EXPECT_TRUE(isNegativeQuietNaN(
+      __llvm_libc::sinf(valueFromBits(BitPatterns::negInf))));
   EXPECT_EQ(llvmlibc_errno, EDOM);
 }
 
@@ -73,7 +77,7 @@ TEST(SinfTest, InFloatRange) {
   constexpr uint32_t count = 1000000;
   constexpr uint32_t step = UINT32_MAX / count;
   for (uint32_t i = 0, v = 0; i <= count; ++i, v += step) {
-    float x = as_float(v);
+    float x = valueFromBits(v);
     if (isnan(x) || isinf(x))
       continue;
     ASSERT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
@@ -81,30 +85,30 @@ TEST(SinfTest, InFloatRange) {
 }
 
 TEST(SinfTest, SpecificBitPatterns) {
-  float x = as_float(0xc70d39a1);
+  float x = valueFromBits(0xc70d39a1);
   EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
 }
 
 // For small values, sin(x) is x.
 TEST(SinfTest, SmallValues) {
   uint32_t bits = 0x17800000;
-  float x = as_float(bits);
+  float x = valueFromBits(bits);
   float result = __llvm_libc::sinf(x);
   EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result, tolerance);
-  EXPECT_EQ(bits, as_uint32_bits(result));
+  EXPECT_EQ(bits, valueAsBits(result));
 
   bits = 0x00400000;
-  x = as_float(bits);
+  x = valueFromBits(bits);
   result = __llvm_libc::sinf(x);
   EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, result, tolerance);
-  EXPECT_EQ(bits, as_uint32_bits(result));
+  EXPECT_EQ(bits, valueAsBits(result));
 }
 
 // SDCOMP-26094: check sinf in the cases for which the range reducer
 // returns values furthest beyond its nominal upper bound of pi/4.
 TEST(SinfTest, SDCOMP_26094) {
   for (uint32_t v : sdcomp26094Values) {
-    float x = as_float(v);
+    float x = valueFromBits(v);
     EXPECT_MPFR_MATCH(mpfr::OP_Sin, x, __llvm_libc::sinf(x), tolerance);
   }
 }
index 1e85d05..8a7ee53 100644 (file)
@@ -1,4 +1,5 @@
 add_subdirectory(CPP)
+add_subdirectory(FPUtil)
 add_subdirectory(HdrGen)
 add_subdirectory(MPFRWrapper)
 add_subdirectory(testutils)
diff --git a/libc/utils/FPUtil/BitPatterns.h b/libc/utils/FPUtil/BitPatterns.h
new file mode 100644 (file)
index 0000000..35c58a4
--- /dev/null
@@ -0,0 +1,62 @@
+//===-- Bit patterns of common floating point numbers -----------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_UTILS_FPUTIL_BIT_PATTERNS_H
+#define LLVM_LIBC_UTILS_FPUTIL_BIT_PATTERNS_H
+
+#include "FloatProperties.h"
+
+namespace __llvm_libc {
+namespace fputil {
+
+template <typename T> struct BitPatterns {};
+
+template <> struct BitPatterns<float> {
+  using BitsType = FloatProperties<float>::BitsType;
+
+  static constexpr BitsType inf = 0x7f800000U;
+  static constexpr BitsType negInf = 0xff800000U;
+
+  static constexpr BitsType zero = 0x0;
+  static constexpr BitsType negZero = 0x80000000U;
+
+  static constexpr BitsType one = 0x3f800000U;
+
+  // Examples of quiet NAN.
+  static constexpr BitsType aQuietNaN = 0x7fc00000U;
+  static constexpr BitsType aNegativeQuietNaN = 0xffc00000U;
+
+  // Examples of signalling NAN.
+  static constexpr BitsType aSignallingNaN = 0x7f800001U;
+  static constexpr BitsType aNegativeSignallingNaN = 0xff800001U;
+};
+
+template <> struct BitPatterns<double> {
+  using BitsType = FloatProperties<double>::BitsType;
+
+  static constexpr BitsType inf = 0x7ff0000000000000ULL;
+  static constexpr BitsType negInf = 0xfff0000000000000ULL;
+
+  static constexpr BitsType zero = 0x0ULL;
+  static constexpr BitsType negZero = 0x8000000000000000ULL;
+
+  static constexpr BitsType one = 0x3FF0000000000000ULL;
+
+  // Examples of quiet NAN.
+  static constexpr BitsType aQuietNaN = 0x7ff8000000000000ULL;
+  static constexpr BitsType aNegativeQuietNaN = 0xfff8000000000000ULL;
+
+  // Examples of signalling NAN.
+  static constexpr BitsType aSignallingNaN = 0x7ff0000000000001ULL;
+  static constexpr BitsType aNegativeSignallingNaN = 0xfff0000000000001ULL;
+};
+
+} // namespace fputil
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_UTILS_FPUTIL_BIT_PATTERNS_H
diff --git a/libc/utils/FPUtil/CMakeLists.txt b/libc/utils/FPUtil/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b50ede1
--- /dev/null
@@ -0,0 +1,9 @@
+add_header_library(
+  fputil
+  HDRS
+    BitPatterns.h
+    FloatOperations.h
+    FloatProperties.h
+  DEPS
+    libc.utils.CPP.standalone_cpp
+)
diff --git a/libc/utils/FPUtil/FloatOperations.h b/libc/utils/FPUtil/FloatOperations.h
new file mode 100644 (file)
index 0000000..902929e
--- /dev/null
@@ -0,0 +1,102 @@
+//===-- Common operations on floating point numbers -------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_UTILS_FPUTIL_FLOAT_OPERATIONS_H
+#define LLVM_LIBC_UTILS_FPUTIL_FLOAT_OPERATIONS_H
+
+#include "BitPatterns.h"
+#include "FloatProperties.h"
+
+#include "utils/CPP/TypeTraits.h"
+
+namespace __llvm_libc {
+namespace fputil {
+
+// Return the bits of a float value.
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline typename FloatProperties<T>::BitsType valueAsBits(T x) {
+  using BitsType = typename FloatProperties<T>::BitsType;
+  return *reinterpret_cast<BitsType *>(&x);
+}
+
+// Return the float value from bits.
+template <typename BitsType,
+          cpp::EnableIfType<
+              cpp::IsFloatingPointType<FloatTypeT<BitsType>>::Value, int> = 0>
+static inline FloatTypeT<BitsType> valueFromBits(BitsType bits) {
+  return *reinterpret_cast<FloatTypeT<BitsType> *>(&bits);
+}
+
+// Return the bits of abs(x).
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline typename FloatProperties<T>::BitsType absBits(T x) {
+  return valueAsBits(x) & (~FloatProperties<T>::signMask);
+}
+
+// Return the zero adjusted exponent value of x.
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+int getExponent(T x) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename Properties::BitsType;
+  BitsType bits = absBits(x);
+  int e = (bits >> Properties::mantissaWidth); // Shift out the mantissa.
+  e -= Properties::exponentOffset;             // Zero adjust.
+  return e;
+}
+
+// Return true if x is infinity (positive or negative.)
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline bool isInf(T x) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename FloatProperties<T>::BitsType;
+  BitsType bits = valueAsBits(x);
+  return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
+         ((bits & Properties::mantissaMask) == 0);
+}
+
+// Return true if x is a NAN (quiet or signalling.)
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline bool isNaN(T x) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename FloatProperties<T>::BitsType;
+  BitsType bits = valueAsBits(x);
+  return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
+         ((bits & Properties::mantissaMask) != 0);
+}
+
+// Return true if x is a quiet NAN.
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline bool isQuietNaN(T x) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename FloatProperties<T>::BitsType;
+  BitsType bits = valueAsBits(x);
+  return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) &&
+         ((bits & Properties::quietNaNMask) != 0);
+}
+
+// Return true if x is a quiet NAN with sign bit set.
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline bool isNegativeQuietNaN(T x) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename FloatProperties<T>::BitsType;
+  BitsType bits = valueAsBits(x);
+  return ((bits & BitPatterns<T>::negInf) == BitPatterns<T>::negInf) &&
+         ((bits & Properties::quietNaNMask) != 0);
+}
+
+} // namespace fputil
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_UTILS_FPUTIL_FLOAT_OPERATIONS_H
diff --git a/libc/utils/FPUtil/FloatProperties.h b/libc/utils/FPUtil/FloatProperties.h
new file mode 100644 (file)
index 0000000..a9584c7
--- /dev/null
@@ -0,0 +1,72 @@
+//===-- Properties of floating point numbers --------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_UTILS_FPUTIL_FLOAT_PROPERTIES_H
+#define LLVM_LIBC_UTILS_FPUTIL_FLOAT_PROPERTIES_H
+
+#include <stdint.h>
+
+namespace __llvm_libc {
+namespace fputil {
+
+template <typename T> struct FloatProperties {};
+
+template <> struct FloatProperties<float> {
+  typedef uint32_t BitsType;
+  static_assert(sizeof(BitsType) == sizeof(float),
+                "Unexpected size of 'float' type.");
+
+  static constexpr uint32_t mantissaWidth = 23;
+  static constexpr BitsType mantissaMask = 0x007fffffU;
+  static constexpr BitsType signMask = 0x80000000U;
+  static constexpr uint32_t exponentOffset = 127;
+
+  // If a number x is a NAN, then it is a quiet NAN if:
+  //   QuietNaNMask & bits(x) != 0
+  // Else, it is a signalling NAN.
+  static constexpr BitsType quietNaNMask = 0x00400000U;
+};
+
+template <> struct FloatProperties<double> {
+  typedef uint64_t BitsType;
+  static_assert(sizeof(BitsType) == sizeof(double),
+                "Unexpected size of 'double' type.");
+
+  static constexpr uint32_t mantissaWidth = 52;
+  static constexpr BitsType mantissaMask = 0x000fffffffffffffU;
+  static constexpr BitsType signMask = 0x8000000000000000ULL;
+  static constexpr uint32_t exponentOffset = 1023;
+
+  // If a number x is a NAN, then it is a quiet NAN if:
+  //   QuietNaNMask & bits(x) != 0
+  // Else, it is a signalling NAN.
+  static constexpr BitsType quietNaNMask = 0x0008000000000000ULL;
+};
+
+// Define the float type corresponding to the BitsType.
+template <typename BitsType> struct FloatType;
+
+template <> struct FloatType<uint32_t> {
+  static_assert(sizeof(uint32_t) == sizeof(float),
+                "Unexpected size of 'float' type.");
+  typedef float Type;
+};
+
+template <> struct FloatType<uint64_t> {
+  static_assert(sizeof(uint64_t) == sizeof(double),
+                "Unexpected size of 'double' type.");
+  typedef double Type;
+};
+
+template <typename BitsType>
+using FloatTypeT = typename FloatType<BitsType>::Type;
+
+} // namespace fputil
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_UTILS_FPUTIL_FLOAT_PROPERTIES_H
index 218d5af..6a3c24e 100644 (file)
@@ -12,7 +12,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
     MPFRUtils.cpp
     MPFRUtils.h
   )
-  add_dependencies(libcMPFRWrapper libc.utils.CPP.standalone_cpp LibcUnitTest LLVMSupport)
+  add_dependencies(libcMPFRWrapper libc.utils.CPP.standalone_cpp libc.utils.FPUtil.fputil LibcUnitTest LLVMSupport)
   target_link_libraries(libcMPFRWrapper -lmpfr -lgmp LibcUnitTest LLVMSupport)
 else()
   message(WARNING "Math tests using MPFR will be skipped.")
index 980557a..74bb07a 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "MPFRUtils.h"
 
+#include "utils/FPUtil/FloatOperations.h"
+
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 
@@ -19,44 +21,6 @@ namespace __llvm_libc {
 namespace testing {
 namespace mpfr {
 
-template <typename T> struct FloatProperties {};
-
-template <> struct FloatProperties<float> {
-  typedef uint32_t BitsType;
-  static_assert(sizeof(BitsType) == sizeof(float),
-                "Unexpected size of 'float' type.");
-
-  static constexpr uint32_t mantissaWidth = 23;
-  static constexpr BitsType signMask = 0x7FFFFFFFU;
-  static constexpr uint32_t exponentOffset = 127;
-};
-
-template <> struct FloatProperties<double> {
-  typedef uint64_t BitsType;
-  static_assert(sizeof(BitsType) == sizeof(double),
-                "Unexpected size of 'double' type.");
-
-  static constexpr uint32_t mantissaWidth = 52;
-  static constexpr BitsType signMask = 0x7FFFFFFFFFFFFFFFULL;
-  static constexpr uint32_t exponentOffset = 1023;
-};
-
-template <typename T> typename FloatProperties<T>::BitsType getBits(T x) {
-  using BitsType = typename FloatProperties<T>::BitsType;
-  return *reinterpret_cast<BitsType *>(&x);
-}
-
-// Returns the zero adjusted exponent value of abs(x).
-template <typename T> int getExponent(T x) {
-  using Properties = FloatProperties<T>;
-  using BitsType = typename Properties::BitsType;
-  BitsType bits = *reinterpret_cast<BitsType *>(&x);
-  bits &= Properties::signMask;                // Zero the sign bit.
-  int e = (bits >> Properties::mantissaWidth); // Shift out the mantissa.
-  e -= Properties::exponentOffset;             // Zero adjust.
-  return e;
-}
-
 class MPFRNumber {
   // A precision value which allows sufficiently large additional
   // precision even compared to double precision floating point values.
@@ -94,7 +58,7 @@ public:
   template <typename XType> MPFRNumber(XType x, const Tolerance &t) {
     mpfr_init2(value, mpfrPrecision);
     mpfr_set_zero(value, 1); // Set to positive zero.
-    MPFRNumber xExponent(getExponent(x));
+    MPFRNumber xExponent(fputil::getExponent(x));
     // E = 2^E
     mpfr_exp2(xExponent.value, xExponent.value, MPFR_RNDN);
     uint32_t bitMask = 1 << (t.width - 1);
@@ -170,15 +134,18 @@ namespace internal {
 
 template <typename T>
 void MPFRMatcher<T>::explainError(testutils::StreamWrapper &OS) {
+  using fputil::valueAsBits;
+
   MPFRNumber mpfrResult(operation, input);
   MPFRNumber mpfrInput(input);
   MPFRNumber mpfrMatchValue(matchValue);
   MPFRNumber mpfrToleranceValue(matchValue, tolerance);
   OS << "Match value not within tolerance value of MPFR result:\n"
      << "  Input decimal: " << mpfrInput.str() << '\n'
-     << "     Input bits: 0x" << llvm::utohexstr(getBits(input)) << '\n'
+     << "     Input bits: 0x" << llvm::utohexstr(valueAsBits(input)) << '\n'
      << "  Match decimal: " << mpfrMatchValue.str() << '\n'
-     << "     Match bits: 0x" << llvm::utohexstr(getBits(matchValue)) << '\n'
+     << "     Match bits: 0x" << llvm::utohexstr(valueAsBits(matchValue))
+     << '\n'
      << "    MPFR result: " << mpfrResult.str() << '\n'
      << "Tolerance value: " << mpfrToleranceValue.str() << '\n';
 }