Skip to content

[libc] Implement roundeven C23 math functions #87678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 5, 2024

Conversation

vinayakdsci
Copy link
Contributor

Implements the functions roundeven(), roundevenf(), roundevenl() from the roundeven family of functions introduced in C23. Also implements roundevenf128().

@llvmbot llvmbot added the libc label Apr 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 4, 2024

@llvm/pr-subscribers-libc

Author: Vinayak Dev (vinayakdsci)

Changes

Implements the functions roundeven(), roundevenf(), roundevenl() from the roundeven family of functions introduced in C23. Also implements roundevenf128().


Patch is 25.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/87678.diff

25 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+4)
  • (modified) libc/docs/math/index.rst (+1-1)
  • (modified) libc/src/math/CMakeLists.txt (+5)
  • (modified) libc/src/math/generic/CMakeLists.txt (+49)
  • (added) libc/src/math/generic/roundeven.cpp (+19)
  • (added) libc/src/math/generic/roundevenf.cpp (+19)
  • (added) libc/src/math/generic/roundevenf128.cpp (+19)
  • (added) libc/src/math/generic/roundevenl.cpp (+19)
  • (added) libc/src/math/roundeven.h (+18)
  • (added) libc/src/math/roundevenf.h (+18)
  • (added) libc/src/math/roundevenf128.h (+20)
  • (added) libc/src/math/roundevenl.h (+18)
  • (modified) libc/test/src/math/CMakeLists.txt (+45)
  • (added) libc/test/src/math/RoundEvenTest.h (+92)
  • (added) libc/test/src/math/roundeven_test.cpp (+13)
  • (added) libc/test/src/math/roundevenf_test.cpp (+13)
  • (added) libc/test/src/math/roundevenl_test.cpp (+13)
  • (modified) libc/test/src/math/smoke/CMakeLists.txt (+56)
  • (added) libc/test/src/math/smoke/RoundEvenTest.h (+72)
  • (added) libc/test/src/math/smoke/roundeven_test.cpp (+12)
  • (added) libc/test/src/math/smoke/roundevenf128_test.cpp (+12)
  • (added) libc/test/src/math/smoke/roundevenf_test.cpp (+12)
  • (added) libc/test/src/math/smoke/roundevenl_test.cpp (+12)
  • (modified) libc/utils/MPFRWrapper/MPFRUtils.cpp (+8)
  • (modified) libc/utils/MPFRWrapper/MPFRUtils.h (+1)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 2742c33ae47845..1248ca6372b10b 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -494,6 +494,10 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.round
     libc.src.math.roundf
     libc.src.math.roundl
+    libc.src.math.roundeven
+    libc.src.math.roundevenf
+    libc.src.math.roundevenl
+    libc.src.math.roundevenf128
     libc.src.math.scalbn
     libc.src.math.scalbnf
     libc.src.math.scalbnl
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index 970a43ca87c9ec..7a7b6c9c8db5de 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -206,7 +206,7 @@ Basic Operations
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | round            | |check|          | |check|         | |check|                |                      | |check|                | 7.12.9.6               | F.10.6.6                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| roundeven        |                  |                 |                        |                      |                        | 7.12.9.8               | F.10.6.8                   |
+| roundeven        | |check|          | |check|         | |check|                |                      | |check|                | 7.12.9.8               | F.10.6.8                   |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
 | scalbn           | |check|          | |check|         | |check|                |                      |                        | 7.12.6.19              | F.10.3.19                  |
 +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index c89792b8ac7be6..e8f699fabe3655 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -293,6 +293,11 @@ add_math_entrypoint_object(roundf)
 add_math_entrypoint_object(roundl)
 add_math_entrypoint_object(roundf128)
 
+add_math_entrypoint_object(roundeven)
+add_math_entrypoint_object(roundevenf)
+add_math_entrypoint_object(roundevenl)
+add_math_entrypoint_object(roundevenf128)
+
 add_math_entrypoint_object(scalbn)
 add_math_entrypoint_object(scalbnf)
 add_math_entrypoint_object(scalbnl)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index dc77f8b5ddba28..5bc9066c6263cd 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -417,6 +417,55 @@ add_entrypoint_object(
     libc.src.__support.FPUtil.nearest_integer_operations
 )
 
