[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