129 changes: 126 additions & 3 deletions libc/src/__support/FPUtil/dyadic_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@

#include "FEnvImpl.h"
#include "FPBits.h"
#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "multiply_add.h"
#include "rounding_mode.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/big_int.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/macros/properties/types.h"

#include <stddef.h>

Expand Down Expand Up @@ -97,13 +101,118 @@ template <size_t Bits> struct DyadicFloat {
return exponent + (Bits - 1);
}

// Assume that it is already normalized.
// Output is rounded correctly with respect to the current rounding mode.
template <typename T, bool ShouldSignalExceptions>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_floating_point_v<T> && (FPBits<T>::FRACTION_LEN < Bits), T>
generic_as() const {
using FPBits = FPBits<float16>;
using StorageType = typename FPBits::StorageType;

constexpr int EXTRA_FRACTION_LEN = Bits - 1 - FPBits::FRACTION_LEN;

if (mantissa == 0)
return FPBits::zero(sign).get_val();

int unbiased_exp = get_unbiased_exponent();

if (unbiased_exp + FPBits::EXP_BIAS >= FPBits::MAX_BIASED_EXPONENT) {
if constexpr (ShouldSignalExceptions) {
set_errno_if_required(ERANGE);
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
}

switch (quick_get_round()) {
case FE_TONEAREST:
return FPBits::inf(sign).get_val();
case FE_TOWARDZERO:
return FPBits::max_normal(sign).get_val();
case FE_DOWNWARD:
if (sign.is_pos())
return FPBits::max_normal(Sign::POS).get_val();
return FPBits::inf(Sign::NEG).get_val();
case FE_UPWARD:
if (sign.is_neg())
return FPBits::max_normal(Sign::NEG).get_val();
return FPBits::inf(Sign::POS).get_val();
default:
__builtin_unreachable();
}
}

StorageType out_biased_exp = 0;
StorageType out_mantissa = 0;
bool round = false;
bool sticky = false;
bool underflow = false;

if (unbiased_exp < -FPBits::EXP_BIAS - FPBits::FRACTION_LEN) {
sticky = true;
underflow = true;
} else if (unbiased_exp == -FPBits::EXP_BIAS - FPBits::FRACTION_LEN) {
round = true;
MantissaType sticky_mask = (MantissaType(1) << (Bits - 1)) - 1;
sticky = (mantissa & sticky_mask) != 0;
} else {
int extra_fraction_len = EXTRA_FRACTION_LEN;

if (unbiased_exp < 1 - FPBits::EXP_BIAS) {
underflow = true;
extra_fraction_len += 1 - FPBits::EXP_BIAS - unbiased_exp;
} else {
out_biased_exp =
static_cast<StorageType>(unbiased_exp + FPBits::EXP_BIAS);
}

MantissaType round_mask = MantissaType(1) << (extra_fraction_len - 1);
round = (mantissa & round_mask) != 0;
MantissaType sticky_mask = round_mask - 1;
sticky = (mantissa & sticky_mask) != 0;

out_mantissa = static_cast<StorageType>(mantissa >> extra_fraction_len);
}

bool lsb = (out_mantissa & 1) != 0;

StorageType result =
FPBits::create_value(sign, out_biased_exp, out_mantissa).uintval();

switch (quick_get_round()) {
case FE_TONEAREST:
if (round && (lsb || sticky))
++result;
break;
case FE_DOWNWARD:
if (sign.is_neg() && (round || sticky))
++result;
break;
case FE_UPWARD:
if (sign.is_pos() && (round || sticky))
++result;
break;
default:
break;
}

if (ShouldSignalExceptions && (round || sticky)) {
int excepts = FE_INEXACT;
if (FPBits(result).is_inf()) {
set_errno_if_required(ERANGE);
excepts |= FE_OVERFLOW;
} else if (underflow) {
set_errno_if_required(ERANGE);
excepts |= FE_UNDERFLOW;
}
raise_except_if_required(excepts);
}

return FPBits(result).get_val();
}

