[libc-commits] [libc] 7aeb380 - [libc] Add implementations of lround[f|l] and llround[f|l].
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Fri Dec 11 11:12:51 PST 2020
Author: Siva Chandra Reddy
Date: 2020-12-11T11:12:40-08:00
New Revision: 7aeb3804c46cc6c8f291415ca09ae34021301eb8
URL: https://github.com/llvm/llvm-project/commit/7aeb3804c46cc6c8f291415ca09ae34021301eb8
DIFF: https://github.com/llvm/llvm-project/commit/7aeb3804c46cc6c8f291415ca09ae34021301eb8.diff
LOG: [libc] Add implementations of lround[f|l] and llround[f|l].
A new function to MPFRWrapper has been added, which is used to set up
the unit tests.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D93007
Added:
libc/src/math/llround.cpp
libc/src/math/llround.h
libc/src/math/llroundf.cpp
libc/src/math/llroundf.h
libc/src/math/llroundl.cpp
libc/src/math/llroundl.h
libc/src/math/lround.cpp
libc/src/math/lround.h
libc/src/math/lroundf.cpp
libc/src/math/lroundf.h
libc/src/math/lroundl.cpp
libc/src/math/lroundl.h
libc/test/src/math/RoundToIntegerTest.h
libc/test/src/math/llround_test.cpp
libc/test/src/math/llroundf_test.cpp
libc/test/src/math/llroundl_test.cpp
libc/test/src/math/lround_test.cpp
libc/test/src/math/lroundf_test.cpp
libc/test/src/math/lroundl_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/spec/spec.td
libc/spec/stdc.td
libc/src/math/CMakeLists.txt
libc/test/src/math/CMakeLists.txt
libc/utils/FPUtil/CMakeLists.txt
libc/utils/FPUtil/NearestIntegerOperations.h
libc/utils/MPFRWrapper/MPFRUtils.cpp
libc/utils/MPFRWrapper/MPFRUtils.h
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 4cae553ac6d4..fce28231f319 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -122,9 +122,15 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.ldexp
libc.src.math.ldexpf
libc.src.math.ldexpl
+ libc.src.math.llround
+ libc.src.math.llroundf
+ libc.src.math.llroundl
libc.src.math.logb
libc.src.math.logbf
libc.src.math.logbl
+ libc.src.math.lround
+ libc.src.math.lroundf
+ libc.src.math.lroundl
libc.src.math.modf
libc.src.math.modff
libc.src.math.modfl
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index 9a31d85c148c..c78c0f053e06 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -39,11 +39,11 @@ class RestrictedPtrType<Type type> : Type {
def VarArgType : Type {}
def VoidType : NamedType<"void">;
def IntType : NamedType<"int">;
+def LongType : NamedType<"long">;
+def LongLongType : NamedType<"long long">;
def FloatType : NamedType<"float">;
def DoubleType : NamedType<"double">;
def LongDoubleType : NamedType<"long double">;
-def LongLongType : NamedType<"long long">;
-def LongType : NamedType<"long">;
def CharType : NamedType<"char">;
// Common types
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 051e0a89eb27..aca9a1020b1e 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -363,6 +363,14 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"roundf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"roundl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
+ FunctionSpec<"lround", RetValSpec<LongType>, [ArgSpec<DoubleType>]>,
+ FunctionSpec<"lroundf", RetValSpec<LongType>, [ArgSpec<FloatType>]>,
+ FunctionSpec<"lroundl", RetValSpec<LongType>, [ArgSpec<LongDoubleType>]>,
+
+ FunctionSpec<"llround", RetValSpec<LongLongType>, [ArgSpec<DoubleType>]>,
+ FunctionSpec<"llroundf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
+ FunctionSpec<"llroundl", RetValSpec<LongLongType>, [ArgSpec<LongDoubleType>]>,
+
FunctionSpec<"sqrt", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"sqrtf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"sqrtl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 8201d737ddb1..c4de1b1eae86 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -236,6 +236,78 @@ add_entrypoint_object(
-O2
)
+add_entrypoint_object(
+ lround
+ SRCS
+ lround.cpp
+ HDRS
+ lround.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ lroundf
+ SRCS
+ lroundf.cpp
+ HDRS
+ lroundf.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ lroundl
+ SRCS
+ lroundl.cpp
+ HDRS
+ lroundl.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ llround
+ SRCS
+ llround.cpp
+ HDRS
+ llround.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ llroundf
+ SRCS
+ llroundf.cpp
+ HDRS
+ llroundf.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+ COMPILE_OPTIONS
+ -O2
+)
+
+add_entrypoint_object(
+ llroundl
+ SRCS
+ llroundl.cpp
+ HDRS
+ llroundl.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+ COMPILE_OPTIONS
+ -O2
+)
+
add_object_library(
exp_utils
HDRS
diff --git a/libc/src/math/llround.cpp b/libc/src/math/llround.cpp
new file mode 100644
index 000000000000..25f7e91cf129
--- /dev/null
+++ b/libc/src/math/llround.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of llround function --------------------------------===//
+//
+// 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 "src/__support/common.h"
+#include "utils/FPUtil/NearestIntegerOperations.h"
+
+namespace __llvm_libc {
+
+long long LLVM_LIBC_ENTRYPOINT(llround)(double x) {
+ return fputil::roundToSignedInteger<double, long long>(x);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/math/llround.h b/libc/src/math/llround.h
new file mode 100644
index 000000000000..5b2b7fc96df8
--- /dev/null
+++ b/libc/src/math/llround.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for llround -----------------------*- 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_LLROUND_H
+#define LLVM_LIBC_SRC_MATH_LLROUND_H
+
+namespace __llvm_libc {
+
+long long llround(double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LLROUND_H
diff --git a/libc/src/math/llroundf.cpp b/libc/src/math/llroundf.cpp
new file mode 100644
index 000000000000..e0b34710594a
--- /dev/null
+++ b/libc/src/math/llroundf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of llroundf function -------------------------------===//
+//
+// 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 "src/__support/common.h"
+#include "utils/FPUtil/NearestIntegerOperations.h"
+
+namespace __llvm_libc {
+
+long long LLVM_LIBC_ENTRYPOINT(llroundf)(float x) {
+ return fputil::roundToSignedInteger<float, long long>(x);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/math/llroundf.h b/libc/src/math/llroundf.h
new file mode 100644
index 000000000000..65faad1e07a6
--- /dev/null
+++ b/libc/src/math/llroundf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for llroundf ----------------------*- 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_LLROUNDF_H
+#define LLVM_LIBC_SRC_MATH_LLROUNDF_H
+
+namespace __llvm_libc {
+
+long long llroundf(float x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LLROUNDF_H
diff --git a/libc/src/math/llroundl.cpp b/libc/src/math/llroundl.cpp
new file mode 100644
index 000000000000..4df0b8138bf7
--- /dev/null
+++ b/libc/src/math/llroundl.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of llroundl function -------------------------------===//
+//
+// 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 "src/__support/common.h"
+#include "utils/FPUtil/NearestIntegerOperations.h"
+
+namespace __llvm_libc {
+
+long long LLVM_LIBC_ENTRYPOINT(llroundl)(long double x) {
+ return fputil::roundToSignedInteger<long double, long long>(x);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/math/llroundl.h b/libc/src/math/llroundl.h
new file mode 100644
index 000000000000..f859485a730b
--- /dev/null
+++ b/libc/src/math/llroundl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for llroundl ----------------------*- 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_LLROUNDL_H
+#define LLVM_LIBC_SRC_MATH_LLROUNDL_H
+
+namespace __llvm_libc {
+
+long long llroundl(long double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LLROUNDL_H
diff --git a/libc/src/math/lround.cpp b/libc/src/math/lround.cpp
new file mode 100644
index 000000000000..3fb9028f84fa
--- /dev/null
+++ b/libc/src/math/lround.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of lround function ---------------------------------===//
+//
+// 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 "src/__support/common.h"
+#include "utils/FPUtil/NearestIntegerOperations.h"
+
+namespace __llvm_libc {
+
+long LLVM_LIBC_ENTRYPOINT(lround)(double x) {
+ return fputil::roundToSignedInteger<double, long>(x);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/math/lround.h b/libc/src/math/lround.h
new file mode 100644
index 000000000000..8c555e816c8b
--- /dev/null
+++ b/libc/src/math/lround.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for lround ------------------------*- 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_LROUND_H
+#define LLVM_LIBC_SRC_MATH_LROUND_H
+
+namespace __llvm_libc {
+
+long lround(double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LROUND_H
diff --git a/libc/src/math/lroundf.cpp b/libc/src/math/lroundf.cpp
new file mode 100644
index 000000000000..0388bdffcd69
--- /dev/null
+++ b/libc/src/math/lroundf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of lroundf function --------------------------------===//
+//
+// 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 "src/__support/common.h"
+#include "utils/FPUtil/NearestIntegerOperations.h"
+
+namespace __llvm_libc {
+
+long LLVM_LIBC_ENTRYPOINT(lroundf)(float x) {
+ return fputil::roundToSignedInteger<float, long>(x);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/math/lroundf.h b/libc/src/math/lroundf.h
new file mode 100644
index 000000000000..3d318a7a2fab
--- /dev/null
+++ b/libc/src/math/lroundf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for lroundf -----------------------*- 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_LROUNDF_H
+#define LLVM_LIBC_SRC_MATH_LROUNDF_H
+
+namespace __llvm_libc {
+
+long lroundf(float x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LROUNDF_H
diff --git a/libc/src/math/lroundl.cpp b/libc/src/math/lroundl.cpp
new file mode 100644
index 000000000000..27310ae68d68
--- /dev/null
+++ b/libc/src/math/lroundl.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of lroundl function --------------------------------===//
+//
+// 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 "src/__support/common.h"
+#include "utils/FPUtil/NearestIntegerOperations.h"
+
+namespace __llvm_libc {
+
+long LLVM_LIBC_ENTRYPOINT(lroundl)(long double x) {
+ return fputil::roundToSignedInteger<long double, long>(x);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/math/lroundl.h b/libc/src/math/lroundl.h
new file mode 100644
index 000000000000..a8b5aff0fcf3
--- /dev/null
+++ b/libc/src/math/lroundl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for lroundl -----------------------*- 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_LROUNDL_H
+#define LLVM_LIBC_SRC_MATH_LROUNDL_H
+
+namespace __llvm_libc {
+
+long lroundl(long double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LROUNDL_H
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 8635e7aba427..44abc401da44 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -267,6 +267,126 @@ add_fp_unittest(
libc.utils.FPUtil.fputil
)
+add_fp_unittest(
+ lround_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ lround_test.cpp
+ HDRS
+ RoundToIntegerTest.h
+ DEPENDS
+ libc.include.errno
+ libc.include.math
+ libc.src.errno.__errno_location
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.math.lround
+ libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+ lroundf_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ lroundf_test.cpp
+ HDRS
+ RoundToIntegerTest.h
+ DEPENDS
+ libc.include.errno
+ libc.include.math
+ libc.src.errno.__errno_location
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.math.lroundf
+ libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+ lroundl_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ lroundl_test.cpp
+ HDRS
+ RoundToIntegerTest.h
+ DEPENDS
+ libc.include.errno
+ libc.include.math
+ libc.src.errno.__errno_location
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.math.lroundl
+ libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+ llround_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ llround_test.cpp
+ HDRS
+ RoundToIntegerTest.h
+ DEPENDS
+ libc.include.errno
+ libc.include.math
+ libc.src.errno.__errno_location
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.math.llround
+ libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+ llroundf_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ llroundf_test.cpp
+ HDRS
+ RoundToIntegerTest.h
+ DEPENDS
+ libc.include.errno
+ libc.include.math
+ libc.src.errno.__errno_location
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.math.llroundf
+ libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+ llroundl_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ llroundl_test.cpp
+ HDRS
+ RoundToIntegerTest.h
+ DEPENDS
+ libc.include.errno
+ libc.include.math
+ libc.src.errno.__errno_location
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.math.llroundl
+ libc.utils.FPUtil.fputil
+)
+
add_fp_unittest(
expf_test
NEED_MPFR
diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
new file mode 100644
index 000000000000..7c0605ebcadd
--- /dev/null
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -0,0 +1,217 @@
+//===-- Utility class to test
diff erent flavors of [l|ll]round --*- 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_ROUNDTOINTEGERTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
+
+#include "src/errno/llvmlibc_errno.h"
+#include "src/fenv/feclearexcept.h"
+#include "src/fenv/feraiseexcept.h"
+#include "src/fenv/fetestexcept.h"
+#include "utils/CPP/TypeTraits.h"
+#include "utils/FPUtil/FPBits.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+
+#include <math.h>
+#if math_errhandling & MATH_ERRNO
+#include <errno.h>
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+#include "utils/FPUtil/FEnv.h"
+#endif
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+template <typename F, typename I>
+class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
+public:
+ typedef I (*RoundToIntegerFunc)(F);
+
+private:
+ using FPBits = __llvm_libc::fputil::FPBits<F>;
+ using UIntType = typename FPBits::UIntType;
+
+ const F zero = __llvm_libc::fputil::FPBits<F>::zero();
+ const F negZero = __llvm_libc::fputil::FPBits<F>::negZero();
+ const F inf = __llvm_libc::fputil::FPBits<F>::inf();
+ const F negInf = __llvm_libc::fputil::FPBits<F>::negInf();
+ const F nan = __llvm_libc::fputil::FPBits<F>::buildNaN(1);
+ static constexpr I IntegerMin = I(1) << (sizeof(I) * 8 - 1);
+ static constexpr I IntegerMax = -(IntegerMin + 1);
+
+ void testOneInput(RoundToIntegerFunc func, F input, I expected,
+ bool expectError) {
+#if math_errhandling & MATH_ERRNO
+ llvmlibc_errno = 0;
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ __llvm_libc::feclearexcept(FE_ALL_EXCEPT);
+#endif
+
+ ASSERT_EQ(func(input), expected);
+
+ if (expectError) {
+#if math_errhandling & MATH_ERREXCEPT
+ ASSERT_EQ(__llvm_libc::fetestexcept(FE_ALL_EXCEPT), FE_INVALID);
+#endif
+#if math_errhandling & MATH_ERRNO
+ ASSERT_EQ(llvmlibc_errno, EDOM);
+#endif
+ } else {
+#if math_errhandling & MATH_ERREXCEPT
+ ASSERT_EQ(__llvm_libc::fetestexcept(FE_ALL_EXCEPT), 0);
+#endif
+#if math_errhandling & MATH_ERRNO
+ ASSERT_EQ(llvmlibc_errno, 0);
+#endif
+ }
+ }
+
+public:
+ void SetUp() override {
+#if math_errhandling & MATH_ERREXCEPT
+ // We will disable all exceptions so that the test will not
+ // crash with SIGFPE. We can still use fetestexcept to check
+ // if the appropriate flag was raised.
+ __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
+#endif
+ }
+
+ void testInfinityAndNaN(RoundToIntegerFunc func) {
+ testOneInput(func, inf, IntegerMax, true);
+ testOneInput(func, negInf, IntegerMin, true);
+ testOneInput(func, nan, IntegerMax, true);
+ }
+
+ void testRoundNumbers(RoundToIntegerFunc func) {
+ testOneInput(func, zero, I(0), false);
+ testOneInput(func, negZero, I(0), false);
+ testOneInput(func, F(1.0), I(1), false);
+ testOneInput(func, F(-1.0), I(-1), false);
+ testOneInput(func, F(10.0), I(10), false);
+ testOneInput(func, F(-10.0), I(-10), false);
+ testOneInput(func, F(1234.0), I(1234), false);
+ testOneInput(func, F(-1234.0), I(-1234), false);
+
+ // The rest of this this function compares with an equivalent MPFR function
+ // which rounds floating point numbers to long values. There is no MPFR
+ // function to round to long long or wider integer values. So, we will
+ // the remaining tests only if the width of I less than equal to that of
+ // long.
+ if (sizeof(I) > sizeof(long))
+ return;
+
+ constexpr int exponentLimit = sizeof(I) * 8 - 1;
+ // We start with 1.0 so that the implicit bit for x86 long doubles
+ // is set.
+ FPBits bits(F(1.0));
+ bits.exponent = exponentLimit + FPBits::exponentBias;
+ bits.sign = 1;
+ bits.mantissa = 0;
+
+ F x = bits;
+ long mpfrResult;
+ bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
+ ASSERT_FALSE(erangeflag);
+ testOneInput(func, x, mpfrResult, false);
+ }
+
+ void testFractions(RoundToIntegerFunc func) {
+ testOneInput(func, F(0.5), I(1), false);
+ testOneInput(func, F(-0.5), I(-1), false);
+ testOneInput(func, F(0.115), I(0), false);
+ testOneInput(func, F(-0.115), I(0), false);
+ testOneInput(func, F(0.715), I(1), false);
+ testOneInput(func, F(-0.715), I(-1), false);
+ }
+
+ void testIntegerOverflow(RoundToIntegerFunc func) {
+ // This function compares with an equivalent MPFR function which rounds
+ // floating point numbers to long values. There is no MPFR function to
+ // round to long long or wider integer values. So, we will peform the
+ // comparisons in this function only if the width of I less than equal to
+ // that of long.
+ if (sizeof(I) > sizeof(long))
+ return;
+
+ constexpr int exponentLimit = sizeof(I) * 8 - 1;
+ // We start with 1.0 so that the implicit bit for x86 long doubles
+ // is set.
+ FPBits bits(F(1.0));
+ bits.exponent = exponentLimit + FPBits::exponentBias;
+ bits.sign = 1;
+ bits.mantissa = UIntType(0x1)
+ << (__llvm_libc::fputil::MantissaWidth<F>::value - 1);
+
+ F x = bits;
+ long mpfrResult;
+ bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
+ ASSERT_TRUE(erangeflag);
+ testOneInput(func, x, IntegerMin, true);
+ }
+
+ void testSubnormalRange(RoundToIntegerFunc func) {
+ // This function compares with an equivalent MPFR function which rounds
+ // floating point numbers to long values. There is no MPFR function to
+ // round to long long or wider integer values. So, we will peform the
+ // comparisons in this function only if the width of I less than equal to
+ // that of long.
+ if (sizeof(I) > sizeof(long))
+ return;
+
+ constexpr UIntType count = 1000001;
+ constexpr UIntType step =
+ (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
+ for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
+ i += step) {
+ F x = FPBits(i);
+ // All subnormal numbers should round to zero.
+ testOneInput(func, x, 0L, false);
+ }
+ }
+
+ void testNormalRange(RoundToIntegerFunc func) {
+ // This function compares with an equivalent MPFR function which rounds
+ // floating point numbers to long values. There is no MPFR function to
+ // round to long long or wider integer values. So, we will peform the
+ // comparisons in this function only if the width of I less than equal to
+ // that of long.
+ if (sizeof(I) > sizeof(long))
+ return;
+
+ constexpr UIntType count = 1000001;
+ constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
+ for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
+ F x = FPBits(i);
+ // In normal range on x86 platforms, the long double implicit 1 bit can be
+ // zero making the numbers NaN. We will skip them.
+ if (isnan(x)) {
+ continue;
+ }
+
+ long mpfrResult;
+ bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
+ if (erangeflag)
+ testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
+ else
+ testOneInput(func, x, mpfrResult, false);
+ }
+ }
+};
+
+#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \
+ using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I>; \
+ TEST_F(RoundToIntegerTest, InfinityAndNaN) { testInfinityAndNaN(&func); } \
+ TEST_F(RoundToIntegerTest, RoundNumbers) { testRoundNumbers(&func); } \
+ TEST_F(RoundToIntegerTest, Fractions) { testFractions(&func); } \
+ TEST_F(RoundToIntegerTest, IntegerOverflow) { testIntegerOverflow(&func); } \
+ TEST_F(RoundToIntegerTest, SubnormalRange) { testSubnormalRange(&func); } \
+ TEST_F(RoundToIntegerTest, NormalRange) { testNormalRange(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
diff --git a/libc/test/src/math/llround_test.cpp b/libc/test/src/math/llround_test.cpp
new file mode 100644
index 000000000000..e7d5b9006621
--- /dev/null
+++ b/libc/test/src/math/llround_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for llround ---------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "include/math.h"
+#include "src/math/llround.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(double, long long, __llvm_libc::llround)
diff --git a/libc/test/src/math/llroundf_test.cpp b/libc/test/src/math/llroundf_test.cpp
new file mode 100644
index 000000000000..35644a7a6829
--- /dev/null
+++ b/libc/test/src/math/llroundf_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for llroundf --------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "include/math.h"
+#include "src/math/llroundf.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(float, long long, __llvm_libc::llroundf)
diff --git a/libc/test/src/math/llroundl_test.cpp b/libc/test/src/math/llroundl_test.cpp
new file mode 100644
index 000000000000..9f19c3516c32
--- /dev/null
+++ b/libc/test/src/math/llroundl_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for llroundl --------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "include/math.h"
+#include "src/math/llroundl.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(long double, long long, __llvm_libc::llroundl)
diff --git a/libc/test/src/math/lround_test.cpp b/libc/test/src/math/lround_test.cpp
new file mode 100644
index 000000000000..96634f84c1a8
--- /dev/null
+++ b/libc/test/src/math/lround_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for lround ----------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "include/math.h"
+#include "src/math/lround.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(double, long, __llvm_libc::lround)
diff --git a/libc/test/src/math/lroundf_test.cpp b/libc/test/src/math/lroundf_test.cpp
new file mode 100644
index 000000000000..9df427386cb0
--- /dev/null
+++ b/libc/test/src/math/lroundf_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for lroundf ---------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "include/math.h"
+#include "src/math/lroundf.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(float, long, __llvm_libc::lroundf)
diff --git a/libc/test/src/math/lroundl_test.cpp b/libc/test/src/math/lroundl_test.cpp
new file mode 100644
index 000000000000..27429a83ee7b
--- /dev/null
+++ b/libc/test/src/math/lroundl_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for lroundl ---------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "include/math.h"
+#include "src/math/lroundl.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(long double, long, __llvm_libc::lroundl)
diff --git a/libc/utils/FPUtil/CMakeLists.txt b/libc/utils/FPUtil/CMakeLists.txt
index a2d2aa18a953..c54184ec775f 100644
--- a/libc/utils/FPUtil/CMakeLists.txt
+++ b/libc/utils/FPUtil/CMakeLists.txt
@@ -29,6 +29,9 @@ add_header_library(
NormalFloat.h
DEPENDS
libc.include.math
+ libc.include.errno
+ libc.include.fenv
+ libc.src.errno.__errno_location
libc.utils.CPP.standalone_cpp
)
diff --git a/libc/utils/FPUtil/NearestIntegerOperations.h b/libc/utils/FPUtil/NearestIntegerOperations.h
index 1c8ad36274c8..98a2f6f6b139 100644
--- a/libc/utils/FPUtil/NearestIntegerOperations.h
+++ b/libc/utils/FPUtil/NearestIntegerOperations.h
@@ -13,6 +13,15 @@
#include "utils/CPP/TypeTraits.h"
+#include <math.h>
+#if math_errhandling & MATH_ERREXCEPT
+#include "FEnv.h"
+#endif
+#if math_errhandling & MATH_ERRNO
+#include "src/errno/llvmlibc_errno.h"
+#include <errno.h>
+#endif
+
namespace __llvm_libc {
namespace fputil {
@@ -150,6 +159,53 @@ static inline T round(T x) {
}
}
+template <typename F, typename I,
+ cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
+ cpp::IsIntegral<I>::Value,
+ int> = 0>
+static inline I roundToSignedInteger(F x) {
+ constexpr I IntegerMin = (I(1) << (sizeof(I) * 8 - 1));
+ constexpr I IntegerMax = -(IntegerMin + 1);
+
+ using FPBits = FPBits<F>;
+ F roundedValue = round(x);
+ FPBits bits(roundedValue);
+ auto setDomainErrorAndRaiseInvalid = []() {
+#if math_errhandling & MATH_ERRNO
+ llvmlibc_errno = EDOM;
+#endif
+#if math_errhandling & MATH_ERREXCEPT
+ raiseExcept(FE_INVALID);
+#endif
+ };
+
+ if (bits.isInfOrNaN()) {
+ // Result of round is infinity or NaN only if x is infinity
+ // or NaN.
+ setDomainErrorAndRaiseInvalid();
+ return bits.sign ? IntegerMin : IntegerMax;
+ }
+
+ int exponent = bits.getExponent();
+ constexpr int exponentLimit = sizeof(I) * 8 - 1;
+ if (exponent > exponentLimit) {
+ setDomainErrorAndRaiseInvalid();
+ return bits.sign ? IntegerMin : IntegerMax;
+ } else if (exponent == exponentLimit) {
+ if (bits.sign == 0 || bits.mantissa != 0) {
+ setDomainErrorAndRaiseInvalid();
+ return bits.sign ? IntegerMin : IntegerMax;
+ }
+ // If the control reaches here, then it means that the rounded
+ // value is the most negative number for the signed integer type I.
+ }
+
+ // For all other cases, if |roundedValue| can fit in the integer type |I|,
+ // we just return the roundedValue. Implicit conversion will convert the
+ // floating point value to the exact integer value.
+ return roundedValue;
+}
+
} // namespace fputil
} // namespace __llvm_libc
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 56764e9740b0..6f3d216b72c9 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -153,6 +153,16 @@ class MPFRNumber {
return result;
}
+ bool roundToLong(long &result) const {
+ // We first calculate the rounded value. This way, when converting
+ // to long using mpfr_get_si, the rounding direction of MPFR_RNDN
+ // (or any other rounding mode), does not have an influence.
+ MPFRNumber roundedValue = round();
+ mpfr_clear_erangeflag();
+ result = mpfr_get_si(roundedValue.value, MPFR_RNDN);
+ return mpfr_erangeflag_p();
+ }
+
MPFRNumber sin() const {
MPFRNumber result;
mpfr_sin(result.value, value, MPFR_RNDN);
@@ -555,6 +565,15 @@ template bool compareBinaryOperationOneOutput<long double>(
} // namespace internal
+template <typename T> bool RoundToLong(T x, long &result) {
+ MPFRNumber mpfr(x);
+ return mpfr.roundToLong(result);
+}
+
+template bool RoundToLong<float>(float, long &);
+template bool RoundToLong<double>(double, long &);
+template bool RoundToLong<long double>(long double, long &);
+
} // namespace mpfr
} // namespace testing
} // namespace __llvm_libc
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index 6fb9fe5c47b6..cc0dab66947e 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -237,6 +237,8 @@ getMPFRMatcher(InputType input, OutputType outputUnused, double t) {
return internal::MPFRMatcher<op, InputType, OutputType>(input, t);
}
+template <typename T> bool RoundToLong(T x, long &result);
+
} // namespace mpfr
} // namespace testing
} // namespace __llvm_libc
More information about the libc-commits
mailing list