+add_entrypoint_object(
+  roundeven
+  SRCS
+    roundeven.cpp
+  HDRS
+    ../roundeven.h
+  COMPILE_OPTIONS
+    -O3
+  DEPENDS
+    libc.src.__support.FPUtil.nearest_integer_operations
+)
+
+add_entrypoint_object(
+  roundevenf
+  SRCS
+    roundevenf.cpp
+  HDRS
+    ../roundevenf.h
+  COMPILE_OPTIONS
+    -O3
+  DEPENDS
+    libc.src.__support.FPUtil.nearest_integer_operations
+)
+
+add_entrypoint_object(
+  roundevenl
+  SRCS
+    roundevenl.cpp
+  HDRS
+    ../roundevenl.h
+  COMPILE_OPTIONS
+    -O3
+  DEPENDS
+    libc.src.__support.FPUtil.nearest_integer_operations
+)
+
+add_entrypoint_object(
+  roundevenf128
+  SRCS
+    roundevenf128.cpp
+  HDRS
+    ../roundevenf128.h
+  COMPILE_OPTIONS
+    -O3
+  DEPENDS
+    libc.src.__support.macros.properties.types
+    libc.src.__support.FPUtil.nearest_integer_operations
+)
+
 add_entrypoint_object(
   lround
   SRCS
diff --git a/libc/src/math/generic/roundeven.cpp b/libc/src/math/generic/roundeven.cpp
new file mode 100644
index 00000000000000..5f2adf9b5fce68
--- /dev/null
+++ b/libc/src/math/generic/roundeven.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of roundeven 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/math/roundeven.h"
+#include "src/__support/FPUtil/NearestIntegerOperations.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(double, roundeven, (double x)) {
+  return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/roundevenf.cpp b/libc/src/math/generic/roundevenf.cpp
new file mode 100644
index 00000000000000..353bec74ecf024
--- /dev/null
+++ b/libc/src/math/generic/roundevenf.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of roundevenf 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/math/roundevenf.h"
+#include "src/__support/FPUtil/NearestIntegerOperations.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float, roundevenf, (float x)) {
+  return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/roundevenf128.cpp b/libc/src/math/generic/roundevenf128.cpp
new file mode 100644
index 00000000000000..259388c86fd336
--- /dev/null
+++ b/libc/src/math/generic/roundevenf128.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of roundevenf128 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/math/roundevenf128.h"
+#include "src/__support/FPUtil/NearestIntegerOperations.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float128, roundevenf128, (float128 x)) {
+  return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/roundevenl.cpp b/libc/src/math/generic/roundevenl.cpp
new file mode 100644
index 00000000000000..f8f429faeec8a8
--- /dev/null
+++ b/libc/src/math/generic/roundevenl.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of roundevenl 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/math/roundevenl.h"
+#include "src/__support/FPUtil/NearestIntegerOperations.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long double, roundevenl, (long double x)) {
+  return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/roundeven.h b/libc/src/math/roundeven.h
new file mode 100644
index 00000000000000..9c76b1fe334ab5
--- /dev/null
+++ b/libc/src/math/roundeven.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for roundeven ---------------------*- 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_ROUNDEVEN_H
+#define LLVM_LIBC_SRC_MATH_ROUNDEVEN_H
+
+namespace LIBC_NAMESPACE {
+
+double roundeven(double x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_ROUNDEVEN_H
diff --git a/libc/src/math/roundevenf.h b/libc/src/math/roundevenf.h
new file mode 100644
index 00000000000000..447e7fd940c18a
--- /dev/null
+++ b/libc/src/math/roundevenf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for roundevenf --------------------*- 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_ROUNDEVENF_H
+#define LLVM_LIBC_SRC_MATH_ROUNDEVENF_H
+
+namespace LIBC_NAMESPACE {
+
+float roundevenf(float x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF_H
diff --git a/libc/src/math/roundevenf128.h b/libc/src/math/roundevenf128.h
new file mode 100644
index 00000000000000..589839d090756c
--- /dev/null
+++ b/libc/src/math/roundevenf128.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for roundevenf128 -----------------*- 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_ROUNDEVENF128_H
+#define LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float128 roundevenf128(float128 x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H
diff --git a/libc/src/math/roundevenl.h b/libc/src/math/roundevenl.h
new file mode 100644
index 00000000000000..a2f3397e4479ae
--- /dev/null
+++ b/libc/src/math/roundevenl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for roundevenl --------------------*- 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_ROUNDEVENL_H
+#define LLVM_LIBC_SRC_MATH_ROUNDEVENL_H
+
+namespace LIBC_NAMESPACE {
+
+long double roundevenl(long double x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENL_H
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index bbf8f071e1e0c2..d928cb5c64750e 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -323,6 +323,51 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  roundeven_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    roundeven_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundeven
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  roundevenf_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    roundevenf_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundevenf
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  roundevenl_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    roundevenl_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundevenl
+    libc.src.__support.FPUtil.fp_bits
+)
+
 add_fp_unittest(
   lround_test
   NEED_MPFR
diff --git a/libc/test/src/math/RoundEvenTest.h b/libc/test/src/math/RoundEvenTest.h
new file mode 100644
index 00000000000000..db7263a39c0f0a
--- /dev/null
+++ b/libc/test/src/math/RoundEvenTest.h
@@ -0,0 +1,92 @@
+//===-- Utility class to test roundeven[f|l] --------------------*- 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_ROUNDEVENTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H
+
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+#include "include/llvm-libc-macros/math-macros.h"
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+template <typename T>
+class RoundEvenTest : public LIBC_NAMESPACE::testing::Test {
+
+  DECLARE_SPECIAL_CONSTANTS(T)
+
+public:
+  typedef T (*RoundEvenFunc)(T);
+
+  void testSpecialNumbers(RoundEvenFunc func) {
+    EXPECT_FP_EQ(zero, func(zero));
+    EXPECT_FP_EQ(neg_zero, func(neg_zero));
+
+    EXPECT_FP_EQ(inf, func(inf));
+    EXPECT_FP_EQ(neg_inf, func(neg_inf));
+
+    EXPECT_FP_EQ(aNaN, func(aNaN));
+  }
+
+  void testRoundedNumbers(RoundEvenFunc func) {
+    EXPECT_FP_EQ(T(1.0), func(T(1.0)));
+    EXPECT_FP_EQ(T(-1.0), func(T(-1.0)));
+    EXPECT_FP_EQ(T(10.0), func(T(10.0)));
+    EXPECT_FP_EQ(T(-10.0), func(T(-10.0)));
+    EXPECT_FP_EQ(T(1234.0), func(T(1234.0)));
+    EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0)));
+  }
+
+  void testFractions(RoundEvenFunc func) {
+    EXPECT_FP_EQ(T(0.0), func(T(0.5)));
+    EXPECT_FP_EQ(T(-0.0), func(T(-0.5)));
+    EXPECT_FP_EQ(T(0.0), func(T(0.115)));
+    EXPECT_FP_EQ(T(-0.0), func(T(-0.115)));
+    EXPECT_FP_EQ(T(1.0), func(T(0.715)));
+    EXPECT_FP_EQ(T(-1.0), func(T(-0.715)));
+    EXPECT_FP_EQ(T(1.0), func(T(1.3)));
+    EXPECT_FP_EQ(T(-1.0), func(T(-1.3)));
+    EXPECT_FP_EQ(T(2.0), func(T(1.5)));
+    EXPECT_FP_EQ(T(-2.0), func(T(-1.5)));
+    EXPECT_FP_EQ(T(2.0), func(T(1.75)));
+    EXPECT_FP_EQ(T(-2.0), func(T(-1.75)));
+    EXPECT_FP_EQ(T(11.0), func(T(10.65)));
+    EXPECT_FP_EQ(T(-11.0), func(T(-10.65)));
+    EXPECT_FP_EQ(T(1233.0), func(T(1233.25)));
+    EXPECT_FP_EQ(T(1234.0), func(T(1233.50)));
+    EXPECT_FP_EQ(T(1234.0), func(T(1233.75)));
+    EXPECT_FP_EQ(T(-1233.0), func(T(-1233.25)));
+    EXPECT_FP_EQ(T(-1234.0), func(T(-1233.50)));
+    EXPECT_FP_EQ(T(-1234.0), func(T(-1233.75)));
+    EXPECT_FP_EQ(T(1234.0), func(T(1234.50)));
+    EXPECT_FP_EQ(T(-1234.0), func(T(-1234.50)));
+  }
+
+  void testRange(RoundEvenFunc func) {
+    constexpr StorageType COUNT = 100'000;
+    constexpr StorageType STEP = STORAGE_MAX / COUNT;
+    for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
+      T x = FPBits(v).get_val();
+      if (isnan(x) || isinf(x))
+        continue;
+
+      ASSERT_MPFR_MATCH(mpfr::Operation::RoundEven, x, func(x), 0.0);
+    }
+  }
+};
+
+#define LIST_ROUNDEVEN_TESTS(T, func)                                          \
+  using LlvmLibcRoundEvenTest = RoundEvenTest<T>;                              \
+  TEST_F(LlvmLibcRoundEvenTest, SpecialNumbers) { testSpecialNumbers(&func); } \
+  TEST_F(LlvmLibcRoundEvenTest, RoundedNubmers) { testRoundedNumbers(&func); } \
+  TEST_F(LlvmLibcRoundEvenTest, Fractions) { testFractions(&func); }           \
+  TEST_F(LlvmLibcRoundEvenTest, Range) { testRange(&func); }
+
+#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H
diff --git a/libc/test/src/math/roundeven_test.cpp b/libc/test/src/math/roundeven_test.cpp
new file mode 100644
index 00000000000000..cd1a7bf2429fbd
--- /dev/null
+++ b/libc/test/src/math/roundeven_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for roundeven -------------------------------------------===//
+//
+// 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 "RoundEvenTest.h"
+
+#include "src/math/roundeven.h"
+
+LIST_ROUNDEVEN_TESTS(double, LIBC_NAMESPACE::roundeven)
diff --git a/libc/test/src/math/roundevenf_test.cpp b/libc/test/src/math/roundevenf_test.cpp
new file mode 100644
index 00000000000000..68dff9b3eca9d5
--- /dev/null
+++ b/libc/test/src/math/roundevenf_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for roundevenf ------------------------------------------===//
+//
+// 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 "RoundEvenTest.h"
+
+#include "src/math/roundevenf.h"
+
+LIST_ROUNDEVEN_TESTS(float, LIBC_NAMESPACE::roundevenf)
diff --git a/libc/test/src/math/roundevenl_test.cpp b/libc/test/src/math/roundevenl_test.cpp
new file mode 100644
index 00000000000000..f4031bd65ec21c
--- /dev/null
+++ b/libc/test/src/math/roundevenl_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for roundevenl ------------------------------------------===//
+//
+// 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 "RoundEvenTest.h"
+
+#include "src/math/roundevenl.h"
+
+LIST_ROUNDEVEN_TESTS(long double, LIBC_NAMESPACE::roundevenl)
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 4ac1842cf5fae7..e9ff35577b9534 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -397,6 +397,62 @@ add_fp_unittest(
     libc.src.__support.FPUtil.fp_bits
 )
 
+add_fp_unittest(
+  roundeven_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    roundeven_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundeven
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  roundevenf_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    roundevenf_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundevenf
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  roundevenl_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    roundevenl_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundevenl
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  roundevenf128_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    roundevenf128_test.cpp
+  HDRS
+  RoundEvenTest.h
+  DEPENDS
+    libc.include.math
+    libc.src.math.roundevenf128
+    libc.src.__support.FPUtil.fp_bits
+)
+
 add_fp_unittest(
   lround_test
   SUITE
diff --git a/libc/test/src/math/smoke/RoundEvenTest.h b/libc/test/src/math/smoke/RoundEvenTest.h
new file mode 100644
index 00000000000000..107052fa0e2867
--- /dev/null
+++ b/libc/test/src/math/smoke/RoundEvenTest.h
@@ -0,0 +1,72 @@
+//===-- Utility class to test roundeven[f|l] --------------------*- 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_SMOKE_ROUNDEVENTEST_H
+#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDEVENTEST_H
+
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+#include "include/llvm-libc-macros/math-macros.h"
+
+template <typename T>
+class RoundEvenTest : public LIBC_NAMESPACE::testing::Test {
+
+  DECLARE_SPECIAL_CONSTANTS(T)
+
+public:
+  typedef T (*RoundEvenFunc)(T);
+
+  void testSpecialNumbers(RoundEvenFunc func) {
+    EXPECT_FP_EQ(zero, func(zero));
+    EXPECT_FP_EQ(neg_zero, func(neg_zero));
+
+    EXPECT_FP_EQ(inf, func(inf));
+    EXPECT_FP_EQ(neg_inf, func(neg_inf));
+
+    EXPECT...
[truncated]

@vinayakdsci
Copy link
Contributor Author

cc @lntue

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update libc/docs/c23.rst too!

@nickdesaulniers nickdesaulniers requested a review from lntue April 4, 2024 19:02
@vinayakdsci
Copy link
Contributor Author

vinayakdsci commented Apr 4, 2024

Please update libc/docs/c23.rst too!

I have to remove the asterisk in front of the function name, right? There is an asterisk in front of all the function names.

@nickdesaulniers
Copy link
Member

Please update libc/docs/c23.rst too!

I have to remove the asterisk in front of the function name, right? There is an asterisk in front of all the function names.

Just add |check| after the name. The asterisk is because I was too lazy to spell out all of the variants. This will all get cleaned up imminently anyways (once #87682 lands, we're going to start rewriting some documentation).

@vinayakdsci
Copy link
Contributor Author

Just add |check| after the name.

Done!

libc.src.math.roundeven
libc.src.math.roundevenf
libc.src.math.roundevenl
libc.src.math.roundevenf128
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move f128 variant down with other f128 functions where they are guarded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry! I somehow didn't notice that. Fixed now.

@vinayakdsci vinayakdsci force-pushed the libc-impl-roundeven branch from a4abd86 to 88f23de Compare April 4, 2024 21:06
@@ -351,6 +351,12 @@ class MPFRNumber {
return result;
}

MPFRNumber roundeven() const {
MPFRNumber result(*this);
mpfr_roundeven(result.value, value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you double check which version of MPFR adding mpfr_roundeven function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is present in 4.0.0, https://www.mpfr.org/mpfr-4.0.0/mpfr.pdf.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the version guard, and implement a replacement for mpfr_roundeven when it's not available, similar to

#if MPFR_VERSION_MAJOR > 4 || \

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented the replacement, but I am not sure if I should simply write MPFR_VERSION_MAJOR >= 4, or also specify the minor version. I went with the latter, but will change if required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just check MPFR_VERSION_MAJOR >= 4 should be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also factored out the common code from the version guard.

@vinayakdsci vinayakdsci requested a review from lntue April 5, 2024 04:39
@vinayakdsci vinayakdsci force-pushed the libc-impl-roundeven branch from 6ac1ea5 to cdf425a Compare April 5, 2024 05:04
Copy link
Contributor

@lntue lntue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this! I'll merge the patch later in the morning so that I can watch the bots.

@vinayakdsci
Copy link
Contributor Author

Thanks for adding this! I'll merge the patch later in the morning so that I can watch the bots.

Thanks a lot!

@lntue lntue merged commit 3b961d1 into llvm:main Apr 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants