[libc-commits] [libc] ff6fd38 - [libc] Add implementations of rounding functions which depend rounding mode.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Tue Dec 29 22:26:02 PST 2020


Author: Siva Chandra Reddy
Date: 2020-12-29T22:22:02-08:00
New Revision: ff6fd3855244bc90094e7de3f07853a5971cf8ef

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

LOG: [libc] Add implementations of rounding functions which depend rounding mode.

Namely, implementations for rint, rintf, rintl, lrint, lrintf, lrintl,
llrint, llrintf and llrintl have been added.

Reviewed By: lntue

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

Added: 
    libc/src/math/llrint.cpp
    libc/src/math/llrint.h
    libc/src/math/llrintf.cpp
    libc/src/math/llrintf.h
    libc/src/math/llrintl.cpp
    libc/src/math/llrintl.h
    libc/src/math/lrint.cpp
    libc/src/math/lrint.h
    libc/src/math/lrintf.cpp
    libc/src/math/lrintf.h
    libc/src/math/lrintl.cpp
    libc/src/math/lrintl.h
    libc/src/math/rint.cpp
    libc/src/math/rint.h
    libc/src/math/rintf.cpp
    libc/src/math/rintf.h
    libc/src/math/rintl.cpp
    libc/src/math/rintl.h
    libc/test/src/math/RIntTest.h
    libc/test/src/math/llrint_test.cpp
    libc/test/src/math/llrintf_test.cpp
    libc/test/src/math/llrintl_test.cpp
    libc/test/src/math/lrint_test.cpp
    libc/test/src/math/lrintf_test.cpp
    libc/test/src/math/lrintl_test.cpp
    libc/test/src/math/rint_test.cpp
    libc/test/src/math/rintf_test.cpp
    libc/test/src/math/rintl_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/stdc.td
    libc/src/math/CMakeLists.txt
    libc/test/src/math/CMakeLists.txt
    libc/test/src/math/RoundToIntegerTest.h
    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 d5a2f295d9d9..8e430afbcfc8 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -123,12 +123,18 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.ldexp
     libc.src.math.ldexpf
     libc.src.math.ldexpl
+    libc.src.math.llrint
+    libc.src.math.llrintf
+    libc.src.math.llrintl
     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.lrint
+    libc.src.math.lrintf
+    libc.src.math.lrintl
     libc.src.math.lround
     libc.src.math.lroundf
     libc.src.math.lroundl
@@ -141,6 +147,9 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.remquof
     libc.src.math.remquo
     libc.src.math.remquol
+    libc.src.math.rint
+    libc.src.math.rintf
+    libc.src.math.rintl
     libc.src.math.round
     libc.src.math.roundf
     libc.src.math.roundl

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index aca9a1020b1e..0eea8e55701f 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -371,6 +371,18 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"llroundf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
           FunctionSpec<"llroundl", RetValSpec<LongLongType>, [ArgSpec<LongDoubleType>]>,
 
+          FunctionSpec<"rint", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
+          FunctionSpec<"rintf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
+          FunctionSpec<"rintl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
+
+          FunctionSpec<"lrint", RetValSpec<LongType>, [ArgSpec<DoubleType>]>,
+          FunctionSpec<"lrintf", RetValSpec<LongType>, [ArgSpec<FloatType>]>,
+          FunctionSpec<"lrintl", RetValSpec<LongType>, [ArgSpec<LongDoubleType>]>,
+
+          FunctionSpec<"llrint", RetValSpec<LongLongType>, [ArgSpec<DoubleType>]>,
+          FunctionSpec<"llrintf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
+          FunctionSpec<"llrintl", 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 c4de1b1eae86..ff9d79131a60 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -308,6 +308,114 @@ add_entrypoint_object(
     -O2
 )
 
