[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