template <typename T, bool ShouldSignalExceptions,
typename = cpp::enable_if_t<cpp::is_floating_point_v<T> &&
(FPBits<T>::FRACTION_LEN < Bits),
void>>
LIBC_INLINE constexpr T as() const {
LIBC_INLINE constexpr T fast_as() const {
if (LIBC_UNLIKELY(mantissa.is_zero()))
return FPBits<T>::zero(sign).get_val();

Expand Down Expand Up @@ -224,6 +333,20 @@ template <size_t Bits> struct DyadicFloat {
return r;
}

// Assume that it is already normalized.
// Output is rounded correctly with respect to the current rounding mode.
template <typename T, bool ShouldSignalExceptions,
typename = cpp::enable_if_t<cpp::is_floating_point_v<T> &&
(FPBits<T>::FRACTION_LEN < Bits),
void>>
LIBC_INLINE constexpr T as() const {
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
if constexpr (cpp::is_same_v<T, float16>)
return generic_as<T, ShouldSignalExceptions>();
#endif
return fast_as<T, ShouldSignalExceptions>();
}

template <typename T,
typename = cpp::enable_if_t<cpp::is_floating_point_v<T> &&
(FPBits<T>::FRACTION_LEN < Bits),
Expand Down
18 changes: 18 additions & 0 deletions libc/src/__support/FPUtil/except_value_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@

#include "FEnvImpl.h"
#include "FPBits.h"
#include "cast.h"
#include "rounding_mode.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/__support/macros/properties/cpu_features.h"
#include "src/__support/macros/properties/types.h"

namespace LIBC_NAMESPACE_DECL {

Expand Down Expand Up @@ -113,6 +116,21 @@ template <typename T> LIBC_INLINE T round_result_slightly_up(T value_rn) {
return tmp;
}

#if defined(LIBC_TYPES_HAS_FLOAT16) && \
!defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
template <> LIBC_INLINE float16 round_result_slightly_down(float16 value_rn) {
volatile float tmp = value_rn;
tmp -= FPBits<float16>::min_normal().get_val();
return cast<float16>(tmp);
}

template <> LIBC_INLINE float16 round_result_slightly_up(float16 value_rn) {
volatile float tmp = value_rn;
tmp += FPBits<float16>::min_normal().get_val();
return cast<float16>(tmp);
}
#endif

} // namespace fputil

} // namespace LIBC_NAMESPACE_DECL
Expand Down
7 changes: 5 additions & 2 deletions libc/src/__support/FPUtil/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_header_library(
libc.src.__support.common
libc.src.__support.CPP.bit
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand All @@ -21,16 +22,17 @@ add_header_library(
FMA.h
DEPENDS
libc.hdr.fenv_macros
libc.src.__support.big_int
libc.src.__support.common
libc.src.__support.CPP.bit
libc.src.__support.CPP.limits
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.basic_operations
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.big_int
libc.src.__support.macros.optimization
libc.src.__support.uint128
)
Expand Down Expand Up @@ -60,9 +62,10 @@ add_header_library(
libc.src.__support.CPP.bit
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.basic_operations
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.dyadic_float
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.macros.attributes
libc.src.__support.macros.optimization
Expand Down
5 changes: 3 additions & 2 deletions libc/src/__support/FPUtil/generic/FMA.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/big_int.h"
Expand Down Expand Up @@ -157,7 +158,7 @@ fma(InType x, InType y, InType z) {
}

if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0))
return static_cast<OutType>(x * y + z);
return cast<OutType>(x * y + z);

int x_exp = 0;
int y_exp = 0;
Expand Down Expand Up @@ -198,7 +199,7 @@ fma(InType x, InType y, InType z) {
if (LIBC_UNLIKELY(x_exp == InFPBits::MAX_BIASED_EXPONENT ||
y_exp == InFPBits::MAX_BIASED_EXPONENT ||
z_exp == InFPBits::MAX_BIASED_EXPONENT))
return static_cast<OutType>(x * y + z);
return cast<OutType>(x * y + z);

// Extract mantissa and append hidden leading bits.
InStorageType x_mant = x_bits.get_explicit_mantissa();
Expand Down
5 changes: 3 additions & 2 deletions libc/src/__support/FPUtil/generic/add_sub.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/macros/attributes.h"
Expand Down Expand Up @@ -106,14 +107,14 @@ add_or_sub(InType x, InType y) {
volatile InType tmp = y;
if constexpr (IsSub)
tmp = -tmp;
return static_cast<OutType>(tmp);
return cast<OutType>(tmp);
}

if (y_bits.is_zero()) {
volatile InType tmp = y;
if constexpr (IsSub)
tmp = -tmp;
return static_cast<OutType>(tmp);
return cast<OutType>(tmp);
}
}

Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/FPUtil/generic/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
Expand Down Expand Up @@ -96,7 +97,7 @@ sqrt(InType x) {
// sqrt(-0) = -0
// sqrt(NaN) = NaN
// sqrt(-NaN) = -NaN
return static_cast<OutType>(x);
return cast<OutType>(x);
} else if (bits.is_neg()) {
// sqrt(-Inf) = NaN
// sqrt(-x) = NaN
Expand Down
24 changes: 18 additions & 6 deletions libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -672,9 +673,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -741,9 +743,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -810,9 +813,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -881,6 +885,7 @@ add_entrypoint_object(
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.FPUtil.cast
libc.src.__support.macros.properties.cpu_features
FLAGS
ROUND_OPT
Expand Down Expand Up @@ -1072,9 +1077,10 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.properties.cpu_features
libc.src.__support.macros.properties.types
FLAGS
ROUND_OPT
)
Expand Down Expand Up @@ -1362,12 +1368,15 @@ add_entrypoint_object(
.expxf16
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.CPP.array
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
libc.src.__support.FPUtil.nearest_integer
libc.src.__support.FPUtil.polyeval
libc.src.__support.FPUtil.rounding_mode
libc.src.__support.macros.attributes
libc.src.__support.macros.optimization
COMPILE_OPTIONS
-O3
Expand Down Expand Up @@ -1442,6 +1451,7 @@ add_entrypoint_object(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.CPP.array
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand Down Expand Up @@ -1545,6 +1555,7 @@ add_entrypoint_object(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.CPP.array
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand Down Expand Up @@ -1617,6 +1628,7 @@ add_entrypoint_object(
.expxf16
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/ceilf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/ceilf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, ceilf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_ceilf(x));
return fputil::cast<float16>(__builtin_ceilf(x));
#else
return fputil::ceil(x);
#endif
Expand Down
11 changes: 6 additions & 5 deletions libc/src/math/generic/exp10f16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/nearest_integer.h"
Expand Down Expand Up @@ -118,13 +119,13 @@ LLVM_LIBC_FUNCTION(float16, exp10f16, (float16 x)) {
if (LIBC_UNLIKELY((x_u & ~(0x3c00U | 0x4000U | 0x4200U | 0x4400U)) == 0)) {
switch (x_u) {
case 0x3c00U: // x = 1.0f16
return static_cast<float16>(10.0);
return fputil::cast<float16>(10.0);
case 0x4000U: // x = 2.0f16
return static_cast<float16>(100.0);
return fputil::cast<float16>(100.0);
case 0x4200U: // x = 3.0f16
return static_cast<float16>(1'000.0);
return fputil::cast<float16>(1'000.0);
case 0x4400U: // x = 4.0f16
return static_cast<float16>(10'000.0);
return fputil::cast<float16>(10'000.0);
}
}

Expand Down Expand Up @@ -164,7 +165,7 @@ LLVM_LIBC_FUNCTION(float16, exp10f16, (float16 x)) {
// > 1 + x * P;
float exp10_lo = fputil::polyeval(lo, 0x1p+0f, 0x1.26bb14p+1f, 0x1.53526p+1f,
0x1.04b434p+1f, 0x1.2bcf9ep+0f);
return static_cast<float16>(exp2_hi_mid * exp10_lo);
return fputil::cast<float16>(exp2_hi_mid * exp10_lo);
}

} // namespace LIBC_NAMESPACE_DECL
3 changes: 2 additions & 1 deletion libc/src/math/generic/exp2f16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/nearest_integer.h"
Expand Down Expand Up @@ -121,7 +122,7 @@ LLVM_LIBC_FUNCTION(float16, exp2f16, (float16 x)) {
// > 1 + x * P;
float exp2_lo = fputil::polyeval(lo, 0x1p+0f, 0x1.62e43p-1f, 0x1.ec0aa6p-3f,
0x1.c6b4a6p-5f);
return static_cast<float16>(exp2_hi_mid * exp2_lo);
return fputil::cast<float16>(exp2_hi_mid * exp2_lo);
}

} // namespace LIBC_NAMESPACE_DECL
5 changes: 3 additions & 2 deletions libc/src/math/generic/expf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/common.h"
Expand Down Expand Up @@ -103,7 +104,7 @@ LLVM_LIBC_FUNCTION(float16, expf16, (float16 x)) {
// > display = hexadecimal;
// > P = fpminimax(expm1(x)/x, 2, [|SG...|], [-2^-5, 2^-5]);
// > 1 + x * P;
return static_cast<float16>(
return fputil::cast<float16>(
fputil::polyeval(xf, 0x1p+0f, 0x1p+0f, 0x1.0004p-1f, 0x1.555778p-3f));
}
}
Expand All @@ -113,7 +114,7 @@ LLVM_LIBC_FUNCTION(float16, expf16, (float16 x)) {

// exp(x) = exp(hi + mid) * exp(lo)
auto [exp_hi_mid, exp_lo] = exp_range_reduction(x);
return static_cast<float16>(exp_hi_mid * exp_lo);
return fputil::cast<float16>(exp_hi_mid * exp_lo);
}

} // namespace LIBC_NAMESPACE_DECL
7 changes: 4 additions & 3 deletions libc/src/math/generic/expm1f16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/rounding_mode.h"
Expand Down Expand Up @@ -99,7 +100,7 @@ LLVM_LIBC_FUNCTION(float16, expm1f16, (float16 x)) {
FPBits::one(Sign::NEG).get_val());
// When x <= -0x1.0ap+3, round(expm1(x), HP, RN) = -0x1.ffcp-1.
return fputil::round_result_slightly_down(
static_cast<float16>(-0x1.ffcp-1));
fputil::cast<float16>(-0x1.ffcp-1));
}

// When 0 < |x| <= 2^(-3).
Expand All @@ -114,7 +115,7 @@ LLVM_LIBC_FUNCTION(float16, expm1f16, (float16 x)) {
// > display = hexadecimal;
// > P = fpminimax(expm1(x)/x, 4, [|SG...|], [-2^-3, 2^-3]);
// > x * P;
return static_cast<float16>(
return fputil::cast<float16>(
xf * fputil::polyeval(xf, 0x1p+0f, 0x1.fffff8p-2f, 0x1.555556p-3f,
0x1.55905ep-5f, 0x1.1124c2p-7f));
}
Expand All @@ -126,7 +127,7 @@ LLVM_LIBC_FUNCTION(float16, expm1f16, (float16 x)) {
// exp(x) = exp(hi + mid) * exp(lo)
auto [exp_hi_mid, exp_lo] = exp_range_reduction(x);
// expm1(x) = exp(hi + mid) * exp(lo) - 1
return static_cast<float16>(fputil::multiply_add(exp_hi_mid, exp_lo, -1.0f));
return fputil::cast<float16>(fputil::multiply_add(exp_hi_mid, exp_lo, -1.0f));
}

} // namespace LIBC_NAMESPACE_DECL
3 changes: 2 additions & 1 deletion libc/src/math/generic/floorf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/floorf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, floorf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_floorf(x));
return fputil::cast<float16>(__builtin_floorf(x));
#else
return fputil::floor(x);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/rintf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/rintf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, rintf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_rintf(x));
return fputil::cast<float16>(__builtin_rintf(x));
#else
return fputil::round_using_current_rounding_mode(x);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/roundevenf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/roundevenf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, roundevenf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_ROUNDEVEN) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_roundevenf(x));
return fputil::cast<float16>(__builtin_roundevenf(x));
#else
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/roundf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/roundf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, roundf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_ROUND) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_roundf(x));
return fputil::cast<float16>(__builtin_roundf(x));
#else
return fputil::round(x);
#endif
Expand Down
3 changes: 2 additions & 1 deletion libc/src/math/generic/truncf16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "src/math/truncf16.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
Expand All @@ -17,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float16, truncf16, (float16 x)) {
#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) && \
defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
return static_cast<float16>(__builtin_truncf(x));
return fputil::cast<float16>(__builtin_truncf(x));
#else
return fputil::trunc(x);
#endif
Expand Down
42 changes: 23 additions & 19 deletions libc/test/src/math/smoke/AddTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,34 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using AddFunc = OutType (*)(InType, InType);

void test_special_numbers(AddFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));
EXPECT_FP_EQ(inf, func(inf, neg_zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, neg_zero));
EXPECT_FP_EQ(inf, func(in.inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
EXPECT_FP_EQ(inf, func(in.inf, in.neg_zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.neg_zero));
}

void test_invalid_operations(AddFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
}

void test_range_errors(AddFunc func) {
#ifndef LIBC_TARGET_OS_IS_WINDOWS
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -75,10 +76,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, neg_max_normal),
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
Expand All @@ -91,9 +93,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -107,11 +111,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, neg_max_normal),
func(in.neg_max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
Expand All @@ -127,7 +131,7 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

void test_inexact_results(AddFunc func) {
func(InType(1.0), min_denormal);
func(InType(1.0), in.min_denormal);
EXPECT_FP_EXCEPTION(FE_INEXACT);
}
};
Expand Down
15 changes: 15 additions & 0 deletions libc/test/src/math/smoke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.dfmal
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -413,6 +414,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.dfmaf128
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down Expand Up @@ -1062,6 +1064,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.expf16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -1098,6 +1101,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.exp2f16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -1145,6 +1149,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.exp10f16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -3317,6 +3322,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.fmaf
libc.src.__support.macros.properties.types
FLAGS
FMA_OPT__ONLY
)
Expand All @@ -3331,6 +3337,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.fma
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down Expand Up @@ -3368,6 +3375,7 @@ add_fp_unittest(
libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.expm1f16
libc.src.__support.FPUtil.cast
)

