[libc-commits] [libc] [libc][math][c23] Add C23 math functions ilogbf128, logbf128, and llogb(f|l|f128). (PR #82144)
via libc-commits
libc-commits at lists.llvm.org
Mon Feb 26 17:58:33 PST 2024
================
@@ -71,54 +71,79 @@ LIBC_INLINE T copysign(T x, T y) {
return xbits.get_val();
}
-template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int ilogb(T x) {
- // TODO: Raise appropriate floating point exceptions and set errno to the
- // an appropriate error value wherever relevant.
- FPBits<T> bits(x);
- if (bits.is_zero()) {
- return FP_ILOGB0;
- } else if (bits.is_nan()) {
- return FP_ILOGBNAN;
- } else if (bits.is_inf()) {
- return INT_MAX;
+template <typename T> struct IntLogbConstants;
+
+template <> struct IntLogbConstants<int> {
+ LIBC_INLINE_VAR static constexpr int FP_LOGB0 = FP_ILOGB0;
+ LIBC_INLINE_VAR static constexpr int FP_LOGBNAN = FP_ILOGBNAN;
+ LIBC_INLINE_VAR static constexpr int T_MAX = INT_MAX;
+ LIBC_INLINE_VAR static constexpr int T_MIN = INT_MIN;
+};
+
+template <> struct IntLogbConstants<long> {
+ LIBC_INLINE_VAR static constexpr long FP_LOGB0 = FP_ILOGB0;
+ LIBC_INLINE_VAR static constexpr long FP_LOGBNAN = FP_ILOGBNAN;
+ LIBC_INLINE_VAR static constexpr long T_MAX = LONG_MAX;
+ LIBC_INLINE_VAR static constexpr long T_MIN = LONG_MIN;
+};
+
+template <typename T, typename U>
+LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<U>, T>
+intlogb(U x) {
+ FPBits<U> bits(x);
+ if (LIBC_UNLIKELY(bits.is_zero() || bits.is_inf_or_nan())) {
+ set_errno_if_required(EDOM);
+ raise_except_if_required(FE_INVALID);
+
+ if (bits.is_zero())
+ return IntLogbConstants<T>::FP_LOGB0;
+ if (bits.is_nan())
+ return IntLogbConstants<T>::FP_LOGBNAN;
+ // bits is inf.
+ return IntLogbConstants<T>::T_MAX;
}
- NormalFloat<T> normal(bits);
+ DyadicFloat<FPBits<U>::STORAGE_LEN> normal(bits.get_val());
+ int exponent = normal.get_unbiased_exponent();
// The C standard does not specify the return value when an exponent is
// out of int range. However, XSI conformance required that INT_MAX or
// INT_MIN are returned.
// NOTE: It is highly unlikely that exponent will be out of int range as
// the exponent is only 15 bits wide even for the 128-bit floating point
// format.
- if (normal.exponent > INT_MAX)
- return INT_MAX;
- else if (normal.exponent < INT_MIN)
- return INT_MIN;
- else
- return normal.exponent;
+ if (LIBC_UNLIKELY(exponent > IntLogbConstants<T>::T_MAX ||
+ exponent < IntLogbConstants<T>::T_MIN)) {
+ set_errno_if_required(ERANGE);
+ raise_except_if_required(FE_INVALID);
+ return exponent ? IntLogbConstants<T>::T_MAX : IntLogbConstants<T>::T_MIN;
+ }
+
+ return static_cast<T>(exponent);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE T logb(T x) {
+LIBC_INLINE constexpr T logb(T x) {
FPBits<T> bits(x);
- if (bits.is_zero()) {
- // TODO(Floating point exception): Raise div-by-zero exception.
- // TODO(errno): POSIX requires setting errno to ERANGE.
- return FPBits<T>::inf(Sign::NEG).get_val();
- } else if (bits.is_nan()) {
- return x;
- } else if (bits.is_inf()) {
- // Return positive infinity.
+ if (LIBC_UNLIKELY(bits.is_zero() || bits.is_inf_or_nan())) {
+ if (bits.is_nan())
+ return x;
----------------
lntue wrote:
Since the test for `is_inf_or_nan()` almost the same as `is_nan()`, while the test for `is_inf()` is totally different, putting the `is_nan()` branch out intercepts with the separation of the single `LIKELY / UNLIKELY` pair, the generated codes are 10-15% worse than the current form.
https://github.com/llvm/llvm-project/pull/82144
More information about the libc-commits
mailing list