[libc-commits] [libc] 4be1c11 - [libc] Add implementations of round and roundf.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Tue Jun 9 23:01:50 PDT 2020


Author: Siva Chandra Reddy
Date: 2020-06-09T23:01:20-07:00
New Revision: 4be1c116ad8602d96d6d212a661425fbf05eb58f

URL: https://github.com/llvm/llvm-project/commit/4be1c116ad8602d96d6d212a661425fbf05eb58f
DIFF: https://github.com/llvm/llvm-project/commit/4be1c116ad8602d96d6d212a661425fbf05eb58f.diff

LOG: [libc] Add implementations of round and roundf.

Reviewers: asteinhauser

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

Added: 
    libc/src/math/roundf.cpp
    libc/src/math/roundf.h
    libc/test/src/math/round_test.cpp
    libc/test/src/math/roundf_test.cpp

Modified: 
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/lib/CMakeLists.txt
    libc/spec/stdc.td
    libc/src/math/CMakeLists.txt
    libc/src/math/round.cpp
    libc/test/src/math/CMakeLists.txt
    libc/utils/FPUtil/FloatOperations.h

Removed: 
    libc/src/math/round_redirector.cpp


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 5ac6b9db01e9..1d20c5fd12b0 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -160,6 +160,7 @@ def MathAPI : PublicAPI<"math.h"> {
    "expf",
    "exp2f",
    "round",
+   "roundf",
    "sincosf",
    "sinf",
    "trunc",

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 47329d281a2b..a6bc492ac67e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -55,6 +55,7 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.floor
     libc.src.math.floorf
     libc.src.math.round
+    libc.src.math.roundf
     libc.src.math.sincosf
     libc.src.math.sinf
     libc.src.math.trunc

diff  --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index 16340531e9d1..b2b872c6d179 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -9,9 +9,3 @@ add_entrypoint_library(
   DEPENDS
   ${TARGET_LIBM_ENTRYPOINTS}
 )
-
-add_redirector_library(
-  llvmlibc_redirectors
-  DEPENDS
-    round_redirector
-)

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 077dc2127355..a9bdfbd710ae 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -203,6 +203,7 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"exp2f", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
 
           FunctionSpec<"round", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
+          FunctionSpec<"roundf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
 
           FunctionSpec<"trunc", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
           FunctionSpec<"truncf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,

diff  --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index a3b1b4f6ec01..701ee6eb0448 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -20,21 +20,6 @@ add_object_library(
     .math_utils
 )
 
-add_entrypoint_object(
-  round
-  REDIRECTED
-  SRCS
-    round.cpp
-  HDRS
-    round.h
-)
-
-add_redirector_object(
-  round_redirector
-  SRC
-    round_redirector.cpp
-)
-
 add_entrypoint_object(
   cosf
   SRCS
@@ -151,6 +136,26 @@ add_entrypoint_object(
     libc.utils.FPUtil.fputil
 )
 
+add_entrypoint_object(
+  round
+  SRCS
+    round.cpp
+  HDRS
+    round.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+  roundf
+  SRCS
+    roundf.cpp
+  HDRS
+    roundf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+)
+
 add_object_library(
   exp_utils
   HDRS

diff  --git a/libc/src/math/round.cpp b/libc/src/math/round.cpp
index d8d5d29a7b23..0a6e54871005 100644
--- a/libc/src/math/round.cpp
+++ b/libc/src/math/round.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of round -------------------------------------------===//
+//===-- Implementation of round function ----------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,16 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/math/round.h"
-
 #include "src/__support/common.h"
+#include "utils/FPUtil/FloatOperations.h"
 
 namespace __llvm_libc {
 
-double __round_redirector(double x);
-
-double LLVM_LIBC_ENTRYPOINT(round)(double x) {
-  return __round_redirector(x);
-}
+double LLVM_LIBC_ENTRYPOINT(round)(double x) { return fputil::round(x); }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/math/round_redirector.cpp b/libc/src/math/roundf.cpp
similarity index 60%
rename from libc/src/math/round_redirector.cpp
rename to libc/src/math/roundf.cpp
index 67cd8f7c585f..bdfcd0a3499c 100644
--- a/libc/src/math/round_redirector.cpp
+++ b/libc/src/math/roundf.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of round redirector --------------------------------===//
+//===-- Implementation of roundf function ---------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,14 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-// Include okay for this redirector.
-// NOLINTNEXTLINE(llvmlibc-restrict-system-libc-headers)
-#include <math.h>
+#include "src/__support/common.h"
+#include "utils/FPUtil/FloatOperations.h"
 
 namespace __llvm_libc {
 
-double __round_redirector(double x) {
-  return ::round(x);
-}
+float LLVM_LIBC_ENTRYPOINT(roundf)(float x) { return fputil::round(x); }
 
 } // namespace __llvm_libc

diff  --git a/libc/src/math/roundf.h b/libc/src/math/roundf.h
new file mode 100644
index 000000000000..6bab35adf781
--- /dev/null
+++ b/libc/src/math/roundf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for roundf ------------------------*- 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_SRC_MATH_ROUNDF_H
+#define LLVM_LIBC_SRC_MATH_ROUNDF_H
+
+namespace __llvm_libc {
+
+float roundf(float x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_ROUNDF_H

diff  --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 3568b20a537c..c381ea8a2e81 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -175,6 +175,32 @@ add_math_unittest(
     libc.utils.FPUtil.fputil
 )
 
+add_math_unittest(
+  round_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    round_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.round
+    libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+  roundf_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    roundf_test.cpp
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundf
+    libc.utils.FPUtil.fputil
+)
+
 add_math_unittest(
   expf_test
   NEED_MPFR

diff  --git a/libc/test/src/math/round_test.cpp b/libc/test/src/math/round_test.cpp
new file mode 100644
index 000000000000..9816b1feea7c
--- /dev/null
+++ b/libc/test/src/math/round_test.cpp
@@ -0,0 +1,84 @@
+//===-- Unittests for round -----------------------------------------------===//
+//
+// 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 "src/math/round.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"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
+using Properties = __llvm_libc::fputil::FloatProperties<double>;
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+// Zero tolerance; As in, exact match with MPFR result.
+static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
+                                           0};
+
+TEST(RoundTest, SpecialNumbers) {
+  EXPECT_EQ(
+      BitPatterns::aQuietNaN,
+      valueAsBits(__llvm_libc::round(valueFromBits(BitPatterns::aQuietNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::round(
+                valueFromBits(BitPatterns::aNegativeQuietNaN))));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::round(
+                valueFromBits(BitPatterns::aSignallingNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+            valueAsBits(__llvm_libc::round(
+                valueFromBits(BitPatterns::aNegativeSignallingNaN))));
+
+  EXPECT_EQ(BitPatterns::inf,
+            valueAsBits(__llvm_libc::round(valueFromBits(BitPatterns::inf))));
+  EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::round(
+                                     valueFromBits(BitPatterns::negInf))));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::round(valueFromBits(BitPatterns::zero))));
+  EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::round(
+                                      valueFromBits(BitPatterns::negZero))));
+}
+
+TEST(RoundTest, RoundedNumbers) {
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::round(1.0)));
+  EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::round(-1.0)));
+  EXPECT_EQ(valueAsBits(10.0), valueAsBits(__llvm_libc::round(10.0)));
+  EXPECT_EQ(valueAsBits(-10.0), valueAsBits(__llvm_libc::round(-10.0)));
+  EXPECT_EQ(valueAsBits(12345.0), valueAsBits(__llvm_libc::round(12345.0)));
+  EXPECT_EQ(valueAsBits(-12345.0), valueAsBits(__llvm_libc::round(-12345.0)));
+}
+
+TEST(RoundTest, CloseToZeroNumbers) {
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::round(0.5)));
+  EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::round(-0.5)));
+  EXPECT_EQ(valueAsBits(0.0), valueAsBits(__llvm_libc::round(0.115)));
+  EXPECT_EQ(valueAsBits(-0.0), valueAsBits(__llvm_libc::round(-0.115)));
+  EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::round(0.715)));
+  EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::round(-0.715)));
+}
+
+TEST(RoundTest, InDoubleRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 1000000;
+  constexpr BitsType step = UINT64_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    double x = valueFromBits(v);
+    if (isnan(x) || isinf(x))
+      continue;
+    ASSERT_MPFR_MATCH(mpfr::Operation::Round, x, __llvm_libc::round(x),
+                      tolerance);
+  }
+}