add_fp_unittest(
Expand Down Expand Up @@ -4352,6 +4360,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fma
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4364,6 +4373,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fmaf
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4376,6 +4386,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fmal
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4388,6 +4399,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.f16fmaf128
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down Expand Up @@ -4490,6 +4502,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.ffma
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4502,6 +4515,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.ffmal
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand All @@ -4514,6 +4528,7 @@ add_fp_unittest(
FmaTest.h
DEPENDS
libc.src.math.ffmaf128
libc.src.__support.macros.properties.types
)

add_fp_unittest(
Expand Down
82 changes: 46 additions & 36 deletions libc/test/src/math/smoke/DivTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,110 +28,120 @@ class DivTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using InFPBits = typename InConstants::FPBits;
using InStorageType = typename InConstants::StorageType;

InConstants in;

public:
using DivFunc = OutType (*)(InType, InType);

void test_special_numbers(DivFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));
EXPECT_FP_EQ(neg_inf, func(inf, neg_zero));
EXPECT_FP_EQ(inf, func(neg_inf, neg_zero));
EXPECT_FP_EQ(inf, func(in.inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.inf, in.neg_zero));
EXPECT_FP_EQ(inf, func(in.neg_inf, in.neg_zero));
}

void test_division_by_zero(DivFunc func) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), zero), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(-1.0), zero),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), in.zero), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(-1.0), in.zero),
FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(1.0), neg_zero),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(1.0), in.neg_zero),
FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), zero), FE_DIVBYZERO);
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), in.zero), FE_DIVBYZERO);
}

