Skip to content

Commit 7fb3d29

Browse files
committed
[libc][math][c23] Add fmodl and fmodf128 math functions.
1 parent 0baef3b commit 7fb3d29

File tree

23 files changed

+317
-111
lines changed

23 files changed

+317
-111
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ set(TARGET_LIBM_ENTRYPOINTS
334334
libc.src.math.fminl
335335
libc.src.math.fmod
336336
libc.src.math.fmodf
337+
libc.src.math.fmodl
337338
libc.src.math.frexp
338339
libc.src.math.frexpf
339340
libc.src.math.frexpl
@@ -425,6 +426,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
425426
libc.src.math.floorf128
426427
libc.src.math.fmaxf128
427428
libc.src.math.fminf128
429+
libc.src.math.fmodf128
428430
libc.src.math.frexpf128
429431
libc.src.math.ilogbf128
430432
libc.src.math.ldexpf128

libc/config/linux/riscv/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ set(TARGET_LIBM_ENTRYPOINTS
342342
libc.src.math.fmaxl
343343
libc.src.math.fmod
344344
libc.src.math.fmodf
345+
libc.src.math.fmodl
345346
libc.src.math.frexp
346347
libc.src.math.frexpf
347348
libc.src.math.frexpl
@@ -433,6 +434,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
433434
libc.src.math.floorf128
434435
libc.src.math.fmaxf128
435436
libc.src.math.fminf128
437+
libc.src.math.fmodf128
436438
libc.src.math.frexpf128
437439
libc.src.math.ilogbf128
438440
libc.src.math.ldexpf128

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ set(TARGET_LIBM_ENTRYPOINTS
370370
libc.src.math.fmaxl
371371
libc.src.math.fmod
372372
libc.src.math.fmodf
373+
libc.src.math.fmodl
373374
libc.src.math.frexp
374375
libc.src.math.frexpf
375376
libc.src.math.frexpl
@@ -463,6 +464,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
463464
libc.src.math.floorf128
464465
libc.src.math.fmaxf128
465466
libc.src.math.fminf128
467+
libc.src.math.fmodf128
466468
libc.src.math.frexpf128
467469
libc.src.math.ilogbf128
468470
libc.src.math.ldexpf128

libc/config/windows/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ set(TARGET_LIBM_ENTRYPOINTS
155155
libc.src.math.fmaxl
156156
libc.src.math.fmod
157157
libc.src.math.fmodf
158+
libc.src.math.fmodl
158159
libc.src.math.frexp
159160
libc.src.math.frexpf
160161
libc.src.math.frexpl

libc/docs/math/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ Basic Operations
169169
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
170170
| fmodf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
171171
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
172-
| fmodl | | | | | | | | | | | | |
172+
| fmodl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
173+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
174+
| fmodf128 | |check| | |check| | | |check| | | | | | | | | |
173175
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
174176
| frexp | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
175177
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+

libc/spec/stdc.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,9 @@ def StdC : StandardSpec<"stdc"> {
405405
FunctionSpec<"fmaf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>, ArgSpec<FloatType>]>,
406406

407407
FunctionSpec<"fmod", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
408-
409408
FunctionSpec<"fmodf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
409+
FunctionSpec<"fmodl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
410+
GuardedFunctionSpec<"fmodf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
410411

411412
FunctionSpec<"frexp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntPtr>]>,
412413
FunctionSpec<"frexpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntPtr>]>,

libc/src/__support/FPUtil/FPBits.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
640640
using UP::EXP_MASK;
641641
using UP::FRACTION_MASK;
642642
using UP::SIG_LEN;
643+
using UP::SIG_MASK;
643644
using UP::SIGN_MASK;
644645
LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =
645646
(1 << UP::EXP_LEN) - 1;
@@ -729,6 +730,9 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
729730
bits = UP::merge(bits, mantVal, FRACTION_MASK);
730731
}
731732

733+
LIBC_INLINE constexpr void set_significand(StorageType sigVal) {
734+
bits = UP::merge(bits, sigVal, SIG_MASK);
735+
}
732736
// Unsafe function to create a floating point representation.
733737
// It simply packs the sign, biased exponent and mantissa values without
734738
// checking bound nor normalization.
@@ -755,20 +759,19 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
755759
// 4) "number" zero value is not processed correctly.
756760
// 5) Number is unsigned, so the result can be only positive.
757761
LIBC_INLINE static constexpr RetT make_value(StorageType number, int ep) {
758-
static_assert(fp_type != FPType::X86_Binary80,
759-
"This function is not tested for X86 Extended Precision");
760-
FPRepImpl result;
761-
// offset: +1 for sign, but -1 for implicit first bit
762-
int lz = cpp::countl_zero(number) - UP::EXP_LEN;
762+
FPRepImpl result(0);
763+
int lz =
764+
UP::FRACTION_LEN + 1 - (UP::STORAGE_LEN - cpp::countl_zero(number));
765+
763766
number <<= lz;
764767
ep -= lz;
765768

766769
if (LIBC_LIKELY(ep >= 0)) {
767770
// Implicit number bit will be removed by mask
768-
result.set_mantissa(number);
771+
result.set_significand(number);
769772
result.set_biased_exponent(ep + 1);
770773
} else {
771-
result.set_mantissa(number >> -ep);
774+
result.set_significand(number >> -ep);
772775
}
773776
return RetT(result.uintval());
774777
}

libc/src/__support/FPUtil/generic/FMod.h

Lines changed: 64 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -117,63 +117,9 @@ namespace generic {
117117
// be implemented in another handler.
118118
// Signaling NaN converted to quiet NaN with FE_INVALID exception.
119119
// https://www.open-std.org/JTC1/SC22/WG14/www/docs/n1011.htm
120-
template <typename T> struct FModExceptionalInputHandler {
121-
122-
static_assert(cpp::is_floating_point_v<T>,
123-
"FModCStandardWrapper instantiated with invalid type.");
124-
125-
LIBC_INLINE static bool pre_check(T x, T y, T &out) {
126-
using FPB = fputil::FPBits<T>;
127-
const T quiet_nan = FPB::quiet_nan().get_val();
128-
FPB sx(x), sy(y);
129-
if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
130-
!sx.is_inf_or_nan())) {
131-
return false;
132-
}
133-
134-
if (sx.is_nan() || sy.is_nan()) {
135-
if ((sx.is_nan() && !sx.is_quiet_nan()) ||
136-
(sy.is_nan() && !sy.is_quiet_nan()))
137-
fputil::raise_except_if_required(FE_INVALID);
138-
out = quiet_nan;
139-
return true;
140-
}
141-
142-
if (sx.is_inf() || sy.is_zero()) {
143-
fputil::raise_except_if_required(FE_INVALID);
144-
fputil::set_errno_if_required(EDOM);
145-
out = quiet_nan;
146-
return true;
147-
}
148-
149-
if (sy.is_inf()) {
150-
out = x;
151-
return true;
152-
}
153-
154-
// case where x == 0
155-
out = x;
156-
return true;
157-
}
158-
};
159-
160-
template <typename T> struct FModFastMathWrapper {
161-
162-
static_assert(cpp::is_floating_point_v<T>,
163-
"FModFastMathWrapper instantiated with invalid type.");
164-
165-
static bool pre_check(T, T, T &) { return false; }
166-
};
167-
168-
template <typename T> class FModDivisionSimpleHelper {
169-
private:
170-
using StorageType = typename FPBits<T>::StorageType;
171-
172-
public:
173-
LIBC_INLINE constexpr static StorageType execute(int exp_diff,
174-
int sides_zeroes_count,
175-
StorageType m_x,
176-
StorageType m_y) {
120+
template <typename T> struct FModDivisionSimpleHelper {
121+
LIBC_INLINE constexpr static T execute(int exp_diff, int sides_zeroes_count,
122+
T m_x, T m_y) {
177123
while (exp_diff > sides_zeroes_count) {
178124
exp_diff -= sides_zeroes_count;
179125
m_x <<= sides_zeroes_count;
@@ -185,28 +131,21 @@ template <typename T> class FModDivisionSimpleHelper {
185131
}
186132
};
187133

188-
template <typename T> class FModDivisionInvMultHelper {
189-
private:
190-
using FPB = FPBits<T>;
191-
using StorageType = typename FPB::StorageType;
192-
193-
public:
194-
LIBC_INLINE constexpr static StorageType execute(int exp_diff,
195-
int sides_zeroes_count,
196-
StorageType m_x,
197-
StorageType m_y) {
134+
template <typename T> struct FModDivisionInvMultHelper {
135+
LIBC_INLINE constexpr static T execute(int exp_diff, int sides_zeroes_count,
136+
T m_x, T m_y) {
137+
constexpr int LENGTH = sizeof(T) * CHAR_BIT;
198138
if (exp_diff > sides_zeroes_count) {
199-
StorageType inv_hy = (cpp::numeric_limits<StorageType>::max() / m_y);
139+
T inv_hy = (cpp::numeric_limits<T>::max() / m_y);
200140
while (exp_diff > sides_zeroes_count) {
201141
exp_diff -= sides_zeroes_count;
202-
StorageType hd =
203-
(m_x * inv_hy) >> (FPB::TOTAL_LEN - sides_zeroes_count);
142+
T hd = (m_x * inv_hy) >> (LENGTH - sides_zeroes_count);
204143
m_x <<= sides_zeroes_count;
205144
m_x -= hd * m_y;
206145
while (LIBC_UNLIKELY(m_x > m_y))
207146
m_x -= m_y;
208147
}
209-
StorageType hd = (m_x * inv_hy) >> (FPB::TOTAL_LEN - exp_diff);
148+
T hd = (m_x * inv_hy) >> (LENGTH - exp_diff);
210149
m_x <<= exp_diff;
211150
m_x -= hd * m_y;
212151
while (LIBC_UNLIKELY(m_x > m_y))
@@ -219,22 +158,57 @@ template <typename T> class FModDivisionInvMultHelper {
219158
}
220159
};
221160

222-
template <typename T, class Wrapper = FModExceptionalInputHandler<T>,
223-
class DivisionHelper = FModDivisionSimpleHelper<T>>
161+
template <typename T, typename U = typename FPBits<T>::StorageType,
162+
typename DivisionHelper = FModDivisionSimpleHelper<U>>
224163
class FMod {
225-
static_assert(cpp::is_floating_point_v<T>,
164+
static_assert(cpp::is_floating_point_v<T> && cpp::is_unsigned_v<U> &&
165+
(sizeof(U) * CHAR_BIT > FPBits<T>::FRACTION_LEN),
226166
"FMod instantiated with invalid type.");
227167

228168
private:
229169
using FPB = FPBits<T>;
230170
using StorageType = typename FPB::StorageType;
231171

172+
LIBC_INLINE static bool pre_check(T x, T y, T &out) {
173+
using FPB = fputil::FPBits<T>;
174+
const T quiet_nan = FPB::quiet_nan().get_val();
175+
FPB sx(x), sy(y);
176+
if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
177+
!sx.is_inf_or_nan())) {
178+
return false;
179+
}
180+
181+
if (sx.is_nan() || sy.is_nan()) {
182+
if ((sx.is_nan() && !sx.is_quiet_nan()) ||
183+
(sy.is_nan() && !sy.is_quiet_nan()))
184+
fputil::raise_except_if_required(FE_INVALID);
185+
out = quiet_nan;
186+
return true;
187+
}
188+
189+
if (sx.is_inf() || sy.is_zero()) {
190+
fputil::raise_except_if_required(FE_INVALID);
191+
fputil::set_errno_if_required(EDOM);
192+
out = quiet_nan;
193+
return true;
194+
}
195+
196+
if (sy.is_inf()) {
197+
out = x;
198+
return true;
199+
}
200+
201+
// case where x == 0
202+
out = x;
203+
return true;
204+
}
205+
232206
LIBC_INLINE static constexpr FPB eval_internal(FPB sx, FPB sy) {
233207

234208
if (LIBC_LIKELY(sx.uintval() <= sy.uintval())) {
235209
if (sx.uintval() < sy.uintval())
236210
return sx; // |x|<|y| return x
237-
return FPB(FPB::zero()); // |x|=|y| return 0.0
211+
return FPB::zero(); // |x|=|y| return 0.0
238212
}
239213

240214
int e_x = sx.get_biased_exponent();
@@ -247,27 +221,29 @@ class FMod {
247221
StorageType m_y = sy.get_explicit_mantissa();
248222
StorageType d = (e_x == e_y) ? (m_x - m_y) : (m_x << (e_x - e_y)) % m_y;
249223
if (d == 0)
250-
return FPB(FPB::zero());
224+
return FPB::zero();
251225
// iy - 1 because of "zero power" for number with power 1
252226
return FPB::make_value(d, e_y - 1);
253227
}
254-
/* Both subnormal special case. */
228+
// Both subnormal special case.
255229
if (LIBC_UNLIKELY(e_x == 0 && e_y == 0)) {
256230
FPB d;
257231
d.set_mantissa(sx.uintval() % sy.uintval());
258232
return d;
259233
}
260234

261235
// Note that hx is not subnormal by conditions above.
262-
StorageType m_x = sx.get_explicit_mantissa();
236+
U m_x = static_cast<U>(sx.get_explicit_mantissa());
263237
e_x--;
264238

265-
StorageType m_y = sy.get_explicit_mantissa();
266-
int lead_zeros_m_y = FPB::EXP_LEN;
239+
U m_y = static_cast<U>(sy.get_explicit_mantissa());
240+
constexpr int DEFAULT_LEAD_ZEROS =
241+
sizeof(U) * CHAR_BIT - FPB::FRACTION_LEN - 1;
242+
int lead_zeros_m_y = DEFAULT_LEAD_ZEROS;
267243
if (LIBC_LIKELY(e_y > 0)) {
268244
e_y--;
269245
} else {
270-
m_y = sy.get_mantissa();
246+
m_y = static_cast<U>(sy.get_mantissa());
271247
lead_zeros_m_y = cpp::countl_zero(m_y);
272248
}
273249

@@ -286,26 +262,27 @@ class FMod {
286262

287263
{
288264
// Shift hx left until the end or n = 0
289-
int left_shift = exp_diff < int(FPB::EXP_LEN) ? exp_diff : FPB::EXP_LEN;
265+
int left_shift =
266+
exp_diff < DEFAULT_LEAD_ZEROS ? exp_diff : DEFAULT_LEAD_ZEROS;
290267
m_x <<= left_shift;
291268
exp_diff -= left_shift;
292269
}
293270

294271
m_x %= m_y;
295272
if (LIBC_UNLIKELY(m_x == 0))
296-
return FPB(FPB::zero());
273+
return FPB::zero();
297274

298275
if (exp_diff == 0)
299-
return FPB::make_value(m_x, e_y);
276+
return FPB::make_value(static_cast<StorageType>(m_x), e_y);
300277

301-
/* hx next can't be 0, because hx < hy, hy % 2 == 1 hx * 2^i % hy != 0 */
278+
// hx next can't be 0, because hx < hy, hy % 2 == 1 hx * 2^i % hy != 0
302279
m_x = DivisionHelper::execute(exp_diff, sides_zeroes_count, m_x, m_y);
303-
return FPB::make_value(m_x, e_y);
280+
return FPB::make_value(static_cast<StorageType>(m_x), e_y);
304281
}
305282

306283
public:
307284
LIBC_INLINE static T eval(T x, T y) {
308-
if (T out; Wrapper::pre_check(x, y, out))
285+
if (T out; LIBC_UNLIKELY(pre_check(x, y, out)))
309286
return out;
310287
FPB sx(x), sy(y);
311288
Sign sign = sx.sign();

libc/src/math/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ add_math_entrypoint_object(fminf128)
119119

120120
add_math_entrypoint_object(fmod)
121121
add_math_entrypoint_object(fmodf)
122+
add_math_entrypoint_object(fmodl)
123+
add_math_entrypoint_object(fmodf128)
122124

123125
add_math_entrypoint_object(frexp)
124126
add_math_entrypoint_object(frexpf)

libc/src/math/fmodf128.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for fmodf128 ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_FMODF128_H
10+
#define LLVM_LIBC_SRC_MATH_FMODF128_H
11+
12+
#include "src/__support/macros/properties/types.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
float128 fmodf128(float128 x, float128 y);
17+
18+
} // namespace LIBC_NAMESPACE
19+
20+
#endif // LLVM_LIBC_SRC_MATH_FMODF128_H

0 commit comments

Comments
 (0)