diff  --git a/libc/test/src/math/roundf_test.cpp b/libc/test/src/math/roundf_test.cpp
new file mode 100644
index 000000000000..88c746b126ef
--- /dev/null
+++ b/libc/test/src/math/roundf_test.cpp
@@ -0,0 +1,85 @@
+//===-- Unittests for roundf ----------------------------------------------===//
+//
+// 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 "src/math/roundf.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"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
+using Properties = __llvm_libc::fputil::FloatProperties<float>;
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+// Zero tolerance; As in, exact match with MPFR result.
+static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
+                                           0};
+
+TEST(RoundfTest, SpecialNumbers) {
+  EXPECT_EQ(
+      BitPatterns::aQuietNaN,
+      valueAsBits(__llvm_libc::roundf(valueFromBits(BitPatterns::aQuietNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+            valueAsBits(__llvm_libc::roundf(
+                valueFromBits(BitPatterns::aNegativeQuietNaN))));
+
+  EXPECT_EQ(BitPatterns::aSignallingNaN,
+            valueAsBits(__llvm_libc::roundf(
+                valueFromBits(BitPatterns::aSignallingNaN))));
+  EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+            valueAsBits(__llvm_libc::roundf(
+                valueFromBits(BitPatterns::aNegativeSignallingNaN))));
+
+  EXPECT_EQ(BitPatterns::inf,
+            valueAsBits(__llvm_libc::roundf(valueFromBits(BitPatterns::inf))));
+  EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::roundf(
+                                     valueFromBits(BitPatterns::negInf))));
+
+  EXPECT_EQ(BitPatterns::zero,
+            valueAsBits(__llvm_libc::roundf(valueFromBits(BitPatterns::zero))));
+  EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::roundf(
+                                      valueFromBits(BitPatterns::negZero))));
+}
+
+TEST(RoundfTest, RoundedNumbers) {
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::roundf(1.0f)));
+  EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::roundf(-1.0f)));
+  EXPECT_EQ(valueAsBits(10.0f), valueAsBits(__llvm_libc::roundf(10.0f)));
+  EXPECT_EQ(valueAsBits(-10.0f), valueAsBits(__llvm_libc::roundf(-10.0f)));
+  EXPECT_EQ(valueAsBits(12345.0f), valueAsBits(__llvm_libc::roundf(12345.0f)));
+  EXPECT_EQ(valueAsBits(-12345.0f),
+            valueAsBits(__llvm_libc::roundf(-12345.0f)));
+}
+
+TEST(RoundTest, CloseToZeroNumbers) {
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::roundf(0.5f)));
+  EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::roundf(-0.5f)));
+  EXPECT_EQ(valueAsBits(0.0f), valueAsBits(__llvm_libc::roundf(0.115f)));
+  EXPECT_EQ(valueAsBits(-0.0f), valueAsBits(__llvm_libc::roundf(-0.115f)));
+  EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::roundf(0.715f)));
+  EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::roundf(-0.715f)));
+}
+
+TEST(RoundfTest, InFloatRange) {
+  using BitsType = Properties::BitsType;
+  constexpr BitsType count = 1000000;
+  constexpr BitsType step = UINT32_MAX / count;
+  for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+    double x = valueFromBits(v);
+    if (isnan(x) || isinf(x))
+      continue;
+    ASSERT_MPFR_MATCH(mpfr::Operation::Round, x, __llvm_libc::roundf(x),
+                      tolerance);
+  }
+}