void test_invalid_operations(DivFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(zero, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_zero, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(zero, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_zero, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.zero, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_zero, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.zero, in.neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_zero, in.neg_zero), FE_INVALID);

EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
}

void test_range_errors(DivFunc func) {
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, min_denormal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, min_denormal),
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, min_denormal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal,
func(neg_min_denormal, max_normal),
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, min_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.min_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, min_denormal),
func(in.neg_max_normal, in.min_denormal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal, func(min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
func(in.min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
func(in.neg_min_denormal, in.max_normal),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
Expand Down
64 changes: 32 additions & 32 deletions libc/test/src/math/smoke/FModTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,61 +108,61 @@ class FmodTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
TEST_SPECIAL(T(3.0), neg_inf, T(3.0), false, 0);

TEST_SPECIAL(zero, aNaN, aNaN, false, 0);
TEST_SPECIAL(zero, -aNaN, aNaN, false, 0);
TEST_SPECIAL(zero, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_zero, aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_zero, -aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_zero, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(T(1.0), aNaN, aNaN, false, 0);
TEST_SPECIAL(T(1.0), -aNaN, aNaN, false, 0);
TEST_SPECIAL(T(1.0), neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(inf, aNaN, aNaN, false, 0);
TEST_SPECIAL(inf, -aNaN, aNaN, false, 0);
TEST_SPECIAL(inf, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_inf, aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_inf, -aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_inf, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(zero, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(zero, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(zero, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_zero, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_zero, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_zero, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(T(1.0), sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(T(1.0), -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(T(1.0), neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(inf, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(inf, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(inf, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_inf, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_inf, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_inf, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, zero, aNaN, false, 0);
TEST_SPECIAL(-aNaN, zero, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, zero, aNaN, false, 0);
TEST_SPECIAL(aNaN, neg_zero, aNaN, false, 0);
TEST_SPECIAL(-aNaN, neg_zero, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, neg_zero, aNaN, false, 0);
TEST_SPECIAL(aNaN, T(1.0), aNaN, false, 0);
TEST_SPECIAL(-aNaN, T(1.0), aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, T(1.0), aNaN, false, 0);
TEST_SPECIAL(aNaN, inf, aNaN, false, 0);
TEST_SPECIAL(-aNaN, inf, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, inf, aNaN, false, 0);
TEST_SPECIAL(aNaN, neg_inf, aNaN, false, 0);
TEST_SPECIAL(-aNaN, neg_inf, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, neg_inf, aNaN, false, 0);
TEST_SPECIAL(sNaN, zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, neg_zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_zero, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, T(1.0), aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, T(1.0), aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, T(1.0), aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, neg_inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_inf, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, aNaN, aNaN, false, 0);
TEST_SPECIAL(aNaN, -aNaN, aNaN, false, 0);
TEST_SPECIAL(-aNaN, aNaN, aNaN, false, 0);
TEST_SPECIAL(-aNaN, -aNaN, aNaN, false, 0);
TEST_SPECIAL(aNaN, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, aNaN, aNaN, false, 0);
TEST_SPECIAL(neg_aNaN, neg_aNaN, aNaN, false, 0);
TEST_SPECIAL(aNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-aNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-aNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(aNaN, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_aNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_aNaN, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, -aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, -aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_aNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(-sNaN, -sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(sNaN, neg_sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, sNaN, aNaN, false, FE_INVALID);
TEST_SPECIAL(neg_sNaN, neg_sNaN, aNaN, false, FE_INVALID);

TEST_SPECIAL(T(6.5), T(2.25), T(2.0), false, 0);
TEST_SPECIAL(T(-6.5), T(2.25), T(-2.0), false, 0);
Expand Down
28 changes: 23 additions & 5 deletions libc/test/src/math/smoke/FmaTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#ifndef LLVM_LIBC_TEST_SRC_MATH_FMATEST_H
#define LLVM_LIBC_TEST_SRC_MATH_FMATEST_H

#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
Expand Down Expand Up @@ -37,6 +40,11 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
OutConstants out;
InConstants in;

const InType in_out_min_normal =
LIBC_NAMESPACE::fputil::cast<InType>(out.min_normal);
const InType in_out_min_denormal =
LIBC_NAMESPACE::fputil::cast<InType>(out.min_denormal);

public:
using FmaFunc = OutType (*)(InType, InType, InType);

Expand All @@ -52,7 +60,7 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {

// Test underflow rounding up.
EXPECT_FP_EQ(OutFPBits(OutStorageType(2)).get_val(),
func(OutType(0.5), out.min_denormal, out.min_denormal));
func(InType(0.5), in_out_min_denormal, in_out_min_denormal));

if constexpr (sizeof(OutType) < sizeof(InType)) {
EXPECT_FP_EQ(out.zero,
Expand All @@ -63,8 +71,9 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
OutType v = OutFPBits(static_cast<OutStorageType>(OUT_MIN_NORMAL_U +
OutStorageType(1)))
.get_val();
EXPECT_FP_EQ(v, func(OutType(1) / OutType(OUT_MIN_NORMAL_U << 1), v,
out.min_normal));
EXPECT_FP_EQ(v, func(InType(1) / InType(OUT_MIN_NORMAL_U << 1),
LIBC_NAMESPACE::fputil::cast<InType>(v),
in_out_min_normal));

if constexpr (sizeof(OutType) < sizeof(InType)) {
InFPBits tmp = InFPBits::one();
Expand All @@ -74,12 +83,21 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
InType v = InFPBits(static_cast<InStorageType>(IN_MIN_NORMAL_U +
InStorageType(1)))
.get_val();
EXPECT_FP_EQ(out.min_normal, func(reciprocal_value, v, out.min_normal));
EXPECT_FP_EQ(out.min_normal,
func(reciprocal_value, v, in_out_min_normal));
}

// Test overflow.
OutType z = out.max_normal;
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0.75) * z, func(InType(1.75), z, -z));
InType in_z = LIBC_NAMESPACE::fputil::cast<InType>(out.max_normal);
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
// Rounding modes other than the default might not be usable with float16.
if constexpr (LIBC_NAMESPACE::cpp::is_same_v<OutType, float16>)
EXPECT_FP_EQ(OutType(0.75) * z, func(InType(1.75), in_z, -in_z));
else
#endif
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0.75) * z,
func(InType(1.75), in_z, -in_z));

// Exact cancellation.
EXPECT_FP_EQ_ROUNDING_NEAREST(
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/smoke/ModfTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ModfTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {

T integral;
T frac = func(x, &integral);
ASSERT_TRUE(LIBC_NAMESPACE::fputil::abs(frac) < 1.0l);
ASSERT_TRUE(LIBC_NAMESPACE::fputil::abs(frac) < T(1.0));
ASSERT_TRUE(LIBC_NAMESPACE::fputil::trunc(x) == integral);
ASSERT_TRUE(integral + frac == x);
}
Expand Down
52 changes: 28 additions & 24 deletions libc/test/src/math/smoke/MulTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using MulFunc = OutType (*)(InType, InType);

void test_special_numbers(MulFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(neg_inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(inf, InType(-1.0)));
EXPECT_FP_EQ(inf, func(neg_inf, InType(-1.0)));
EXPECT_FP_EQ(inf, func(in.inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, InType(1.0)));
EXPECT_FP_EQ(neg_inf, func(in.inf, InType(-1.0)));
EXPECT_FP_EQ(inf, func(in.neg_inf, InType(-1.0)));

EXPECT_FP_EQ_ALL_ROUNDING(zero, func(zero, zero));
EXPECT_FP_EQ_ALL_ROUNDING(zero, func(neg_zero, neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(zero, neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(neg_zero, zero));
EXPECT_FP_EQ_ALL_ROUNDING(zero, func(in.zero, in.zero));
EXPECT_FP_EQ_ALL_ROUNDING(zero, func(in.neg_zero, in.neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.zero, in.neg_zero));
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.neg_zero, in.zero));

EXPECT_FP_EQ_ALL_ROUNDING(OutType(1.0), func(1.0, 1.0));
EXPECT_FP_EQ_ALL_ROUNDING(OutType(15.0), func(3.0, 5.0));
Expand All @@ -58,20 +58,21 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

void test_invalid_operations(MulFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.zero), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_zero), FE_INVALID);
}

void test_range_errors(MulFunc func) {
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf,
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -85,10 +86,11 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
Expand All @@ -101,9 +103,11 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf,
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -117,11 +121,11 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
Expand Down
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/NextTowardTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
const T neg_zero = FPBits::zero(Sign::NEG).get_val();
const T nan = FPBits::quiet_nan().get_val();

const long double to_inf = ToFPBits::inf(Sign::POS).get_val();
const long double to_neg_inf = ToFPBits::inf(Sign::NEG).get_val();
const long double to_zero = ToFPBits::zero().get_val();
const long double to_neg_zero = ToFPBits::zero(Sign::NEG).get_val();
const long double to_nan = ToFPBits::quiet_nan().get_val();
Expand Down Expand Up @@ -134,7 +136,7 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);

result = func(x, inf);
result = func(x, to_inf);
expected_bits = min_normal + 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
Expand All @@ -145,7 +147,7 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);

result = func(x, -inf);
result = func(x, to_neg_inf);
expected_bits = FPBits::SIGN_MASK + min_normal + 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
Expand All @@ -156,29 +158,29 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
expected_bits = max_normal - 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, inf), inf);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, to_inf), inf);

x = -x;
result = func(x, 0);
expected_bits = FPBits::SIGN_MASK + max_normal - 1;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, -inf), -inf);
ASSERT_FP_EQ_WITH_OVERFLOW(func(x, to_neg_inf), neg_inf);

// 'from' is infinity.
x = inf;
result = func(x, 0);
expected_bits = max_normal;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ(func(x, inf), inf);
ASSERT_FP_EQ(func(x, to_inf), inf);

x = neg_inf;
result = func(x, 0);
expected_bits = FPBits::SIGN_MASK + max_normal;
expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
ASSERT_FP_EQ(result, expected);
ASSERT_FP_EQ(func(x, neg_inf), neg_inf);
ASSERT_FP_EQ(func(x, to_neg_inf), neg_inf);

// 'from' is a power of 2.
x = T(32.0);
Expand Down
16 changes: 11 additions & 5 deletions libc/test/src/math/smoke/SqrtTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@ class SqrtTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {

DECLARE_SPECIAL_CONSTANTS(OutType)

struct InConstants {
DECLARE_SPECIAL_CONSTANTS(InType)
};

InConstants in;

public:
typedef OutType (*SqrtFunc)(InType);

void test_special_numbers(SqrtFunc func) {
ASSERT_FP_EQ(aNaN, func(aNaN));
ASSERT_FP_EQ(inf, func(inf));
ASSERT_FP_EQ(aNaN, func(neg_inf));
ASSERT_FP_EQ(zero, func(zero));
ASSERT_FP_EQ(neg_zero, func(neg_zero));
ASSERT_FP_EQ(aNaN, func(in.aNaN));
ASSERT_FP_EQ(inf, func(in.inf));
ASSERT_FP_EQ(aNaN, func(in.neg_inf));
ASSERT_FP_EQ(zero, func(in.zero));
ASSERT_FP_EQ(neg_zero, func(in.neg_zero));
ASSERT_FP_EQ(aNaN, func(InType(-1.0)));
ASSERT_FP_EQ(OutType(1.0), func(InType(1.0)));
ASSERT_FP_EQ(OutType(2.0), func(InType(4.0)));
Expand Down
40 changes: 21 additions & 19 deletions libc/test/src/math/smoke/SubTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,33 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
using SubFunc = OutType (*)(InType, InType);

void test_special_numbers(SubFunc func) {
EXPECT_FP_IS_NAN(func(aNaN, aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);

InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
EXPECT_FP_IS_NAN(func(qnan_42, zero));
EXPECT_FP_IS_NAN(func(zero, qnan_42));
EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
EXPECT_FP_IS_NAN(func(in.zero, qnan_42));

EXPECT_FP_EQ(inf, func(inf, zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));
EXPECT_FP_EQ(inf, func(inf, neg_zero));
EXPECT_FP_EQ(neg_inf, func(neg_inf, neg_zero));
EXPECT_FP_EQ(inf, func(in.inf, in.zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
EXPECT_FP_EQ(inf, func(in.inf, in.neg_zero));
EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.neg_zero));
}

void test_invalid_operations(SubFunc func) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.inf), FE_INVALID);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_inf), FE_INVALID);
}

void test_range_errors(SubFunc func) {
#ifndef LIBC_TARGET_OS_IS_WINDOWS
using namespace LIBC_NAMESPACE::fputil::testing;

if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -75,10 +75,11 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(zero,
Expand All @@ -92,9 +93,10 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);

Expand All @@ -109,11 +111,11 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, neg_max_normal),
EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.neg_max_normal),
FE_OVERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
func(neg_max_normal, max_normal),
func(in.neg_max_normal, in.max_normal),
FE_OVERFLOW | FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
Expand All @@ -129,7 +131,7 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}

void test_inexact_results(SubFunc func) {
func(InType(1.0), min_denormal);
func(InType(1.0), in.min_denormal);
EXPECT_FP_EXCEPTION(FE_INEXACT);
}
};
Expand Down
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/exp10f16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/exp10f16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -26,15 +27,14 @@ TEST_F(LlvmLibcExp10f16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp10f16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(zero),
LIBC_NAMESPACE::exp10f16(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp10f16(neg_inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp10f16(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp10f16(neg_zero));
EXPECT_MATH_ERRNO(0);
}
Expand All @@ -47,7 +47,8 @@ TEST_F(LlvmLibcExp10f16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
inf, LIBC_NAMESPACE::exp10f16(static_cast<float16>(5.0)), FE_OVERFLOW);
inf, LIBC_NAMESPACE::exp10f16(LIBC_NAMESPACE::fputil::cast<float16>(5.0)),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
}

Expand All @@ -59,7 +60,8 @@ TEST_F(LlvmLibcExp10f16Test, Underflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
zero, LIBC_NAMESPACE::exp10f16(static_cast<float16>(-8.0)),
zero,
LIBC_NAMESPACE::exp10f16(LIBC_NAMESPACE::fputil::cast<float16>(-8.0)),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/exp2f16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/exp2f16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -26,15 +27,14 @@ TEST_F(LlvmLibcExp2f16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp2f16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(zero),
LIBC_NAMESPACE::exp2f16(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp2f16(neg_inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp2f16(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::exp2f16(neg_zero));
EXPECT_MATH_ERRNO(0);
}
Expand All @@ -47,7 +47,8 @@ TEST_F(LlvmLibcExp2f16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
inf, LIBC_NAMESPACE::exp2f16(static_cast<float16>(16.0)), FE_OVERFLOW);
inf, LIBC_NAMESPACE::exp2f16(LIBC_NAMESPACE::fputil::cast<float16>(16.0)),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
}

Expand All @@ -59,7 +60,8 @@ TEST_F(LlvmLibcExp2f16Test, Underflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
zero, LIBC_NAMESPACE::exp2f16(static_cast<float16>(-25.0)),
zero,
LIBC_NAMESPACE::exp2f16(LIBC_NAMESPACE::fputil::cast<float16>(-25.0)),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
14 changes: 8 additions & 6 deletions libc/test/src/math/smoke/expf16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/expf16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -27,15 +28,14 @@ TEST_F(LlvmLibcExpf16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::expf16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(zero),
LIBC_NAMESPACE::expf16(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::expf16(neg_inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::expf16(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(1.0f),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(1.0f),
LIBC_NAMESPACE::expf16(neg_zero));
EXPECT_MATH_ERRNO(0);
}
Expand All @@ -48,7 +48,8 @@ TEST_F(LlvmLibcExpf16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
inf, LIBC_NAMESPACE::expf16(static_cast<float16>(12.0)), FE_OVERFLOW);
inf, LIBC_NAMESPACE::expf16(LIBC_NAMESPACE::fputil::cast<float16>(12.0)),
FE_OVERFLOW);
EXPECT_MATH_ERRNO(ERANGE);
}

Expand All @@ -60,7 +61,8 @@ TEST_F(LlvmLibcExpf16Test, Underflow) {
EXPECT_MATH_ERRNO(ERANGE);

EXPECT_FP_EQ_WITH_EXCEPTION(
zero, LIBC_NAMESPACE::expf16(static_cast<float16>(-18.0)),
zero,
LIBC_NAMESPACE::expf16(LIBC_NAMESPACE::fputil::cast<float16>(-18.0)),
FE_UNDERFLOW | FE_INEXACT);
EXPECT_MATH_ERRNO(ERANGE);
}
44 changes: 24 additions & 20 deletions libc/test/src/math/smoke/expm1f16_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.h"
#include "src/__support/FPUtil/cast.h"
#include "src/errno/libc_errno.h"
#include "src/math/expm1f16.h"
#include "test/UnitTest/FPMatcher.h"
Expand All @@ -27,7 +28,7 @@ TEST_F(LlvmLibcExpm1f16Test, SpecialNumbers) {
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::expm1f16(inf));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ_ALL_ROUNDING(static_cast<float16>(-1.0),
EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast<float16>(-1.0),
LIBC_NAMESPACE::expm1f16(neg_inf));
EXPECT_MATH_ERRNO(0);

Expand All @@ -46,7 +47,7 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) {
EXPECT_MATH_ERRNO(ERANGE);

// round(16 * log(2), HP, RN);
float16 x = static_cast<float16>(0x1.63p+3);
float16 x = LIBC_NAMESPACE::fputil::cast<float16>(0x1.63p+3);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(inf, LIBC_NAMESPACE::expm1f16(x),
FE_OVERFLOW | FE_INEXACT);
Expand All @@ -68,41 +69,44 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) {
TEST_F(LlvmLibcExpm1f16Test, ResultNearNegOne) {
LIBC_NAMESPACE::libc_errno = 0;

EXPECT_FP_EQ_WITH_EXCEPTION(static_cast<float16>(-1.0),
EXPECT_FP_EQ_WITH_EXCEPTION(LIBC_NAMESPACE::fputil::cast<float16>(-1.0),
LIBC_NAMESPACE::expm1f16(neg_max_normal),
FE_INEXACT);

// round(-11 * log(2), HP, RN);
float16 x = static_cast<float16>(-0x1.e8p+2);
float16 x = LIBC_NAMESPACE::fputil::cast<float16>(-0x1.e8p+2);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(
static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD(
static_cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO(
static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

x = static_cast<float16>(-0x1.0a4p+3);
x = LIBC_NAMESPACE::fputil::cast<float16>(-0x1.0a4p+3);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(
static_cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD(
static_cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-1.0), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);

EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO(
static_cast<float16>(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x),
FE_INEXACT);
LIBC_NAMESPACE::fputil::cast<float16>(-0x1.ffcp-1),
LIBC_NAMESPACE::expm1f16(x), FE_INEXACT);
}
1 change: 1 addition & 0 deletions libc/utils/MPFRWrapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
libc.src.__support.CPP.stringstream
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fpbits_str
LibcTest.unit
Expand Down
3 changes: 2 additions & 1 deletion libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/stringstream.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/fpbits_str.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/types.h"
Expand Down Expand Up @@ -683,7 +684,7 @@ template <> long double MPFRNumber::as<long double>() const {
template <> float16 MPFRNumber::as<float16>() const {
// TODO: Either prove that this cast won't cause double-rounding errors, or
// find a better way to get a float16.
return static_cast<float16>(mpfr_get_d(value, mpfr_rounding));
return fputil::cast<float16>(mpfr_get_d(value, mpfr_rounding));
}
#endif

Expand Down
16 changes: 16 additions & 0 deletions utils/bazel/llvm-project-overlay/libc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,19 @@ libc_support_library(
],
)

libc_support_library(
name = "__support_fputil_cast",
hdrs = ["src/__support/FPUtil/cast.h"],
deps = [
":__support_cpp_algorithm",
":__support_cpp_type_traits",
":__support_fputil_dyadic_float",
":__support_fputil_fp_bits",
":__support_macros_properties_types",
":hdr_fenv_macros",
],
)

libc_support_library(
name = "__support_fputil_division_and_remainder_operations",
hdrs = ["src/__support/FPUtil/DivisionAndRemainderOperations.h"],
Expand All @@ -821,9 +834,12 @@ libc_support_library(
hdrs = ["src/__support/FPUtil/except_value_utils.h"],
deps = [
":__support_cpp_optional",
":__support_fputil_cast",
":__support_fputil_fenv_impl",
":__support_fputil_fp_bits",
":__support_fputil_rounding_mode",
":__support_macros_properties_cpu_features",
":__support_macros_properties_types",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ libc_support_library(
"//libc:__support_cpp_string_view",
"//libc:__support_cpp_stringstream",
"//libc:__support_cpp_type_traits",
"//libc:__support_fputil_cast",
"//libc:__support_fputil_fp_bits",
"//libc:__support_fputil_fpbits_str",
"//libc:__support_macros_config",
Expand Down