diff --git a/libc/cmake/modules/CheckCompilerFeatures.cmake b/libc/cmake/modules/CheckCompilerFeatures.cmake index 63145fe709dda..862c7ecbd7fdf 100644 --- a/libc/cmake/modules/CheckCompilerFeatures.cmake +++ b/libc/cmake/modules/CheckCompilerFeatures.cmake @@ -10,6 +10,7 @@ set( "builtin_round" "builtin_roundeven" "float16" + "float16_conversion" "float128" "fixed_point" ) @@ -61,15 +62,21 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES) set(link_options "") if(${feature} STREQUAL "fixed_point") list(APPEND compile_options "-ffixed-point") - elseif(${feature} MATCHES "^builtin_") + elseif(${feature} MATCHES "^builtin_" OR + ${feature} STREQUAL "float16_conversion") set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT}) set(link_options -nostdlib) - # The compiler might handle calls to rounding builtins by generating calls - # to the respective libc math functions, in which case we cannot use these + # The compiler might handle calls to math builtins by generating calls to + # the respective libc math functions, in which case we cannot use these # builtins in our implementations of these functions. We check that this is # not the case by trying to link an executable, since linking would fail due # to unresolved references with -nostdlib if calls to libc functions were # generated. + # + # We also had issues with soft-float float16 conversion functions using both + # compiler-rt and libgcc, so we also check whether we can convert from and + # to float16 without calls to compiler runtime functions by trying to link + # an executable with -nostdlib. set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) endif() @@ -97,6 +104,8 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES) list(APPEND AVAILABLE_COMPILER_FEATURES ${feature}) if(${feature} STREQUAL "float16") set(LIBC_TYPES_HAS_FLOAT16 TRUE) + elseif(${feature} STREQUAL "float16_conversion") + add_compile_definitions(__LIBC_USE_FLOAT16_CONVERSION) elseif(${feature} STREQUAL "float128") set(LIBC_TYPES_HAS_FLOAT128 TRUE) elseif(${feature} STREQUAL "fixed_point") @@ -115,6 +124,10 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES) endif() endforeach() +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT}) +set(link_options "") + message(STATUS "Compiler features available: ${AVAILABLE_COMPILER_FEATURES}") ### Compiler Feature Detection ### diff --git a/libc/cmake/modules/compiler_features/check_float16_conversion.cpp b/libc/cmake/modules/compiler_features/check_float16_conversion.cpp new file mode 100644 index 0000000000000..09ac8e9c8bc9d --- /dev/null +++ b/libc/cmake/modules/compiler_features/check_float16_conversion.cpp @@ -0,0 +1,30 @@ +#include "include/llvm-libc-macros/float16-macros.h" +#include "include/llvm-libc-types/float128.h" + +#ifndef LIBC_TYPES_HAS_FLOAT16 +#error unsupported +#endif + +_Float16 cvt_from_float(float x) { return static_cast<_Float16>(x); } + +_Float16 cvt_from_double(double x) { return static_cast<_Float16>(x); } + +_Float16 cvt_from_long_double(long double x) { + return static_cast<_Float16>(x); +} + +#ifdef LIBC_TYPES_HAS_FLOAT128 +_Float16 cvt_from_float128(float128 x) { return static_cast<_Float16>(x); } +#endif + +float cvt_to_float(_Float16 x) { return x; } + +double cvt_to_double(_Float16 x) { return x; } + +long double cvt_to_long_double(_Float16 x) { return x; } + +#ifdef LIBC_TYPES_HAS_FLOAT128 +float128 cvt_to_float128(_Float16 x) { return x; } +#endif + +extern "C" void _start() {} diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index ea1e0e8b39d10..522b4afefd48d 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -92,11 +92,14 @@ add_header_library( HDRS except_value_utils.h DEPENDS + .cast .fp_bits .fenv_impl .rounding_mode libc.src.__support.CPP.optional libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features + libc.src.__support.macros.properties.types ) @@ -175,9 +178,13 @@ add_header_library( .fenv_impl .fp_bits .multiply_add + .rounding_mode + libc.hdr.errno_macros + libc.hdr.fenv_macros libc.src.__support.CPP.type_traits libc.src.__support.big_int libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types ) add_header_library( @@ -217,18 +224,32 @@ add_header_library( HDRS ManipulationFunctions.h DEPENDS + .cast + .dyadic_float .fenv_impl .fp_bits - .dyadic_float .nearest_integer_operations .normal_float libc.hdr.math_macros + libc.src.errno.errno + libc.src.__support.common libc.src.__support.CPP.bit libc.src.__support.CPP.limits libc.src.__support.CPP.type_traits - libc.src.__support.common libc.src.__support.macros.optimization - libc.src.errno.errno +) + +add_header_library( + cast + HDRS + cast.h + DEPENDS + .dyadic_float + .fp_bits + libc.hdr.fenv_macros + libc.src.__support.CPP.algorithm + libc.src.__support.CPP.type_traits + libc.src.__support.macros.properties.types ) add_subdirectory(generic) diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h index a14f355789999..66bfe2aa377f9 100644 --- a/libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/libc/src/__support/FPUtil/ManipulationFunctions.h @@ -12,6 +12,7 @@ #include "FPBits.h" #include "NearestIntegerOperations.h" #include "NormalFloat.h" +#include "cast.h" #include "dyadic_float.h" #include "rounding_mode.h" @@ -192,7 +193,8 @@ ldexp(T x, U exp) { // For all other values, NormalFloat to T conversion handles it the right way. DyadicFloat::STORAGE_LEN> normal(bits.get_val()); normal.exponent += static_cast(exp); - return static_cast(normal); + // TODO: Add tests for exceptions. + return normal.template as(); } template to_bits(to); if (to_bits.is_nan()) - return static_cast(to); + return cast(to); // NOTE: This would work only if `U` has a greater or equal precision than // `T`. Otherwise `from` could loose its precision and the following statement // could incorrectly evaluate to `true`. - if (static_cast(from) == to) - return static_cast(to); + if (cast(from) == to) + return cast(to); using StorageType = typename FPBits::StorageType; if (from != T(0)) { - if ((static_cast(from) < to) == (from > T(0))) { + if ((cast(from) < to) == (from > T(0))) { from_bits = FPBits(StorageType(from_bits.uintval() + 1)); } else { from_bits = FPBits(StorageType(from_bits.uintval() - 1)); diff --git a/libc/src/__support/FPUtil/cast.h b/libc/src/__support/FPUtil/cast.h new file mode 100644 index 0000000000000..126f3852137b7 --- /dev/null +++ b/libc/src/__support/FPUtil/cast.h @@ -0,0 +1,65 @@ +//===-- Conversion between floating-point types -----------------*- 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___SUPPORT_FPUTIL_CAST_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_CAST_H + +#include "FPBits.h" +#include "dyadic_float.h" +#include "hdr/fenv_macros.h" +#include "src/__support/CPP/algorithm.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE::fputil { + +template +LIBC_INLINE constexpr cpp::enable_if_t && + cpp::is_floating_point_v, + OutType> +cast(InType x) { +#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION) + if constexpr (cpp::is_same_v || + cpp::is_same_v) { + using InFPBits = FPBits; + using InStorageType = typename InFPBits::StorageType; + using OutFPBits = FPBits; + using OutStorageType = typename OutFPBits::StorageType; + + InFPBits x_bits(x); + + if (x_bits.is_nan()) { + if (x_bits.is_signaling_nan()) { + raise_except_if_required(FE_INVALID); + return OutFPBits::quiet_nan().get_val(); + } + + InStorageType x_mant = x_bits.get_mantissa(); + if (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN) + x_mant >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN; + return OutFPBits::quiet_nan(x_bits.sign(), + static_cast(x_mant)) + .get_val(); + } + + if (x_bits.is_inf()) + return OutFPBits::inf(x_bits.sign()).get_val(); + + constexpr size_t MAX_FRACTION_LEN = + cpp::max(OutFPBits::FRACTION_LEN, InFPBits::FRACTION_LEN); + DyadicFloat xd(x); + return xd.template as(); + } +#endif + + return static_cast(x); +} + +} // namespace LIBC_NAMESPACE::fputil + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_CAST_H diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h index 86346a47b35a3..f2de70f344607 100644 --- a/libc/src/__support/FPUtil/dyadic_float.h +++ b/libc/src/__support/FPUtil/dyadic_float.h @@ -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 @@ -97,13 +101,118 @@ template struct DyadicFloat { return exponent + (Bits - 1); } - // Assume that it is already normalized. - // Output is rounded correctly with respect to the current rounding mode. + template + LIBC_INLINE constexpr cpp::enable_if_t< + cpp::is_floating_point_v && (FPBits::FRACTION_LEN < Bits), T> + generic_as() const { + using FPBits = FPBits; + 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(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(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 && (FPBits::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::zero(sign).get_val(); @@ -224,6 +333,20 @@ template struct DyadicFloat { return r; } + // Assume that it is already normalized. + // Output is rounded correctly with respect to the current rounding mode. + template && + (FPBits::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) + return generic_as(); +#endif + return fast_as(); + } + template && (FPBits::FRACTION_LEN < Bits), diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h index b9f54aa24e3a2..f8e4e92d3e1fb 100644 --- a/libc/src/__support/FPUtil/except_value_utils.h +++ b/libc/src/__support/FPUtil/except_value_utils.h @@ -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 { @@ -113,6 +116,21 @@ template 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::min_normal().get_val(); + return cast(tmp); +} + +template <> LIBC_INLINE float16 round_result_slightly_up(float16 value_rn) { + volatile float tmp = value_rn; + tmp += FPBits::min_normal().get_val(); + return cast(tmp); +} +#endif + } // namespace fputil } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt index 43096aa529fc3..60434d6f6f11a 100644 --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -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 @@ -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 ) @@ -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 diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h index e5683c8ff61ea..bec312e44b1b1 100644 --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -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" @@ -157,7 +158,7 @@ fma(InType x, InType y, InType z) { } if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0)) - return static_cast(x * y + z); + return cast(x * y + z); int x_exp = 0; int y_exp = 0; @@ -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(x * y + z); + return cast(x * y + z); // Extract mantissa and append hidden leading bits. InStorageType x_mant = x_bits.get_explicit_mantissa(); diff --git a/libc/src/__support/FPUtil/generic/add_sub.h b/libc/src/__support/FPUtil/generic/add_sub.h index 850db3f83209e..6bc9dcd23bafa 100644 --- a/libc/src/__support/FPUtil/generic/add_sub.h +++ b/libc/src/__support/FPUtil/generic/add_sub.h @@ -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" @@ -106,14 +107,14 @@ add_or_sub(InType x, InType y) { volatile InType tmp = y; if constexpr (IsSub) tmp = -tmp; - return static_cast(tmp); + return cast(tmp); } if (y_bits.is_zero()) { volatile InType tmp = y; if constexpr (IsSub) tmp = -tmp; - return static_cast(tmp); + return cast(tmp); } } diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h index 4502cc07d32b3..01af4bb7c9009 100644 --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -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" @@ -96,7 +97,7 @@ sqrt(InType x) { // sqrt(-0) = -0 // sqrt(NaN) = NaN // sqrt(-NaN) = -NaN - return static_cast(x); + return cast(x); } else if (bits.is_neg()) { // sqrt(-Inf) = NaN // sqrt(-x) = NaN diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 350072f4b9649..01ca65fda9fa1 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -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 ) @@ -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 ) @@ -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 ) @@ -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 ) @@ -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 @@ -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 ) @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/libc/src/math/generic/ceilf16.cpp b/libc/src/math/generic/ceilf16.cpp index 8af31c6623a02..9d89efc5311d1 100644 --- a/libc/src/math/generic/ceilf16.cpp +++ b/libc/src/math/generic/ceilf16.cpp @@ -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" @@ -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(__builtin_ceilf(x)); + return fputil::cast(__builtin_ceilf(x)); #else return fputil::ceil(x); #endif diff --git a/libc/src/math/generic/exp10f16.cpp b/libc/src/math/generic/exp10f16.cpp index 9959f7450b591..1c5966c1f1c12 100644 --- a/libc/src/math/generic/exp10f16.cpp +++ b/libc/src/math/generic/exp10f16.cpp @@ -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" @@ -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(10.0); + return fputil::cast(10.0); case 0x4000U: // x = 2.0f16 - return static_cast(100.0); + return fputil::cast(100.0); case 0x4200U: // x = 3.0f16 - return static_cast(1'000.0); + return fputil::cast(1'000.0); case 0x4400U: // x = 4.0f16 - return static_cast(10'000.0); + return fputil::cast(10'000.0); } } @@ -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(exp2_hi_mid * exp10_lo); + return fputil::cast(exp2_hi_mid * exp10_lo); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/exp2f16.cpp b/libc/src/math/generic/exp2f16.cpp index 66b7956704005..3c4310259b1df 100644 --- a/libc/src/math/generic/exp2f16.cpp +++ b/libc/src/math/generic/exp2f16.cpp @@ -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" @@ -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(exp2_hi_mid * exp2_lo); + return fputil::cast(exp2_hi_mid * exp2_lo); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/expf16.cpp b/libc/src/math/generic/expf16.cpp index 7ffdbd5191008..0548ef3932ae9 100644 --- a/libc/src/math/generic/expf16.cpp +++ b/libc/src/math/generic/expf16.cpp @@ -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" @@ -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( + return fputil::cast( fputil::polyeval(xf, 0x1p+0f, 0x1p+0f, 0x1.0004p-1f, 0x1.555778p-3f)); } } @@ -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(exp_hi_mid * exp_lo); + return fputil::cast(exp_hi_mid * exp_lo); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/expm1f16.cpp b/libc/src/math/generic/expm1f16.cpp index 0facdc510e428..4ce0efd1f461b 100644 --- a/libc/src/math/generic/expm1f16.cpp +++ b/libc/src/math/generic/expm1f16.cpp @@ -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" @@ -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(-0x1.ffcp-1)); + fputil::cast(-0x1.ffcp-1)); } // When 0 < |x| <= 2^(-3). @@ -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( + return fputil::cast( xf * fputil::polyeval(xf, 0x1p+0f, 0x1.fffff8p-2f, 0x1.555556p-3f, 0x1.55905ep-5f, 0x1.1124c2p-7f)); } @@ -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(fputil::multiply_add(exp_hi_mid, exp_lo, -1.0f)); + return fputil::cast(fputil::multiply_add(exp_hi_mid, exp_lo, -1.0f)); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/floorf16.cpp b/libc/src/math/generic/floorf16.cpp index 3092048f5ab06..361b22729f642 100644 --- a/libc/src/math/generic/floorf16.cpp +++ b/libc/src/math/generic/floorf16.cpp @@ -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" @@ -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(__builtin_floorf(x)); + return fputil::cast(__builtin_floorf(x)); #else return fputil::floor(x); #endif diff --git a/libc/src/math/generic/rintf16.cpp b/libc/src/math/generic/rintf16.cpp index 3a53dd28e3d10..aefdcbea77064 100644 --- a/libc/src/math/generic/rintf16.cpp +++ b/libc/src/math/generic/rintf16.cpp @@ -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" @@ -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(__builtin_rintf(x)); + return fputil::cast(__builtin_rintf(x)); #else return fputil::round_using_current_rounding_mode(x); #endif diff --git a/libc/src/math/generic/roundevenf16.cpp b/libc/src/math/generic/roundevenf16.cpp index c3dbd779b9739..fdcd968bc9b87 100644 --- a/libc/src/math/generic/roundevenf16.cpp +++ b/libc/src/math/generic/roundevenf16.cpp @@ -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" @@ -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(__builtin_roundevenf(x)); + return fputil::cast(__builtin_roundevenf(x)); #else return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST); #endif diff --git a/libc/src/math/generic/roundf16.cpp b/libc/src/math/generic/roundf16.cpp index a5e2b44fbd54b..9adfb52ed27c6 100644 --- a/libc/src/math/generic/roundf16.cpp +++ b/libc/src/math/generic/roundf16.cpp @@ -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" @@ -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(__builtin_roundf(x)); + return fputil::cast(__builtin_roundf(x)); #else return fputil::round(x); #endif diff --git a/libc/src/math/generic/truncf16.cpp b/libc/src/math/generic/truncf16.cpp index 31b1214a9a0e4..4d37e6560a965 100644 --- a/libc/src/math/generic/truncf16.cpp +++ b/libc/src/math/generic/truncf16.cpp @@ -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" @@ -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(__builtin_truncf(x)); + return fputil::cast(__builtin_truncf(x)); #else return fputil::trunc(x); #endif diff --git a/libc/test/src/math/smoke/AddTest.h b/libc/test/src/math/smoke/AddTest.h index 88c2067ca1474..f06a0868a520f 100644 --- a/libc/test/src/math/smoke/AddTest.h +++ b/libc/test/src/math/smoke/AddTest.h @@ -35,22 +35,22 @@ 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) { @@ -58,10 +58,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { 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); @@ -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), @@ -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); @@ -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, @@ -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); } }; diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 47e16926f10df..9f9203c491d04 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -401,6 +401,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.dfmal + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -413,6 +414,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.dfmaf128 + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -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( @@ -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( @@ -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( @@ -3317,6 +3322,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.fmaf + libc.src.__support.macros.properties.types FLAGS FMA_OPT__ONLY ) @@ -3331,6 +3337,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.fma + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -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( @@ -4352,6 +4360,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.f16fma + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -4364,6 +4373,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.f16fmaf + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -4376,6 +4386,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.f16fmal + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -4388,6 +4399,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.f16fmaf128 + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -4490,6 +4502,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.ffma + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -4502,6 +4515,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.ffmal + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -4514,6 +4528,7 @@ add_fp_unittest( FmaTest.h DEPENDS libc.src.math.ffmaf128 + libc.src.__support.macros.properties.types ) add_fp_unittest( diff --git a/libc/test/src/math/smoke/DivTest.h b/libc/test/src/math/smoke/DivTest.h index 666179628c55f..60e7a8adc9eba 100644 --- a/libc/test/src/math/smoke/DivTest.h +++ b/libc/test/src/math/smoke/DivTest.h @@ -28,45 +28,47 @@ 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); } @@ -74,64 +76,72 @@ class DivTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { 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); } diff --git a/libc/test/src/math/smoke/FModTest.h b/libc/test/src/math/smoke/FModTest.h index 0a4227da83f81..ad9688fc01e7c 100644 --- a/libc/test/src/math/smoke/FModTest.h +++ b/libc/test/src/math/smoke/FModTest.h @@ -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); diff --git a/libc/test/src/math/smoke/FmaTest.h b/libc/test/src/math/smoke/FmaTest.h index bf6d06d698fde..41093422d51b2 100644 --- a/libc/test/src/math/smoke/FmaTest.h +++ b/libc/test/src/math/smoke/FmaTest.h @@ -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" @@ -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(out.min_normal); + const InType in_out_min_denormal = + LIBC_NAMESPACE::fputil::cast(out.min_denormal); + public: using FmaFunc = OutType (*)(InType, InType, InType); @@ -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, @@ -63,8 +71,9 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { OutType v = OutFPBits(static_cast(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(v), + in_out_min_normal)); if constexpr (sizeof(OutType) < sizeof(InType)) { InFPBits tmp = InFPBits::one(); @@ -74,12 +83,21 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { InType v = InFPBits(static_cast(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(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) + 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( diff --git a/libc/test/src/math/smoke/ModfTest.h b/libc/test/src/math/smoke/ModfTest.h index 6226e5d55f40c..24cfb1152c2e5 100644 --- a/libc/test/src/math/smoke/ModfTest.h +++ b/libc/test/src/math/smoke/ModfTest.h @@ -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); } diff --git a/libc/test/src/math/smoke/MulTest.h b/libc/test/src/math/smoke/MulTest.h index 0c847e39687b7..c409122397b1d 100644 --- a/libc/test/src/math/smoke/MulTest.h +++ b/libc/test/src/math/smoke/MulTest.h @@ -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)); @@ -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); @@ -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), @@ -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); @@ -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, diff --git a/libc/test/src/math/smoke/NextTowardTest.h b/libc/test/src/math/smoke/NextTowardTest.h index 5992273d91901..61528f71305db 100644 --- a/libc/test/src/math/smoke/NextTowardTest.h +++ b/libc/test/src/math/smoke/NextTowardTest.h @@ -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(); @@ -134,7 +136,7 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { expected = LIBC_NAMESPACE::cpp::bit_cast(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(expected_bits); ASSERT_FP_EQ(result, expected); @@ -145,7 +147,7 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { expected = LIBC_NAMESPACE::cpp::bit_cast(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(expected_bits); ASSERT_FP_EQ(result, expected); @@ -156,14 +158,14 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { expected_bits = max_normal - 1; expected = LIBC_NAMESPACE::cpp::bit_cast(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(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; @@ -171,14 +173,14 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { expected_bits = max_normal; expected = LIBC_NAMESPACE::cpp::bit_cast(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(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); diff --git a/libc/test/src/math/smoke/SqrtTest.h b/libc/test/src/math/smoke/SqrtTest.h index ce9f2f85b4604..b5eaee22fc79d 100644 --- a/libc/test/src/math/smoke/SqrtTest.h +++ b/libc/test/src/math/smoke/SqrtTest.h @@ -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))); diff --git a/libc/test/src/math/smoke/SubTest.h b/libc/test/src/math/smoke/SubTest.h index 99c4b6c760af7..8793b9f157f72 100644 --- a/libc/test/src/math/smoke/SubTest.h +++ b/libc/test/src/math/smoke/SubTest.h @@ -34,22 +34,22 @@ 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) { @@ -57,10 +57,10 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { 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); @@ -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, @@ -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); @@ -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, @@ -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); } }; diff --git a/libc/test/src/math/smoke/exp10f16_test.cpp b/libc/test/src/math/smoke/exp10f16_test.cpp index 006dfafa8aa14..1c4ef2aa08a70 100644 --- a/libc/test/src/math/smoke/exp10f16_test.cpp +++ b/libc/test/src/math/smoke/exp10f16_test.cpp @@ -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" @@ -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(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(1.0f), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(1.0f), LIBC_NAMESPACE::exp10f16(zero)); EXPECT_MATH_ERRNO(0); - EXPECT_FP_EQ_ALL_ROUNDING(static_cast(1.0f), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(1.0f), LIBC_NAMESPACE::exp10f16(neg_zero)); EXPECT_MATH_ERRNO(0); } @@ -47,7 +47,8 @@ TEST_F(LlvmLibcExp10f16Test, Overflow) { EXPECT_MATH_ERRNO(ERANGE); EXPECT_FP_EQ_WITH_EXCEPTION( - inf, LIBC_NAMESPACE::exp10f16(static_cast(5.0)), FE_OVERFLOW); + inf, LIBC_NAMESPACE::exp10f16(LIBC_NAMESPACE::fputil::cast(5.0)), + FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } @@ -59,7 +60,8 @@ TEST_F(LlvmLibcExp10f16Test, Underflow) { EXPECT_MATH_ERRNO(ERANGE); EXPECT_FP_EQ_WITH_EXCEPTION( - zero, LIBC_NAMESPACE::exp10f16(static_cast(-8.0)), + zero, + LIBC_NAMESPACE::exp10f16(LIBC_NAMESPACE::fputil::cast(-8.0)), FE_UNDERFLOW | FE_INEXACT); EXPECT_MATH_ERRNO(ERANGE); } diff --git a/libc/test/src/math/smoke/exp2f16_test.cpp b/libc/test/src/math/smoke/exp2f16_test.cpp index cd87e6134557a..f69b33a3cf37f 100644 --- a/libc/test/src/math/smoke/exp2f16_test.cpp +++ b/libc/test/src/math/smoke/exp2f16_test.cpp @@ -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" @@ -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(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(1.0f), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(1.0f), LIBC_NAMESPACE::exp2f16(zero)); EXPECT_MATH_ERRNO(0); - EXPECT_FP_EQ_ALL_ROUNDING(static_cast(1.0f), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(1.0f), LIBC_NAMESPACE::exp2f16(neg_zero)); EXPECT_MATH_ERRNO(0); } @@ -47,7 +47,8 @@ TEST_F(LlvmLibcExp2f16Test, Overflow) { EXPECT_MATH_ERRNO(ERANGE); EXPECT_FP_EQ_WITH_EXCEPTION( - inf, LIBC_NAMESPACE::exp2f16(static_cast(16.0)), FE_OVERFLOW); + inf, LIBC_NAMESPACE::exp2f16(LIBC_NAMESPACE::fputil::cast(16.0)), + FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } @@ -59,7 +60,8 @@ TEST_F(LlvmLibcExp2f16Test, Underflow) { EXPECT_MATH_ERRNO(ERANGE); EXPECT_FP_EQ_WITH_EXCEPTION( - zero, LIBC_NAMESPACE::exp2f16(static_cast(-25.0)), + zero, + LIBC_NAMESPACE::exp2f16(LIBC_NAMESPACE::fputil::cast(-25.0)), FE_UNDERFLOW | FE_INEXACT); EXPECT_MATH_ERRNO(ERANGE); } diff --git a/libc/test/src/math/smoke/expf16_test.cpp b/libc/test/src/math/smoke/expf16_test.cpp index 969870fe247bc..ab745a3cf6f56 100644 --- a/libc/test/src/math/smoke/expf16_test.cpp +++ b/libc/test/src/math/smoke/expf16_test.cpp @@ -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" @@ -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(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(1.0f), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(1.0f), LIBC_NAMESPACE::expf16(zero)); EXPECT_MATH_ERRNO(0); - EXPECT_FP_EQ_ALL_ROUNDING(static_cast(1.0f), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(1.0f), LIBC_NAMESPACE::expf16(neg_zero)); EXPECT_MATH_ERRNO(0); } @@ -48,7 +48,8 @@ TEST_F(LlvmLibcExpf16Test, Overflow) { EXPECT_MATH_ERRNO(ERANGE); EXPECT_FP_EQ_WITH_EXCEPTION( - inf, LIBC_NAMESPACE::expf16(static_cast(12.0)), FE_OVERFLOW); + inf, LIBC_NAMESPACE::expf16(LIBC_NAMESPACE::fputil::cast(12.0)), + FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } @@ -60,7 +61,8 @@ TEST_F(LlvmLibcExpf16Test, Underflow) { EXPECT_MATH_ERRNO(ERANGE); EXPECT_FP_EQ_WITH_EXCEPTION( - zero, LIBC_NAMESPACE::expf16(static_cast(-18.0)), + zero, + LIBC_NAMESPACE::expf16(LIBC_NAMESPACE::fputil::cast(-18.0)), FE_UNDERFLOW | FE_INEXACT); EXPECT_MATH_ERRNO(ERANGE); } diff --git a/libc/test/src/math/smoke/expm1f16_test.cpp b/libc/test/src/math/smoke/expm1f16_test.cpp index 3bdbaad227941..f297c5dfc3c7e 100644 --- a/libc/test/src/math/smoke/expm1f16_test.cpp +++ b/libc/test/src/math/smoke/expm1f16_test.cpp @@ -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" @@ -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(-1.0), + EXPECT_FP_EQ_ALL_ROUNDING(LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::expm1f16(neg_inf)); EXPECT_MATH_ERRNO(0); @@ -46,7 +47,7 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) { EXPECT_MATH_ERRNO(ERANGE); // round(16 * log(2), HP, RN); - float16 x = static_cast(0x1.63p+3); + float16 x = LIBC_NAMESPACE::fputil::cast(0x1.63p+3); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(inf, LIBC_NAMESPACE::expm1f16(x), FE_OVERFLOW | FE_INEXACT); @@ -68,41 +69,44 @@ TEST_F(LlvmLibcExpm1f16Test, Overflow) { TEST_F(LlvmLibcExpm1f16Test, ResultNearNegOne) { LIBC_NAMESPACE::libc_errno = 0; - EXPECT_FP_EQ_WITH_EXCEPTION(static_cast(-1.0), + EXPECT_FP_EQ_WITH_EXCEPTION(LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::expm1f16(neg_max_normal), FE_INEXACT); // round(-11 * log(2), HP, RN); - float16 x = static_cast(-0x1.e8p+2); + float16 x = LIBC_NAMESPACE::fputil::cast(-0x1.e8p+2); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( - static_cast(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x), - FE_INEXACT); + LIBC_NAMESPACE::fputil::cast(-0x1.ffcp-1), + LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); - EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast(-0x1.ffcp-1), - LIBC_NAMESPACE::expm1f16(x), - FE_INEXACT); + EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD( + LIBC_NAMESPACE::fputil::cast(-0x1.ffcp-1), + LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( - static_cast(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); + LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::expm1f16(x), + FE_INEXACT); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( - static_cast(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x), - FE_INEXACT); + LIBC_NAMESPACE::fputil::cast(-0x1.ffcp-1), + LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); - x = static_cast(-0x1.0a4p+3); + x = LIBC_NAMESPACE::fputil::cast(-0x1.0a4p+3); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST( - static_cast(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); + LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::expm1f16(x), + FE_INEXACT); - EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(static_cast(-0x1.ffcp-1), - LIBC_NAMESPACE::expm1f16(x), - FE_INEXACT); + EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD( + LIBC_NAMESPACE::fputil::cast(-0x1.ffcp-1), + LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD( - static_cast(-1.0), LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); + LIBC_NAMESPACE::fputil::cast(-1.0), LIBC_NAMESPACE::expm1f16(x), + FE_INEXACT); EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO( - static_cast(-0x1.ffcp-1), LIBC_NAMESPACE::expm1f16(x), - FE_INEXACT); + LIBC_NAMESPACE::fputil::cast(-0x1.ffcp-1), + LIBC_NAMESPACE::expm1f16(x), FE_INEXACT); } diff --git a/libc/utils/MPFRWrapper/CMakeLists.txt b/libc/utils/MPFRWrapper/CMakeLists.txt index 941d3cf004d48..0101c9f399082 100644 --- a/libc/utils/MPFRWrapper/CMakeLists.txt +++ b/libc/utils/MPFRWrapper/CMakeLists.txt @@ -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 diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index 7ce6a70d09316..27ff1f7190ef9 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -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" @@ -683,7 +684,7 @@ template <> long double MPFRNumber::as() const { template <> float16 MPFRNumber::as() 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(mpfr_get_d(value, mpfr_rounding)); + return fputil::cast(mpfr_get_d(value, mpfr_rounding)); } #endif diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 4646aef95f949..bdc7bc8f9e065 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -774,6 +774,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"], @@ -791,9 +804,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", ], ) diff --git a/utils/bazel/llvm-project-overlay/libc/utils/MPFRWrapper/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/utils/MPFRWrapper/BUILD.bazel index adf4b235b1b5e..ca21eaee504ff 100644 --- a/utils/bazel/llvm-project-overlay/libc/utils/MPFRWrapper/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/utils/MPFRWrapper/BUILD.bazel @@ -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",