diff  --git a/libc/utils/FPUtil/FloatOperations.h b/libc/utils/FPUtil/FloatOperations.h
index a378903c38b4..d841237176a5 100644
--- a/libc/utils/FPUtil/FloatOperations.h
+++ b/libc/utils/FPUtil/FloatOperations.h
@@ -214,6 +214,62 @@ static inline T floor(T x) {
   }
 }
 
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T round(T x) {
+  using Properties = FloatProperties<T>;
+  using BitsType = typename FloatProperties<T>::BitsType;
+
+  BitsType bits = valueAsBits(x);
+
+  // If x is infinity, NaN or zero, return it.
+  if (bitsAreInfOrNaN(bits) || bitsAreZero(bits))
+    return x;
+
+  bool isNeg = bits & Properties::signMask;
+  int exponent = getExponentFromBits(bits);
+
+  // If the exponent is greater than the most negative mantissa
+  // exponent, then x is already an integer.
+  if (exponent >= static_cast<int>(Properties::mantissaWidth))
+    return x;
+
+  if (exponent == -1) {
+    // Absolute value of x is greater than equal to 0.5 but less than 1.
+    if (isNeg)
+      return T(-1.0);
+    else
+      return T(1.0);
+  }
+
+  if (exponent <= -2) {
+    // Absolute value of x is less than 0.5.
+    if (isNeg)
+      return T(-0.0);
+    else
+      return T(0.0);
+  }
+
+  uint32_t trimSize = Properties::mantissaWidth - exponent;
+  // If x is already an integer, return it.
+  if ((bits << (Properties::bitWidth - trimSize)) == 0)
+    return x;
+
+  BitsType truncBits = (bits >> trimSize) << trimSize;
+  T truncValue = valueFromBits(truncBits);
+
+  if ((bits & (BitsType(1) << (trimSize - 1))) == 0) {
+    // Franctional part is less than 0.5 so round value is the
+    // same as the trunc value.
+    return truncValue;
+  }
+
+  if (isNeg)
+    return truncValue - T(1.0);
+  else
+    return truncValue + T(1.0);
+}
+
 } // namespace fputil
 } // namespace __llvm_libc
 


        


More information about the libc-commits mailing list