[libc-commits] [libc] [libc][math][c23] Add fmodl and fmodf128 math functions. (PR #84600)
via libc-commits
libc-commits at lists.llvm.org
Mon Mar 11 12:57:37 PDT 2024
https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/84600
>From 733d28ee1ab757bfe02848f82ef4c4abc40159db Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue at google.com>
Date: Fri, 8 Mar 2024 23:16:58 -0500
Subject: [PATCH 1/4] [libc][math][c23] Add fmodl and fmodf128 math functions.
---
libc/config/linux/aarch64/entrypoints.txt | 2 +
libc/config/linux/riscv/entrypoints.txt | 2 +
libc/config/linux/x86_64/entrypoints.txt | 2 +
libc/config/windows/entrypoints.txt | 1 +
libc/docs/math/index.rst | 4 +-
libc/spec/stdc.td | 3 +-
libc/src/__support/FPUtil/FPBits.h | 17 +-
libc/src/__support/FPUtil/generic/FMod.h | 151 ++++++++----------
libc/src/math/CMakeLists.txt | 2 +
libc/src/math/fmodf128.h | 20 +++
libc/src/math/fmodl.h | 18 +++
libc/src/math/generic/CMakeLists.txt | 27 +++-
libc/src/math/generic/fmodf.cpp | 2 +-
libc/src/math/generic/fmodf128.cpp | 19 +++
libc/src/math/generic/fmodl.cpp | 19 +++
.../exhaustive/fmod_generic_impl_test.cpp | 9 +-
.../BinaryOpSingleOutputPerf.h | 2 +-
.../math/performance_testing/CMakeLists.txt | 22 +++
.../performance_testing/fmodf128_perf.cpp | 16 ++
.../math/performance_testing/fmodl_perf.cpp | 16 ++
libc/test/src/math/smoke/CMakeLists.txt | 36 +++++
libc/test/src/math/smoke/fmodf128_test.cpp | 13 ++
libc/test/src/math/smoke/fmodl_test.cpp | 13 ++
23 files changed, 311 insertions(+), 105 deletions(-)
create mode 100644 libc/src/math/fmodf128.h
create mode 100644 libc/src/math/fmodl.h
create mode 100644 libc/src/math/generic/fmodf128.cpp
create mode 100644 libc/src/math/generic/fmodl.cpp
create mode 100644 libc/test/src/math/performance_testing/fmodf128_perf.cpp
create mode 100644 libc/test/src/math/performance_testing/fmodl_perf.cpp
create mode 100644 libc/test/src/math/smoke/fmodf128_test.cpp
create mode 100644 libc/test/src/math/smoke/fmodl_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b447b5dfe0989e..1656973cb27c8a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -335,6 +335,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.fminl
libc.src.math.fmod
libc.src.math.fmodf
+ libc.src.math.fmodl
libc.src.math.frexp
libc.src.math.frexpf
libc.src.math.frexpl
@@ -426,6 +427,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
libc.src.math.floorf128
libc.src.math.fmaxf128
libc.src.math.fminf128
+ libc.src.math.fmodf128
libc.src.math.frexpf128
libc.src.math.ilogbf128
libc.src.math.ldexpf128
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5175b14adf2e74..07d1acfcfe079d 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -343,6 +343,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.fmaxl
libc.src.math.fmod
libc.src.math.fmodf
+ libc.src.math.fmodl
libc.src.math.frexp
libc.src.math.frexpf
libc.src.math.frexpl
@@ -434,6 +435,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
libc.src.math.floorf128
libc.src.math.fmaxf128
libc.src.math.fminf128
+ libc.src.math.fmodf128
libc.src.math.frexpf128
libc.src.math.ilogbf128
libc.src.math.ldexpf128
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b8bec14a3d2a6d..e0324061a9c78c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -376,6 +376,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.fmaxl
libc.src.math.fmod
libc.src.math.fmodf
+ libc.src.math.fmodl
libc.src.math.frexp
libc.src.math.frexpf
libc.src.math.frexpl
@@ -469,6 +470,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
libc.src.math.floorf128
libc.src.math.fmaxf128
libc.src.math.fminf128
+ libc.src.math.fmodf128
libc.src.math.frexpf128
libc.src.math.ilogbf128
libc.src.math.ldexpf128
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 1c9ed7bbcfed69..d6227a427afe2b 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -155,6 +155,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.fmaxl
libc.src.math.fmod
libc.src.math.fmodf
+ libc.src.math.fmodl
libc.src.math.frexp
libc.src.math.frexpf
libc.src.math.frexpl
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index b22ed5127c179e..6984b785125f1a 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -169,7 +169,9 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fmodf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
-| fmodl | | | | | | | | | | | | |
+| fmodl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fmodf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| frexp | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index d91f5c1f723345..1f14fe758130e8 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -405,8 +405,9 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"fmaf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>, ArgSpec<FloatType>]>,
FunctionSpec<"fmod", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
-
FunctionSpec<"fmodf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
+ FunctionSpec<"fmodl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
+ GuardedFunctionSpec<"fmodf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
FunctionSpec<"frexp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntPtr>]>,
FunctionSpec<"frexpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntPtr>]>,
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 7b3882dde1b72b..b06b3f7b73959a 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -640,6 +640,7 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
using UP::EXP_MASK;
using UP::FRACTION_MASK;
using UP::SIG_LEN;
+ using UP::SIG_MASK;
using UP::SIGN_MASK;
LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =
(1 << UP::EXP_LEN) - 1;
@@ -729,6 +730,9 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
bits = UP::merge(bits, mantVal, FRACTION_MASK);
}
+ LIBC_INLINE constexpr void set_significand(StorageType sigVal) {
+ bits = UP::merge(bits, sigVal, SIG_MASK);
+ }
// Unsafe function to create a floating point representation.
// It simply packs the sign, biased exponent and mantissa values without
// checking bound nor normalization.
@@ -755,20 +759,19 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
// 4) "number" zero value is not processed correctly.
// 5) Number is unsigned, so the result can be only positive.
LIBC_INLINE static constexpr RetT make_value(StorageType number, int ep) {
- static_assert(fp_type != FPType::X86_Binary80,
- "This function is not tested for X86 Extended Precision");
- FPRepImpl result;
- // offset: +1 for sign, but -1 for implicit first bit
- int lz = cpp::countl_zero(number) - UP::EXP_LEN;
+ FPRepImpl result(0);
+ int lz =
+ UP::FRACTION_LEN + 1 - (UP::STORAGE_LEN - cpp::countl_zero(number));
+
number <<= lz;
ep -= lz;
if (LIBC_LIKELY(ep >= 0)) {
// Implicit number bit will be removed by mask
- result.set_mantissa(number);
+ result.set_significand(number);
result.set_biased_exponent(ep + 1);
} else {
- result.set_mantissa(number >> -ep);
+ result.set_significand(number >> -ep);
}
return RetT(result.uintval());
}
diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h
index 2d31290bc4bc2c..2cbbc5932345c3 100644
--- a/libc/src/__support/FPUtil/generic/FMod.h
+++ b/libc/src/__support/FPUtil/generic/FMod.h
@@ -117,63 +117,9 @@ namespace generic {
// be implemented in another handler.
// Signaling NaN converted to quiet NaN with FE_INVALID exception.
// https://www.open-std.org/JTC1/SC22/WG14/www/docs/n1011.htm
-template <typename T> struct FModExceptionalInputHandler {
-
- static_assert(cpp::is_floating_point_v<T>,
- "FModCStandardWrapper instantiated with invalid type.");
-
- LIBC_INLINE static bool pre_check(T x, T y, T &out) {
- using FPB = fputil::FPBits<T>;
- const T quiet_nan = FPB::quiet_nan().get_val();
- FPB sx(x), sy(y);
- if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
- !sx.is_inf_or_nan())) {
- return false;
- }
-
- if (sx.is_nan() || sy.is_nan()) {
- if ((sx.is_nan() && !sx.is_quiet_nan()) ||
- (sy.is_nan() && !sy.is_quiet_nan()))
- fputil::raise_except_if_required(FE_INVALID);
- out = quiet_nan;
- return true;
- }
-
- if (sx.is_inf() || sy.is_zero()) {
- fputil::raise_except_if_required(FE_INVALID);
- fputil::set_errno_if_required(EDOM);
- out = quiet_nan;
- return true;
- }
-
- if (sy.is_inf()) {
- out = x;
- return true;
- }
-
- // case where x == 0
- out = x;
- return true;
- }
-};
-
-template <typename T> struct FModFastMathWrapper {
-
- static_assert(cpp::is_floating_point_v<T>,
- "FModFastMathWrapper instantiated with invalid type.");
-
- static bool pre_check(T, T, T &) { return false; }
-};
-
-template <typename T> class FModDivisionSimpleHelper {
-private:
- using StorageType = typename FPBits<T>::StorageType;
-
-public:
- LIBC_INLINE constexpr static StorageType execute(int exp_diff,
- int sides_zeroes_count,
- StorageType m_x,
- StorageType m_y) {
+template <typename T> struct FModDivisionSimpleHelper {
+ LIBC_INLINE constexpr static T execute(int exp_diff, int sides_zeroes_count,
+ T m_x, T m_y) {
while (exp_diff > sides_zeroes_count) {
exp_diff -= sides_zeroes_count;
m_x <<= sides_zeroes_count;
@@ -185,28 +131,21 @@ template <typename T> class FModDivisionSimpleHelper {
}
};
-template <typename T> class FModDivisionInvMultHelper {
-private:
- using FPB = FPBits<T>;
- using StorageType = typename FPB::StorageType;
-
-public:
- LIBC_INLINE constexpr static StorageType execute(int exp_diff,
- int sides_zeroes_count,
- StorageType m_x,
- StorageType m_y) {
+template <typename T> struct FModDivisionInvMultHelper {
+ LIBC_INLINE constexpr static T execute(int exp_diff, int sides_zeroes_count,
+ T m_x, T m_y) {
+ constexpr int LENGTH = sizeof(T) * CHAR_BIT;
if (exp_diff > sides_zeroes_count) {
- StorageType inv_hy = (cpp::numeric_limits<StorageType>::max() / m_y);
+ T inv_hy = (cpp::numeric_limits<T>::max() / m_y);
while (exp_diff > sides_zeroes_count) {
exp_diff -= sides_zeroes_count;
- StorageType hd =
- (m_x * inv_hy) >> (FPB::TOTAL_LEN - sides_zeroes_count);
+ T hd = (m_x * inv_hy) >> (LENGTH - sides_zeroes_count);
m_x <<= sides_zeroes_count;
m_x -= hd * m_y;
while (LIBC_UNLIKELY(m_x > m_y))
m_x -= m_y;
}
- StorageType hd = (m_x * inv_hy) >> (FPB::TOTAL_LEN - exp_diff);
+ T hd = (m_x * inv_hy) >> (LENGTH - exp_diff);
m_x <<= exp_diff;
m_x -= hd * m_y;
while (LIBC_UNLIKELY(m_x > m_y))
@@ -219,22 +158,57 @@ template <typename T> class FModDivisionInvMultHelper {
}
};
-template <typename T, class Wrapper = FModExceptionalInputHandler<T>,
- class DivisionHelper = FModDivisionSimpleHelper<T>>
+template <typename T, typename U = typename FPBits<T>::StorageType,
+ typename DivisionHelper = FModDivisionSimpleHelper<U>>
class FMod {
- static_assert(cpp::is_floating_point_v<T>,
+ static_assert(cpp::is_floating_point_v<T> && cpp::is_unsigned_v<U> &&
+ (sizeof(U) * CHAR_BIT > FPBits<T>::FRACTION_LEN),
"FMod instantiated with invalid type.");
private:
using FPB = FPBits<T>;
using StorageType = typename FPB::StorageType;
+ LIBC_INLINE static bool pre_check(T x, T y, T &out) {
+ using FPB = fputil::FPBits<T>;
+ const T quiet_nan = FPB::quiet_nan().get_val();
+ FPB sx(x), sy(y);
+ if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
+ !sx.is_inf_or_nan())) {
+ return false;
+ }
+
+ if (sx.is_nan() || sy.is_nan()) {
+ if ((sx.is_nan() && !sx.is_quiet_nan()) ||
+ (sy.is_nan() && !sy.is_quiet_nan()))
+ fputil::raise_except_if_required(FE_INVALID);
+ out = quiet_nan;
+ return true;
+ }
+
+ if (sx.is_inf() || sy.is_zero()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ fputil::set_errno_if_required(EDOM);
+ out = quiet_nan;
+ return true;
+ }
+
+ if (sy.is_inf()) {
+ out = x;
+ return true;
+ }
+
+ // case where x == 0
+ out = x;
+ return true;
+ }
+
LIBC_INLINE static constexpr FPB eval_internal(FPB sx, FPB sy) {
if (LIBC_LIKELY(sx.uintval() <= sy.uintval())) {
if (sx.uintval() < sy.uintval())
return sx; // |x|<|y| return x
- return FPB(FPB::zero()); // |x|=|y| return 0.0
+ return FPB::zero(); // |x|=|y| return 0.0
}
int e_x = sx.get_biased_exponent();
@@ -247,11 +221,11 @@ class FMod {
StorageType m_y = sy.get_explicit_mantissa();
StorageType d = (e_x == e_y) ? (m_x - m_y) : (m_x << (e_x - e_y)) % m_y;
if (d == 0)
- return FPB(FPB::zero());
+ return FPB::zero();
// iy - 1 because of "zero power" for number with power 1
return FPB::make_value(d, e_y - 1);
}
- /* Both subnormal special case. */
+ // Both subnormal special case.
if (LIBC_UNLIKELY(e_x == 0 && e_y == 0)) {
FPB d;
d.set_mantissa(sx.uintval() % sy.uintval());
@@ -259,15 +233,17 @@ class FMod {
}
// Note that hx is not subnormal by conditions above.
- StorageType m_x = sx.get_explicit_mantissa();
+ U m_x = static_cast<U>(sx.get_explicit_mantissa());
e_x--;
- StorageType m_y = sy.get_explicit_mantissa();
- int lead_zeros_m_y = FPB::EXP_LEN;
+ U m_y = static_cast<U>(sy.get_explicit_mantissa());
+ constexpr int DEFAULT_LEAD_ZEROS =
+ sizeof(U) * CHAR_BIT - FPB::FRACTION_LEN - 1;
+ int lead_zeros_m_y = DEFAULT_LEAD_ZEROS;
if (LIBC_LIKELY(e_y > 0)) {
e_y--;
} else {
- m_y = sy.get_mantissa();
+ m_y = static_cast<U>(sy.get_mantissa());
lead_zeros_m_y = cpp::countl_zero(m_y);
}
@@ -286,26 +262,27 @@ class FMod {
{
// Shift hx left until the end or n = 0
- int left_shift = exp_diff < int(FPB::EXP_LEN) ? exp_diff : FPB::EXP_LEN;
+ int left_shift =
+ exp_diff < DEFAULT_LEAD_ZEROS ? exp_diff : DEFAULT_LEAD_ZEROS;
m_x <<= left_shift;
exp_diff -= left_shift;
}
m_x %= m_y;
if (LIBC_UNLIKELY(m_x == 0))
- return FPB(FPB::zero());
+ return FPB::zero();
if (exp_diff == 0)
- return FPB::make_value(m_x, e_y);
+ return FPB::make_value(static_cast<StorageType>(m_x), e_y);
- /* hx next can't be 0, because hx < hy, hy % 2 == 1 hx * 2^i % hy != 0 */
+ // hx next can't be 0, because hx < hy, hy % 2 == 1 hx * 2^i % hy != 0
m_x = DivisionHelper::execute(exp_diff, sides_zeroes_count, m_x, m_y);
- return FPB::make_value(m_x, e_y);
+ return FPB::make_value(static_cast<StorageType>(m_x), e_y);
}
public:
LIBC_INLINE static T eval(T x, T y) {
- if (T out; Wrapper::pre_check(x, y, out))
+ if (T out; LIBC_UNLIKELY(pre_check(x, y, out)))
return out;
FPB sx(x), sy(y);
Sign sign = sx.sign();
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 6c06d383ec2b04..bba02aa78a2313 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -119,6 +119,8 @@ add_math_entrypoint_object(fminf128)
add_math_entrypoint_object(fmod)
add_math_entrypoint_object(fmodf)
+add_math_entrypoint_object(fmodl)
+add_math_entrypoint_object(fmodf128)
add_math_entrypoint_object(frexp)
add_math_entrypoint_object(frexpf)
diff --git a/libc/src/math/fmodf128.h b/libc/src/math/fmodf128.h
new file mode 100644
index 00000000000000..b3242705f025ee
--- /dev/null
+++ b/libc/src/math/fmodf128.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for fmodf128 ----------------------*- 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_FMODF128_H
+#define LLVM_LIBC_SRC_MATH_FMODF128_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float128 fmodf128(float128 x, float128 y);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FMODF128_H
diff --git a/libc/src/math/fmodl.h b/libc/src/math/fmodl.h
new file mode 100644
index 00000000000000..f259ddb238a8e4
--- /dev/null
+++ b/libc/src/math/fmodl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for fmodl -------------------------*- 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_FMODL_H
+#define LLVM_LIBC_SRC_MATH_FMODL_H
+
+namespace LIBC_NAMESPACE {
+
+long double fmodl(long double x, long double y);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FMODL_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 933a05dad157c9..bc4e9b34cfc2f6 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -1859,7 +1859,6 @@ add_entrypoint_object(
HDRS
../fmod.h
DEPENDS
- libc.include.math
libc.src.__support.FPUtil.generic.fmod
COMPILE_OPTIONS
-O3
@@ -1872,7 +1871,31 @@ add_entrypoint_object(
HDRS
../fmodf.h
DEPENDS
- libc.include.math
+ libc.src.__support.FPUtil.generic.fmod
+ COMPILE_OPTIONS
+ -O3
+)
+
+add_entrypoint_object(
+ fmodl
+ SRCS
+ fmodl.cpp
+ HDRS
+ ../fmodl.h
+ DEPENDS
+ libc.src.__support.FPUtil.generic.fmod
+ COMPILE_OPTIONS
+ -O3
+)
+
+add_entrypoint_object(
+ fmodf128
+ SRCS
+ fmodf128.cpp
+ HDRS
+ ../fmodf128.h
+ DEPENDS
+ libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.generic.fmod
COMPILE_OPTIONS
-O3
diff --git a/libc/src/math/generic/fmodf.cpp b/libc/src/math/generic/fmodf.cpp
index 7a29ff1f18d319..9a9e46e29b4662 100644
--- a/libc/src/math/generic/fmodf.cpp
+++ b/libc/src/math/generic/fmodf.cpp
@@ -13,7 +13,7 @@
namespace LIBC_NAMESPACE {
LLVM_LIBC_FUNCTION(float, fmodf, (float x, float y)) {
- return fputil::generic::FMod<float>::eval(x, y);
+ return fputil::generic::FMod<float, uint64_t>::eval(x, y);
}
} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/fmodf128.cpp b/libc/src/math/generic/fmodf128.cpp
new file mode 100644
index 00000000000000..08a379702d889b
--- /dev/null
+++ b/libc/src/math/generic/fmodf128.cpp
@@ -0,0 +1,19 @@
+//===-- Single-precision fmodf128 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/fmodf128.h"
+#include "src/__support/FPUtil/generic/FMod.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float128, fmodf128, (float128 x, float128 y)) {
+ return fputil::generic::FMod<float128>::eval(x, y);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/math/generic/fmodl.cpp b/libc/src/math/generic/fmodl.cpp
new file mode 100644
index 00000000000000..23a37028905573
--- /dev/null
+++ b/libc/src/math/generic/fmodl.cpp
@@ -0,0 +1,19 @@
+//===-- Single-precision fmodl 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/fmodl.h"
+#include "src/__support/FPUtil/generic/FMod.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long double, fmodl, (long double x, long double y)) {
+ return fputil::generic::FMod<long double>::eval(x, y);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/test/src/math/exhaustive/fmod_generic_impl_test.cpp b/libc/test/src/math/exhaustive/fmod_generic_impl_test.cpp
index b47d24c54869bb..25a5e3898599ae 100644
--- a/libc/test/src/math/exhaustive/fmod_generic_impl_test.cpp
+++ b/libc/test/src/math/exhaustive/fmod_generic_impl_test.cpp
@@ -19,10 +19,11 @@ namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
template <typename T, bool InverseMultiplication>
class LlvmLibcFModTest : public LIBC_NAMESPACE::testing::Test {
+ using U = typename LIBC_NAMESPACE::fputil::FPBits<T>::StorageType;
using DivisionHelper = LIBC_NAMESPACE::cpp::conditional_t<
InverseMultiplication,
- LIBC_NAMESPACE::fputil::generic::FModDivisionInvMultHelper<T>,
- LIBC_NAMESPACE::fputil::generic::FModDivisionSimpleHelper<T>>;
+ LIBC_NAMESPACE::fputil::generic::FModDivisionInvMultHelper<U>,
+ LIBC_NAMESPACE::fputil::generic::FModDivisionSimpleHelper<U>>;
static constexpr std::array<T, 11> test_bases = {
T(0.0),
@@ -39,9 +40,7 @@ class LlvmLibcFModTest : public LIBC_NAMESPACE::testing::Test {
public:
void testExtensive() {
- using FMod = LIBC_NAMESPACE::fputil::generic::FMod<
- T, LIBC_NAMESPACE::fputil::generic::FModFastMathWrapper<T>,
- DivisionHelper>;
+ using FMod = LIBC_NAMESPACE::fputil::generic::FMod<T, U, DivisionHelper>;
using nl = std::numeric_limits<T>;
int min2 = nl::min_exponent - nl::digits - 5;
int max2 = nl::max_exponent + 3;
diff --git a/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h b/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
index 68d37b46b77c73..504d1be94b891c 100644
--- a/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
+++ b/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
@@ -86,7 +86,7 @@ template <typename T> class BinaryOpSingleOutputPerf {
"close to each other:\n";
run_perf_in_range(
myFunc, otherFunc, /* startingBit= */ FPBits(T(0x1.0p-10)).uintval(),
- /* endingBit= */ FPBits(T(0x1.0p+10)).uintval(), 10'000'001, log);
+ /* endingBit= */ FPBits(T(0x1.0p+10)).uintval(), 1'001'001, log);
}
static void run_diff(Func myFunc, Func otherFunc, const char *logFile) {
diff --git a/libc/test/src/math/performance_testing/CMakeLists.txt b/libc/test/src/math/performance_testing/CMakeLists.txt
index d20c2eb303a7cc..8205ec3fa1bec0 100644
--- a/libc/test/src/math/performance_testing/CMakeLists.txt
+++ b/libc/test/src/math/performance_testing/CMakeLists.txt
@@ -331,3 +331,25 @@ add_perf_binary(
COMPILE_OPTIONS
-fno-builtin
)
+
+add_diff_binary(
+ fmodl_perf
+ SRCS
+ fmodl_perf.cpp
+ DEPENDS
+ .single_input_single_output_diff
+ libc.src.math.fmodl
+ COMPILE_OPTIONS
+ -fno-builtin
+)
+
+add_diff_binary(
+ fmodf128_perf
+ SRCS
+ fmodf128_perf.cpp
+ DEPENDS
+ .single_input_single_output_diff
+ libc.src.math.fmodf128
+ COMPILE_OPTIONS
+ -fno-builtin
+)
diff --git a/libc/test/src/math/performance_testing/fmodf128_perf.cpp b/libc/test/src/math/performance_testing/fmodf128_perf.cpp
new file mode 100644
index 00000000000000..8165e9254dd561
--- /dev/null
+++ b/libc/test/src/math/performance_testing/fmodf128_perf.cpp
@@ -0,0 +1,16 @@
+//===-- Differential test for fmodf128 ------------------------------------===//
+//
+// 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 "BinaryOpSingleOutputDiff.h"
+
+#include "src/math/fmodf128.h"
+
+#include <math.h>
+
+BINARY_OP_SINGLE_OUTPUT_PERF(float, LIBC_NAMESPACE::fmodf128, ::fmodf128,
+ "fmodf128_perf.log")
diff --git a/libc/test/src/math/performance_testing/fmodl_perf.cpp b/libc/test/src/math/performance_testing/fmodl_perf.cpp
new file mode 100644
index 00000000000000..aefdf2d6b42fcf
--- /dev/null
+++ b/libc/test/src/math/performance_testing/fmodl_perf.cpp
@@ -0,0 +1,16 @@
+//===-- Differential test for fmodl ---------------------------------------===//
+//
+// 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 "BinaryOpSingleOutputDiff.h"
+
+#include "src/math/fmodl.h"
+
+#include <math.h>
+
+BINARY_OP_SINGLE_OUTPUT_PERF(long double, LIBC_NAMESPACE::fmodl, ::fmodl,
+ "fmodl_perf.log")
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 8d3871dd427aaa..d9be172056a833 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -1793,6 +1793,42 @@ add_fp_unittest(
UNIT_TEST_ONLY
)
+add_fp_unittest(
+ fmodl_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ fmodl_test.cpp
+ HDRS
+ FModTest.h
+ DEPENDS
+ libc.include.math
+ libc.src.errno.errno
+ libc.src.math.fmodl
+ libc.src.__support.FPUtil.basic_operations
+ libc.src.__support.FPUtil.nearest_integer_operations
+ # FIXME: Currently fails on the GPU build.
+ UNIT_TEST_ONLY
+)
+
+add_fp_unittest(
+ fmodf128_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ fmodf128_test.cpp
+ HDRS
+ FModTest.h
+ DEPENDS
+ libc.include.math
+ libc.src.errno.errno
+ libc.src.math.fmodf128
+ libc.src.__support.FPUtil.basic_operations
+ libc.src.__support.FPUtil.nearest_integer_operations
+ # FIXME: Currently fails on the GPU build.
+ UNIT_TEST_ONLY
+)
+
add_fp_unittest(
coshf_test
SUITE
diff --git a/libc/test/src/math/smoke/fmodf128_test.cpp b/libc/test/src/math/smoke/fmodf128_test.cpp
new file mode 100644
index 00000000000000..f75aadac843864
--- /dev/null
+++ b/libc/test/src/math/smoke/fmodf128_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for fmodf128 --------------------------------------------===//
+//
+// 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 "FModTest.h"
+
+#include "src/math/fmodf128.h"
+
+LIST_FMOD_TESTS(float128, LIBC_NAMESPACE::fmodf128)
diff --git a/libc/test/src/math/smoke/fmodl_test.cpp b/libc/test/src/math/smoke/fmodl_test.cpp
new file mode 100644
index 00000000000000..b69ed8ec85c84b
--- /dev/null
+++ b/libc/test/src/math/smoke/fmodl_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for fmodl -----------------------------------------------===//
+//
+// 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 "FModTest.h"
+
+#include "src/math/fmodl.h"
+
+LIST_FMOD_TESTS(long double, LIBC_NAMESPACE::fmodl)
>From c4a49c427f0bb639189f2bf50c8dcaf7314f6245 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue at google.com>
Date: Mon, 11 Mar 2024 11:58:19 -0400
Subject: [PATCH 2/4] Fix merge issue.
---
libc/test/src/math/performance_testing/CMakeLists.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libc/test/src/math/performance_testing/CMakeLists.txt b/libc/test/src/math/performance_testing/CMakeLists.txt
index 8205ec3fa1bec0..d1fb24e37f7286 100644
--- a/libc/test/src/math/performance_testing/CMakeLists.txt
+++ b/libc/test/src/math/performance_testing/CMakeLists.txt
@@ -332,7 +332,7 @@ add_perf_binary(
-fno-builtin
)
-add_diff_binary(
+add_perf_binary(
fmodl_perf
SRCS
fmodl_perf.cpp
@@ -343,7 +343,7 @@ add_diff_binary(
-fno-builtin
)
-add_diff_binary(
+add_perf_binary(
fmodf128_perf
SRCS
fmodf128_perf.cpp
>From 068479cd24b1bf606656264474b0e043587354ef Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue at google.com>
Date: Mon, 11 Mar 2024 15:48:34 -0400
Subject: [PATCH 3/4] Address comments.
---
libc/src/__support/FPUtil/generic/FMod.h | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h
index 2cbbc5932345c3..73594cd2b7d2ba 100644
--- a/libc/src/__support/FPUtil/generic/FMod.h
+++ b/libc/src/__support/FPUtil/generic/FMod.h
@@ -174,13 +174,11 @@ class FMod {
const T quiet_nan = FPB::quiet_nan().get_val();
FPB sx(x), sy(y);
if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
- !sx.is_inf_or_nan())) {
+ !sx.is_inf_or_nan()))
return false;
- }
if (sx.is_nan() || sy.is_nan()) {
- if ((sx.is_nan() && !sx.is_quiet_nan()) ||
- (sy.is_nan() && !sy.is_quiet_nan()))
+ if (sx.is_signalling_nan() || sy.is_signalling())
fputil::raise_except_if_required(FE_INVALID);
out = quiet_nan;
return true;
@@ -193,12 +191,6 @@ class FMod {
return true;
}
- if (sy.is_inf()) {
- out = x;
- return true;
- }
-
- // case where x == 0
out = x;
return true;
}
>From 6c902b48e375e02f53a084ce87d8157955236919 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue at google.com>
Date: Mon, 11 Mar 2024 15:57:12 -0400
Subject: [PATCH 4/4] Fix `is_signaling_nan` typos.
---
libc/src/__support/FPUtil/generic/FMod.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h
index 73594cd2b7d2ba..24fb264b779b73 100644
--- a/libc/src/__support/FPUtil/generic/FMod.h
+++ b/libc/src/__support/FPUtil/generic/FMod.h
@@ -178,7 +178,7 @@ class FMod {
return false;
if (sx.is_nan() || sy.is_nan()) {
- if (sx.is_signalling_nan() || sy.is_signalling())
+ if (sx.is_signaling_nan() || sy.is_signaling_nan())
fputil::raise_except_if_required(FE_INVALID);
out = quiet_nan;
return true;
More information about the libc-commits
mailing list