[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