+add_entrypoint_object(
+  rint
+  SRCS
+    rint.cpp
+  HDRS
+    rint.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  rintf
+  SRCS
+    rintf.cpp
+  HDRS
+    rintf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  rintl
+  SRCS
+    rintl.cpp
+  HDRS
+    rintl.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  lrint
+  SRCS
+    lrint.cpp
+  HDRS
+    lrint.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  lrintf
+  SRCS
+    lrintf.cpp
+  HDRS
+    lrintf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  lrintl
+  SRCS
+    lrintl.cpp
+  HDRS
+    lrintl.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  llrint
+  SRCS
+    llrint.cpp
+  HDRS
+    llrint.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  llrintf
+  SRCS
+    llrintf.cpp
+  HDRS
+    llrintf.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
+add_entrypoint_object(
+  llrintl
+  SRCS
+    llrintl.cpp
+  HDRS
+    llrintl.h
+  DEPENDS
+    libc.utils.FPUtil.fputil
+  COMPILE_OPTIONS
+    -O2
+)
+
 add_object_library(
   exp_utils
   HDRS

diff  --git a/libc/src/math/llrint.cpp b/libc/src/math/llrint.cpp
new file mode 100644
index 000000000000..182eaa5c2da0
--- /dev/null
+++ b/libc/src/math/llrint.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of llrint 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(llrint)(double x) {
+  return fputil::roundToSignedIntegerUsingCurrentRoundingMode<double,
+                                                              long long>(x);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/llrint.h b/libc/src/math/llrint.h
new file mode 100644
index 000000000000..96bd7b8cc9e1
--- /dev/null
+++ b/libc/src/math/llrint.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for llrint ------------------------*- 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_LLRINT_H
+#define LLVM_LIBC_SRC_MATH_LLRINT_H
+
+namespace __llvm_libc {
+
+long long llrint(double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LLRINT_H

diff  --git a/libc/src/math/llrintf.cpp b/libc/src/math/llrintf.cpp
new file mode 100644
index 000000000000..33f6cb679179
--- /dev/null
+++ b/libc/src/math/llrintf.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of llrintf 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(llrintf)(float x) {
+  return fputil::roundToSignedIntegerUsingCurrentRoundingMode<float, long long>(
+      x);
+}
+
+} // namespace __llvm_libc

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

diff  --git a/libc/src/math/llrintl.cpp b/libc/src/math/llrintl.cpp
new file mode 100644
index 000000000000..725b3d5959e8
--- /dev/null
+++ b/libc/src/math/llrintl.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of llrintl 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(llrintl)(long double x) {
+  return fputil::roundToSignedIntegerUsingCurrentRoundingMode<long double,
+                                                              long long>(x);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/llrintl.h b/libc/src/math/llrintl.h
new file mode 100644
index 000000000000..94dfba7080aa
--- /dev/null
+++ b/libc/src/math/llrintl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for llrintl -----------------------*- 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_LLRINTL_H
+#define LLVM_LIBC_SRC_MATH_LLRINTL_H
+
+namespace __llvm_libc {
+
+long long llrintl(long double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LLRINTL_H

diff  --git a/libc/src/math/lrint.cpp b/libc/src/math/lrint.cpp
new file mode 100644
index 000000000000..f7ac0266a35f
--- /dev/null
+++ b/libc/src/math/lrint.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of lrint 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(lrint)(double x) {
+  return fputil::roundToSignedIntegerUsingCurrentRoundingMode<double, long>(x);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/lrint.h b/libc/src/math/lrint.h
new file mode 100644
index 000000000000..62df79a1de23
--- /dev/null
+++ b/libc/src/math/lrint.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for lrint -------------------------*- 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_LRINT_H
+#define LLVM_LIBC_SRC_MATH_LRINT_H
+
+namespace __llvm_libc {
+
+long lrint(double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LRINT_H

diff  --git a/libc/src/math/lrintf.cpp b/libc/src/math/lrintf.cpp
new file mode 100644
index 000000000000..ab5911945ab2
--- /dev/null
+++ b/libc/src/math/lrintf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of lrintf 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(lrintf)(float x) {
+  return fputil::roundToSignedIntegerUsingCurrentRoundingMode<float, long>(x);
+}
+
+} // namespace __llvm_libc

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

diff  --git a/libc/src/math/lrintl.cpp b/libc/src/math/lrintl.cpp
new file mode 100644
index 000000000000..ae0e699d9f28
--- /dev/null
+++ b/libc/src/math/lrintl.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of lrintl 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(lrintl)(long double x) {
+  return fputil::roundToSignedIntegerUsingCurrentRoundingMode<long double,
+                                                              long>(x);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/lrintl.h b/libc/src/math/lrintl.h
new file mode 100644
index 000000000000..812acecadafa
--- /dev/null
+++ b/libc/src/math/lrintl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for lrintl ------------------------*- 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_LRINTL_H
+#define LLVM_LIBC_SRC_MATH_LRINTL_H
+
+namespace __llvm_libc {
+
+long lrintl(long double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_LRINTL_H

diff  --git a/libc/src/math/rint.cpp b/libc/src/math/rint.cpp
new file mode 100644
index 000000000000..5081d0ad28fb
--- /dev/null
+++ b/libc/src/math/rint.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of rint 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 {
+
+double LLVM_LIBC_ENTRYPOINT(rint)(double x) {
+  return fputil::roundUsingCurrentRoundingMode(x);
+}
+
+} // namespace __llvm_libc

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

diff  --git a/libc/src/math/rintf.cpp b/libc/src/math/rintf.cpp
new file mode 100644
index 000000000000..7535ee61f123
--- /dev/null
+++ b/libc/src/math/rintf.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of rintf 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 {
+
+float LLVM_LIBC_ENTRYPOINT(rintf)(float x) {
+  return fputil::roundUsingCurrentRoundingMode(x);
+}
+
+} // namespace __llvm_libc

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

diff  --git a/libc/src/math/rintl.cpp b/libc/src/math/rintl.cpp
new file mode 100644
index 000000000000..cc617a2c78bb
--- /dev/null
+++ b/libc/src/math/rintl.cpp
@@ -0,0 +1,18 @@
+//===-- Implementation of rintl 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 double LLVM_LIBC_ENTRYPOINT(rintl)(long double x) {
+  return fputil::roundUsingCurrentRoundingMode(x);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/math/rintl.h b/libc/src/math/rintl.h
new file mode 100644
index 000000000000..2bf095de76f8
--- /dev/null
+++ b/libc/src/math/rintl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for rintl -------------------------*- 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_RINTL_H
+#define LLVM_LIBC_SRC_MATH_RINTL_H
+
+namespace __llvm_libc {
+
+long double rintl(long double x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_RINTL_H

diff  --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 7475be150900..f07843ae8256 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -390,6 +390,141 @@ add_fp_unittest(
     libc.utils.FPUtil.fputil
 )
 
+add_fp_unittest(
+  rint_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    rint_test.cpp
+  HDRS
+    RIntTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.rint
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  rintf_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    rintf_test.cpp
+  HDRS
+    RIntTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.rintf
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  rintl_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    rintl_test.cpp
+  HDRS
+    RIntTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.rintl
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  lrint_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    lrint_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.lrint
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  lrintf_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    lrintf_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.lrintf
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  lrintl_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    lrintl_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.lrintl
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  llrint_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    llrint_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.llrint
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  llrintf_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    llrintf_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.llrintf
+    libc.utils.FPUtil.fputil
+)
+
+add_fp_unittest(
+  llrintl_test
+  NEED_MPFR
+  SUITE
+    libc_math_unittests
+  SRCS
+    llrintl_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.llrintl
+    libc.utils.FPUtil.fputil
+)
+
 add_fp_unittest(
   expf_test
   NEED_MPFR

diff  --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
new file mode 100644
index 000000000000..d09dc9324977
--- /dev/null
+++ b/libc/test/src/math/RIntTest.h
@@ -0,0 +1,138 @@
+//===-- Utility class to test 
diff erent flavors of rint ---------*- 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_RINTTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
+
+#include "utils/FPUtil/FEnv.h"
+#include "utils/FPUtil/FPBits.h"
+#include "utils/FPUtil/TestHelpers.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+
+#include <fenv.h>
+#include <math.h>
+#include <stdio.h>
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
+                                         FE_TONEAREST};
+
+template <typename T>
+class RIntTestTemplate : public __llvm_libc::testing::Test {
+public:
+  typedef T (*RIntFunc)(T);
+
+private:
+  using FPBits = __llvm_libc::fputil::FPBits<T>;
+  using UIntType = typename FPBits::UIntType;
+
+  const T zero = FPBits::zero();
+  const T negZero = FPBits::negZero();
+  const T inf = FPBits::inf();
+  const T negInf = FPBits::negInf();
+  const T nan = FPBits::buildNaN(1);
+
+  static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
+    switch (mode) {
+    case FE_UPWARD:
+      return mpfr::RoundingMode::Upward;
+    case FE_DOWNWARD:
+      return mpfr::RoundingMode::Downward;
+    case FE_TOWARDZERO:
+      return mpfr::RoundingMode::TowardZero;
+    case FE_TONEAREST:
+      return mpfr::RoundingMode::Nearest;
+    default:
+      __builtin_unreachable();
+    }
+  }
+
+public:
+  void testSpecialNumbers(RIntFunc func) {
+    for (int mode : roundingModes) {
+      __llvm_libc::fputil::setRound(mode);
+      ASSERT_FP_EQ(inf, func(inf));
+      ASSERT_FP_EQ(negInf, func(negInf));
+      ASSERT_FP_EQ(nan, func(nan));
+      ASSERT_FP_EQ(zero, func(zero));
+      ASSERT_FP_EQ(negZero, func(negZero));
+    }
+  }
+
+  void testRoundNumbers(RIntFunc func) {
+    for (int mode : roundingModes) {
+      __llvm_libc::fputil::setRound(mode);
+      mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
+      ASSERT_FP_EQ(func(T(1.0)), mpfr::Round(T(1.0), mpfrMode));
+      ASSERT_FP_EQ(func(T(-1.0)), mpfr::Round(T(-1.0), mpfrMode));
+      ASSERT_FP_EQ(func(T(10.0)), mpfr::Round(T(10.0), mpfrMode));
+      ASSERT_FP_EQ(func(T(-10.0)), mpfr::Round(T(-10.0), mpfrMode));
+      ASSERT_FP_EQ(func(T(1234.0)), mpfr::Round(T(1234.0), mpfrMode));
+      ASSERT_FP_EQ(func(T(-1234.0)), mpfr::Round(T(-1234.0), mpfrMode));
+    }
+  }
+
+  void testFractions(RIntFunc func) {
+    for (int mode : roundingModes) {
+      __llvm_libc::fputil::setRound(mode);
+      mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
+      ASSERT_FP_EQ(func(T(0.5)), mpfr::Round(T(0.5), mpfrMode));
+      ASSERT_FP_EQ(func(T(-0.5)), mpfr::Round(T(-0.5), mpfrMode));
+      ASSERT_FP_EQ(func(T(0.115)), mpfr::Round(T(0.115), mpfrMode));
+      ASSERT_FP_EQ(func(T(-0.115)), mpfr::Round(T(-0.115), mpfrMode));
+      ASSERT_FP_EQ(func(T(0.715)), mpfr::Round(T(0.715), mpfrMode));
+      ASSERT_FP_EQ(func(T(-0.715)), mpfr::Round(T(-0.715), mpfrMode));
+    }
+  }
+
+  void testSubnormalRange(RIntFunc func) {
+    constexpr UIntType count = 1000001;
+    constexpr UIntType step =
+        (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
+    for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
+         i += step) {
+      T x = FPBits(i);
+      for (int mode : roundingModes) {
+        __llvm_libc::fputil::setRound(mode);
+        mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
+        ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
+      }
+    }
+  }
+
+  void testNormalRange(RIntFunc func) {
+    constexpr UIntType count = 1000001;
+    constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
+    for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
+      T 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;
+      }
+
+      for (int mode : roundingModes) {
+        __llvm_libc::fputil::setRound(mode);
+        mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
+        ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
+      }
+    }
+  }
+};
+
+#define LIST_RINT_TESTS(F, func)                                               \
+  using RIntTest = RIntTestTemplate<F>;                                        \
+  TEST_F(RIntTest, specialNumbers) { testSpecialNumbers(&func); }              \
+  TEST_F(RIntTest, RoundNumbers) { testRoundNumbers(&func); }                  \
+  TEST_F(RIntTest, Fractions) { testFractions(&func); }                        \
+  TEST_F(RIntTest, SubnormalRange) { testSubnormalRange(&func); }              \
+  TEST_F(RIntTest, NormalRange) { testNormalRange(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H

diff  --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
index 37b42f385247..d8711faca3f1 100644
--- a/libc/test/src/math/RoundToIntegerTest.h
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -10,9 +10,6 @@
 #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/FPUtil/FPBits.h"
 #include "utils/MPFRWrapper/MPFRUtils.h"
 #include "utils/UnitTest/Test.h"
@@ -27,7 +24,10 @@
 
 namespace mpfr = __llvm_libc::testing::mpfr;
 
-template <typename F, typename I>
+static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
+                                         FE_TONEAREST};
+
+template <typename F, typename I, bool TestModes = false>
 class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
 public:
   typedef I (*RoundToIntegerFunc)(F);
@@ -50,21 +50,21 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
     llvmlibc_errno = 0;
 #endif
 #if math_errhandling & MATH_ERREXCEPT
-    __llvm_libc::feclearexcept(FE_ALL_EXCEPT);
+    __llvm_libc::fputil::clearExcept(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);
+      ASSERT_EQ(__llvm_libc::fputil::testExcept(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);
+      ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), 0);
 #endif
 #if math_errhandling & MATH_ERRNO
       ASSERT_EQ(llvmlibc_errno, 0);
@@ -72,6 +72,21 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
     }
   }
 
+  static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
+    switch (mode) {
+    case FE_UPWARD:
+      return mpfr::RoundingMode::Upward;
+    case FE_DOWNWARD:
+      return mpfr::RoundingMode::Downward;
+    case FE_TOWARDZERO:
+      return mpfr::RoundingMode::TowardZero;
+    case FE_TONEAREST:
+      return mpfr::RoundingMode::Nearest;
+    default:
+      __builtin_unreachable();
+    }
+  }
+
 public:
   void SetUp() override {
 #if math_errhandling & MATH_ERREXCEPT
@@ -82,13 +97,24 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
 #endif
   }
 
-  void testInfinityAndNaN(RoundToIntegerFunc func) {
+  void doInfinityAndNaNTest(RoundToIntegerFunc func) {
     testOneInput(func, inf, IntegerMax, true);
     testOneInput(func, negInf, IntegerMin, true);
     testOneInput(func, nan, IntegerMax, true);
   }
 
-  void testRoundNumbers(RoundToIntegerFunc func) {
+  void testInfinityAndNaN(RoundToIntegerFunc func) {
+    if (TestModes) {
+      for (int mode : roundingModes) {
+        __llvm_libc::fputil::setRound(mode);
+        doInfinityAndNaNTest(func);
+      }
+    } else {
+      doInfinityAndNaNTest(func);
+    }
+  }
+
+  void doRoundNumbersTest(RoundToIntegerFunc func) {
     testOneInput(func, zero, I(0), false);
     testOneInput(func, negZero, I(0), false);
     testOneInput(func, F(1.0), I(1), false);
@@ -121,13 +147,44 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
     testOneInput(func, x, mpfrResult, false);
   }
 
+  void testRoundNumbers(RoundToIntegerFunc func) {
+    if (TestModes) {
+      for (int mode : roundingModes) {
+        __llvm_libc::fputil::setRound(mode);
+        doRoundNumbersTest(func);
+      }
+    } else {
+      doRoundNumbersTest(func);
+    }
+  }
+
+  void doFractionsTest(RoundToIntegerFunc func, int mode) {
+    constexpr F fractions[] = {0.5, -0.5, 0.115, -0.115, 0.715, -0.715};
+    for (F x : fractions) {
+      long mpfrLongResult;
+      bool erangeflag;
+      if (TestModes)
+        erangeflag =
+            mpfr::RoundToLong(x, toMPFRRoundingMode(mode), mpfrLongResult);
+      else
+        erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
+      ASSERT_FALSE(erangeflag);
+      I mpfrResult = mpfrLongResult;
+      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);
+    if (TestModes) {
+      for (int mode : roundingModes) {
+        __llvm_libc::fputil::setRound(mode);
+        doFractionsTest(func, mode);
+      }
+    } else {
+      // Passing 0 for mode has no effect as it is not used in doFractionsTest
+      // when `TestModes` is false;
+      doFractionsTest(func, 0);
+    }
   }
 
   void testIntegerOverflow(RoundToIntegerFunc func) {
@@ -149,29 +206,56 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
                     << (__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);
+    if (TestModes) {
+      for (int m : roundingModes) {
+        __llvm_libc::fputil::setRound(m);
+        long mpfrLongResult;
+        bool erangeflag =
+            mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
+        ASSERT_TRUE(erangeflag);
+        testOneInput(func, x, IntegerMin, true);
+      }
+    } else {
+      long mpfrLongResult;
+      bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
+      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);
+      if (x == F(0.0))
+        continue;
       // All subnormal numbers should round to zero.
-      testOneInput(func, x, 0L, false);
+      if (TestModes) {
+        if (x > 0) {
+          __llvm_libc::fputil::setRound(FE_UPWARD);
+          testOneInput(func, x, I(1), false);
+          __llvm_libc::fputil::setRound(FE_DOWNWARD);
+          testOneInput(func, x, I(0), false);
+          __llvm_libc::fputil::setRound(FE_TOWARDZERO);
+          testOneInput(func, x, I(0), false);
+          __llvm_libc::fputil::setRound(FE_TONEAREST);
+          testOneInput(func, x, I(0), false);
+        } else {
+          __llvm_libc::fputil::setRound(FE_UPWARD);
+          testOneInput(func, x, I(0), false);
+          __llvm_libc::fputil::setRound(FE_DOWNWARD);
+          testOneInput(func, x, I(-1), false);
+          __llvm_libc::fputil::setRound(FE_TOWARDZERO);
+          testOneInput(func, x, I(0), false);
+          __llvm_libc::fputil::setRound(FE_TONEAREST);
+          testOneInput(func, x, I(0), false);
+        }
+      } else {
+        testOneInput(func, x, 0L, false);
+      }
     }
   }
 
@@ -194,18 +278,33 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
         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);
+      if (TestModes) {
+        for (int m : roundingModes) {
+          long mpfrLongResult;
+          bool erangeflag =
+              mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
+          I mpfrResult = mpfrLongResult;
+          __llvm_libc::fputil::setRound(m);
+          if (erangeflag)
+            testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
+          else
+            testOneInput(func, x, mpfrResult, false);
+        }
+      } else {
+        long mpfrLongResult;
+        bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
+        I mpfrResult = mpfrLongResult;
+        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>;                 \
+#define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes)              \
+  using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I, TestModes>;      \
   TEST_F(RoundToIntegerTest, InfinityAndNaN) { testInfinityAndNaN(&func); }    \
   TEST_F(RoundToIntegerTest, RoundNumbers) { testRoundNumbers(&func); }        \
   TEST_F(RoundToIntegerTest, Fractions) { testFractions(&func); }              \
@@ -213,4 +312,10 @@ class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
   TEST_F(RoundToIntegerTest, SubnormalRange) { testSubnormalRange(&func); }    \
   TEST_F(RoundToIntegerTest, NormalRange) { testNormalRange(&func); }
 
+#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func)                                \
+  LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false)
+
+#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func)                     \
+  LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true)
+
 #endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H

diff  --git a/libc/test/src/math/llrint_test.cpp b/libc/test/src/math/llrint_test.cpp
new file mode 100644
index 000000000000..8027004bd50a
--- /dev/null
+++ b/libc/test/src/math/llrint_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for llrint ----------------------------------------------===//
+//
+// 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 "src/math/llrint.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(double, long long, __llvm_libc::llrint)

diff  --git a/libc/test/src/math/llrintf_test.cpp b/libc/test/src/math/llrintf_test.cpp
new file mode 100644
index 000000000000..9ad710e46983
--- /dev/null
+++ b/libc/test/src/math/llrintf_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for llrintf ---------------------------------------------===//
+//
+// 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 "src/math/llrintf.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float, long long, __llvm_libc::llrintf)

diff  --git a/libc/test/src/math/llrintl_test.cpp b/libc/test/src/math/llrintl_test.cpp
new file mode 100644
index 000000000000..948e961e57bd
--- /dev/null
+++ b/libc/test/src/math/llrintl_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for llrintl ---------------------------------------------===//
+//
+// 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 "src/math/llrintl.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(long double, long long,
+                                       __llvm_libc::llrintl)

diff  --git a/libc/test/src/math/lrint_test.cpp b/libc/test/src/math/lrint_test.cpp
new file mode 100644
index 000000000000..0dbfa3dd466d
--- /dev/null
+++ b/libc/test/src/math/lrint_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for lrint -----------------------------------------------===//
+//
+// 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 "src/math/lrint.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(double, long, __llvm_libc::lrint)

diff  --git a/libc/test/src/math/lrintf_test.cpp b/libc/test/src/math/lrintf_test.cpp
new file mode 100644
index 000000000000..407813aa83c0
--- /dev/null
+++ b/libc/test/src/math/lrintf_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for lrintf ----------------------------------------------===//
+//
+// 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 "src/math/lrintf.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float, long, __llvm_libc::lrintf)

diff  --git a/libc/test/src/math/lrintl_test.cpp b/libc/test/src/math/lrintl_test.cpp
new file mode 100644
index 000000000000..a4551c38de10
--- /dev/null
+++ b/libc/test/src/math/lrintl_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for lrintl ----------------------------------------------===//
+//
+// 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 "src/math/lrintl.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(long double, long, __llvm_libc::lrintl)

diff  --git a/libc/test/src/math/rint_test.cpp b/libc/test/src/math/rint_test.cpp
new file mode 100644
index 000000000000..eafa1a7fe611
--- /dev/null
+++ b/libc/test/src/math/rint_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for rint ------------------------------------------------===//
+//
+// 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 "RIntTest.h"
+
+#include "src/math/rint.h"
+
+LIST_RINT_TESTS(double, __llvm_libc::rint)

diff  --git a/libc/test/src/math/rintf_test.cpp b/libc/test/src/math/rintf_test.cpp
new file mode 100644
index 000000000000..c15a697fac92
--- /dev/null
+++ b/libc/test/src/math/rintf_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for rintf -----------------------------------------------===//
+//
+// 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 "RIntTest.h"
+
+#include "src/math/rintf.h"
+
+LIST_RINT_TESTS(float, __llvm_libc::rintf)

diff  --git a/libc/test/src/math/rintl_test.cpp b/libc/test/src/math/rintl_test.cpp
new file mode 100644
index 000000000000..6c50873a272d
--- /dev/null
+++ b/libc/test/src/math/rintl_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for rintl -----------------------------------------------===//
+//
+// 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 "RIntTest.h"
+
+#include "src/math/rintl.h"
+
+LIST_RINT_TESTS(long double, __llvm_libc::rintl)

diff  --git a/libc/utils/FPUtil/NearestIntegerOperations.h b/libc/utils/FPUtil/NearestIntegerOperations.h
index 98a2f6f6b139..6af4c4ccf913 100644
--- a/libc/utils/FPUtil/NearestIntegerOperations.h
+++ b/libc/utils/FPUtil/NearestIntegerOperations.h
@@ -9,14 +9,12 @@
 #ifndef LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
 #define LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
 
+#include "FEnv.h"
 #include "FPBits.h"
 
 #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>
@@ -159,17 +157,94 @@ static inline T round(T x) {
   }
 }
 
+template <typename T,
+          cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T roundUsingCurrentRoundingMode(T x) {
+  using UIntType = typename FPBits<T>::UIntType;
+  FPBits<T> bits(x);
+
+  // If x is infinity NaN or zero, return it.
+  if (bits.isInfOrNaN() || bits.isZero())
+    return x;
+
+  bool isNeg = bits.sign;
+  int exponent = bits.getExponent();
+  int roundingMode = getRound();
+
+  // If the exponent is greater than the most negative mantissa
+  // exponent, then x is already an integer.
+  if (exponent >= static_cast<int>(MantissaWidth<T>::value))
+    return x;
+
+  if (exponent <= -1) {
+    switch (roundingMode) {
+    case FE_DOWNWARD:
+      return isNeg ? T(-1.0) : T(0.0);
+    case FE_UPWARD:
+      return isNeg ? T(-0.0) : T(1.0);
+    case FE_TOWARDZERO:
+      return isNeg ? T(-0.0) : T(0.0);
+    case FE_TONEAREST:
+      if (exponent <= -2 || bits.mantissa == 0)
+        return isNeg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
+      else
+        return isNeg ? T(-1.0) : T(1.0); // abs(x) > 0.5
+    default:
+      __builtin_unreachable();
+    }
+  }
+
+  uint32_t trimSize = MantissaWidth<T>::value - exponent;
+  FPBits<T> newBits = bits;
+  newBits.mantissa = (bits.mantissa >> trimSize) << trimSize;
+  T truncValue = T(newBits);
+
+  // If x is already an integer, return it.
+  if (truncValue == x)
+    return x;
+
+  UIntType trimValue = bits.mantissa & ((UIntType(1) << trimSize) - 1);
+  UIntType halfValue = (UIntType(1) << (trimSize - 1));
+  // If exponent is 0, trimSize will be equal to the mantissa width, and
+  // truncIsOdd` will not be correct. So, we handle it as a special case
+  // below.
+  UIntType truncIsOdd = newBits.mantissa & (UIntType(1) << trimSize);
+
+  switch (roundingMode) {
+  case FE_DOWNWARD:
+    return isNeg ? truncValue - T(1.0) : truncValue;
+  case FE_UPWARD:
+    return isNeg ? truncValue : truncValue + T(1.0);
+  case FE_TOWARDZERO:
+    return truncValue;
+  case FE_TONEAREST:
+    if (trimValue > halfValue) {
+      return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
+    } else if (trimValue == halfValue) {
+      if (exponent == 0)
+        return isNeg ? T(-2.0) : T(2.0);
+      if (truncIsOdd)
+        return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
+      else
+        return truncValue;
+    } else {
+      return truncValue;
+    }
+  default:
+    __builtin_unreachable();
+  }
+}
+
+namespace internal {
+
 template <typename F, typename I,
           cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
                                 cpp::IsIntegral<I>::Value,
                             int> = 0>
-static inline I roundToSignedInteger(F x) {
+static inline I roundedFloatToSignedInteger(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);
+  FPBits<F> bits(x);
   auto setDomainErrorAndRaiseInvalid = []() {
 #if math_errhandling & MATH_ERRNO
     llvmlibc_errno = EDOM;
@@ -180,8 +255,6 @@ static inline I roundToSignedInteger(F x) {
   };
 
   if (bits.isInfOrNaN()) {
-    // Result of round is infinity or NaN only if x is infinity
-    // or NaN.
     setDomainErrorAndRaiseInvalid();
     return bits.sign ? IntegerMin : IntegerMax;
   }
@@ -200,10 +273,29 @@ static inline I roundToSignedInteger(F x) {
     // 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
+  // For all other cases, if `x` can fit in the integer type `I`,
+  // we just return `x`. Implicit conversion will convert the
   // floating point value to the exact integer value.
-  return roundedValue;
+  return x;
+}
+
+} // namespace internal
+
+template <typename F, typename I,
+          cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
+                                cpp::IsIntegral<I>::Value,
+                            int> = 0>
+static inline I roundToSignedInteger(F x) {
+  return internal::roundedFloatToSignedInteger<F, I>(round(x));
+}
+
+template <typename F, typename I,
+          cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
+                                cpp::IsIntegral<I>::Value,
+                            int> = 0>
+static inline I roundToSignedIntegerUsingCurrentRoundingMode(F x) {
+  return internal::roundedFloatToSignedInteger<F, I>(
+      roundUsingCurrentRoundingMode(x));
 }
 
 } // namespace fputil

diff  --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 6f3d216b72c9..3c66ccfe5b38 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -163,6 +163,18 @@ class MPFRNumber {
     return mpfr_erangeflag_p();
   }
 
+  bool roundToLong(mpfr_rnd_t rnd, long &result) const {
+    MPFRNumber rint_result;
+    mpfr_rint(rint_result.value, value, rnd);
+    return rint_result.roundToLong(result);
+  }
+
+  MPFRNumber rint(mpfr_rnd_t rnd) const {
+    MPFRNumber result;
+    mpfr_rint(result.value, value, rnd);
+    return result;
+  }
+
   MPFRNumber sin() const {
     MPFRNumber result;
     mpfr_sin(result.value, value, MPFR_RNDN);
@@ -563,6 +575,23 @@ compareBinaryOperationOneOutput<double>(Operation, const BinaryInput<double> &,
 template bool compareBinaryOperationOneOutput<long double>(
     Operation, const BinaryInput<long double> &, long double, double);
 
+static mpfr_rnd_t getMPFRRoundingMode(RoundingMode mode) {
+  switch (mode) {
+  case RoundingMode::Upward:
+    return MPFR_RNDU;
+    break;
+  case RoundingMode::Downward:
+    return MPFR_RNDD;
+    break;
+  case RoundingMode::TowardZero:
+    return MPFR_RNDZ;
+    break;
+  case RoundingMode::Nearest:
+    return MPFR_RNDN;
+    break;
+  }
+}
+
 } // namespace internal
 
 template <typename T> bool RoundToLong(T x, long &result) {
@@ -574,6 +603,25 @@ template bool RoundToLong<float>(float, long &);
 template bool RoundToLong<double>(double, long &);
 template bool RoundToLong<long double>(long double, long &);
 
+template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result) {
+  MPFRNumber mpfr(x);
+  return mpfr.roundToLong(internal::getMPFRRoundingMode(mode), result);
+}
+
+template bool RoundToLong<float>(float, RoundingMode, long &);
+template bool RoundToLong<double>(double, RoundingMode, long &);
+template bool RoundToLong<long double>(long double, RoundingMode, long &);
+
+template <typename T> T Round(T x, RoundingMode mode) {
+  MPFRNumber mpfr(x);
+  MPFRNumber result = mpfr.rint(internal::getMPFRRoundingMode(mode));
+  return result.as<T>();
+}
+
+template float Round<float>(float, RoundingMode);
+template double Round<double>(double, RoundingMode);
+template long double Round<long double>(long double, RoundingMode);
+
 } // namespace mpfr
 } // namespace testing
 } // namespace __llvm_libc

diff  --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index cc0dab66947e..db20b1b2d8c8 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -237,7 +237,12 @@ getMPFRMatcher(InputType input, OutputType outputUnused, double t) {
   return internal::MPFRMatcher<op, InputType, OutputType>(input, t);
 }
 
+enum class RoundingMode : uint8_t { Upward, Downward, TowardZero, Nearest };
+
+template <typename T> T Round(T x, RoundingMode mode);
+
 template <typename T> bool RoundToLong(T x, long &result);
+template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result);
 
 } // namespace mpfr
 } // namespace testing


        


More information about the libc-commits mailing list