diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -133,6 +133,7 @@ libc.src.__support.CPP.limits libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode libc.src.__support.builtin_wrappers libc.src.__support.common libc.src.errno.errno diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -2,6 +2,15 @@ fenv_impl HDRS FEnvImpl.h + DEPENDS + libc.include.fenv + libc.src.__support.macros.attributes +) + +add_header_library( + rounding_mode + HDRS + rounding_mode.h DEPENDS libc.include.fenv libc.include.math @@ -62,6 +71,7 @@ DEPENDS .fp_bits .fenv_impl + .rounding_mode libc.src.__support.CPP.type_traits libc.src.__support.common libc.include.math @@ -124,6 +134,7 @@ DEPENDS .fp_bits .fenv_impl + .rounding_mode libc.src.__support.CPP.optional libc.src.__support.macros.optimization ) @@ -137,6 +148,7 @@ .basic_operations .fenv_impl .fp_bits + .rounding_mode libc.src.__support.builtin_wrappers libc.src.__support.CPP.bit libc.src.__support.CPP.type_traits diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -12,6 +12,7 @@ #include "BasicOperations.h" #include "FEnvImpl.h" #include "FPBits.h" +#include "rounding_mode.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/UInt128.h" @@ -190,7 +191,7 @@ sum >>= 2; ++out_exp; if (out_exp >= FPBits_t::MAX_EXPONENT) { - if (int round_mode = get_round(); + if (int round_mode = quick_get_round(); round_mode == FE_TONEAREST || round_mode == FE_UPWARD) return T(FPBits_t::inf()); return T(FPBits_t(FPBits_t::MAX_NORMAL)); @@ -231,7 +232,7 @@ y_new >>= 1; // Round to the nearest, tie to even. - int round_mode = get_round(); + int round_mode = quick_get_round(); switch (round_mode) { case FE_TONEAREST: // Round to nearest, ties to even diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h --- a/libc/src/__support/FPUtil/NearestIntegerOperations.h +++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h @@ -11,6 +11,7 @@ #include "FEnvImpl.h" #include "FPBits.h" +#include "rounding_mode.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/common.h" @@ -162,7 +163,7 @@ bool is_neg = bits.get_sign(); int exponent = bits.get_exponent(); - int rounding_mode = get_round(); + int rounding_mode = quick_get_round(); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h --- a/libc/src/__support/FPUtil/except_value_utils.h +++ b/libc/src/__support/FPUtil/except_value_utils.h @@ -11,6 +11,7 @@ #include "FEnvImpl.h" #include "FPBits.h" +#include "rounding_mode.h" #include "src/__support/CPP/optional.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY @@ -52,7 +53,7 @@ for (size_t i = 0; i < N; ++i) { if (LIBC_UNLIKELY(x_bits == values[i].input)) { UIntType out_bits = values[i].rnd_towardzero_result; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_UPWARD: out_bits += values[i].rnd_upward_offset; break; @@ -74,7 +75,7 @@ for (size_t i = 0; i < N; ++i) { if (LIBC_UNLIKELY(x_abs == values[i].input)) { UIntType out_bits = values[i].rnd_towardzero_result; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_UPWARD: out_bits += sign ? values[i].rnd_downward_offset : values[i].rnd_upward_offset; diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -9,6 +9,7 @@ libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.platform_defs + libc.src.__support.FPUtil.rounding_mode libc.src.__support.builtin_wrappers libc.src.__support.common libc.src.__support.uint128 @@ -25,6 +26,7 @@ libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.float_properties libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode libc.src.__support.builtin_wrappers libc.src.__support.macros.optimization libc.src.__support.uint128 @@ -40,6 +42,7 @@ libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.float_properties libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode libc.src.__support.builtin_wrappers libc.src.__support.macros.optimization libc.src.math.generic.math_utils diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -13,6 +13,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/FloatProperties.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/UInt128.h" #include "src/__support/builtin_wrappers.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE @@ -254,7 +255,7 @@ } // Finalize the result. - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (LIBC_UNLIKELY(r_exp >= FPBits::MAX_EXPONENT)) { if ((round_mode == FE_TOWARDZERO) || (round_mode == FE_UPWARD && prod_sign) || diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -15,6 +15,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PlatformDefs.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/UInt128.h" #include "src/__support/builtin_wrappers.h" #include "src/__support/common.h" @@ -150,7 +151,7 @@ y = (y - ONE) | (static_cast(x_exp) << MantissaWidth::VALUE); - switch (get_round()) { + switch (quick_get_round()) { case FE_TONEAREST: // Round to nearest, ties to even if (rb && (lsb || (r != 0))) diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h --- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h +++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h @@ -12,6 +12,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PlatformDefs.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/UInt128.h" #include "src/__support/builtin_wrappers.h" #include "src/__support/common.h" @@ -114,7 +115,7 @@ y |= (static_cast(x_exp) << (MantissaWidth::VALUE + 1)); - switch (get_round()) { + switch (quick_get_round()) { case FE_TONEAREST: // Round to nearest, ties to even if (rb && (lsb || (r != 0))) diff --git a/libc/src/__support/FPUtil/rounding_mode.h b/libc/src/__support/FPUtil/rounding_mode.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/FPUtil/rounding_mode.h @@ -0,0 +1,79 @@ +//===---- Free-standing function to detect rounding mode --------*- 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_ROUNDING_MODE_H +#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_ROUNDING_MODE_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE + +#include + +namespace __llvm_libc::fputil { + +// Quick free-standing test whether fegetround() == FE_UPWARD. +// Using the following observation: +// 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.000002f for FE_UPWARD. +LIBC_INLINE bool fenv_is_round_up() { + volatile float x = 0x1.0p-25f; + return (1.0f + x != 1.0f); +} + +// Quick free-standing test whether fegetround() == FE_DOWNWARD. +// Using the following observation: +// -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO +// = -0x1.000002f for FE_DOWNWARD. +LIBC_INLINE bool fenv_is_round_down() { + volatile float x = 0x1.0p-25f; + return (-1.0f - x != -1.0f); +} + +// Quick free-standing test whether fegetround() == FE_TONEAREST. +// Using the following observation: +// 1.5f + 2^-24 = 1.5f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.100002p0f for FE_UPWARD, +// 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD +// = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO +LIBC_INLINE bool fenv_is_round_to_nearest() { + static volatile float x = 0x1.0p-24f; + float y = x; + return (1.5f + y == 1.5f - y); +} + +// Quick free-standing test whether fegetround() == FE_TOWARDZERO. +// Using the following observation: +// 1.0f + 2^-23 + 2^-24 = 0x1.000002p0f for FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.000004p0f for FE_TONEAREST, FE_UPWARD, +// -1.0f - 2^-24 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO +// = -0x1.000002p0f for FE_DOWNWARD +// So: +// (0x1.000002p0f + 2^-24) + (-1.0f - 2^-24) = 2^-23 for FE_TOWARDZERO +// = 2^-22 for FE_TONEAREST, FE_UPWARD +// = 0 for FE_DOWNWARD +LIBC_INLINE bool fenv_is_round_to_zero() { + static volatile float x = 0x1.0p-24f; + float y = x; + return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); +} + +// Quick free standing get rounding mode based on the above observations. +LIBC_INLINE int quick_get_round() { + static volatile float x = 0x1.0p-24f; + float y = x; + float z = (0x1.000002p0f + y) + (-1.0f - y); + + if (z == 0.0f) + return FE_DOWNWARD; + if (z == 0x1.0p-23f) + return FE_TOWARDZERO; + return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; +} + +} // namespace __llvm_libc::fputil + +#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_ROUNDING_MODE_H diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -13,6 +13,7 @@ #include "src/__support/CPP/optional.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/UInt128.h" #include "src/__support/builtin_wrappers.h" #include "src/__support/common.h" @@ -1120,7 +1121,7 @@ RoundDirection round_direction = RoundDirection::Nearest; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: round_direction = RoundDirection::Nearest; break; diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -109,6 +109,7 @@ libc.src.__support.FPUtil.fma libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 @@ -130,6 +131,7 @@ libc.src.__support.FPUtil.fma libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 @@ -542,6 +544,7 @@ 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.optimization libc.include.errno libc.src.errno.errno @@ -563,6 +566,7 @@ 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.optimization libc.include.errno libc.src.errno.errno @@ -584,6 +588,7 @@ 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.optimization libc.include.errno libc.src.errno.errno @@ -606,6 +611,7 @@ 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.optimization libc.include.errno libc.src.errno.errno @@ -1336,6 +1342,7 @@ .explogxf libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 @@ -1350,6 +1357,7 @@ DEPENDS .explogxf libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 @@ -1364,6 +1372,7 @@ DEPENDS .explogxf libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 @@ -1483,6 +1492,7 @@ .inv_trigf_utils .math_utils libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 diff --git a/libc/src/math/generic/atanf.cpp b/libc/src/math/generic/atanf.cpp --- a/libc/src/math/generic/atanf.cpp +++ b/libc/src/math/generic/atanf.cpp @@ -9,6 +9,7 @@ #include "src/math/atanf.h" #include "math_utils.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/math/generic/inv_trigf_utils.h" @@ -28,7 +29,7 @@ } // |x| == 0.06905200332403183 if (LIBC_UNLIKELY(xbits.uintval() == 0x3d8d6b23U)) { - if (fputil::get_round() == FE_TONEAREST) { + if (fputil::fenv_is_round_to_nearest()) { // 0.06894256919622421 FPBits br(0x3d8d31c3U); br.set_sign(sign); @@ -38,7 +39,7 @@ // |x| == 1.8670953512191772 if (LIBC_UNLIKELY(xbits.uintval() == 0x3feefcfbU)) { - int rounding_mode = fputil::get_round(); + int rounding_mode = fputil::quick_get_round(); if (sign) { if (rounding_mode == FE_DOWNWARD) { // -1.0790828466415405 diff --git a/libc/src/math/generic/coshf.cpp b/libc/src/math/generic/coshf.cpp --- a/libc/src/math/generic/coshf.cpp +++ b/libc/src/math/generic/coshf.cpp @@ -9,6 +9,7 @@ #include "src/math/coshf.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/math/generic/explogxf.h" @@ -32,7 +33,7 @@ if (xbits.is_inf_or_nan()) return x + FPBits::inf().get_val(); - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) return FPBits(FPBits::MAX_NORMAL).get_val(); diff --git a/libc/src/math/generic/exp10f.cpp b/libc/src/math/generic/exp10f.cpp --- a/libc/src/math/generic/exp10f.cpp +++ b/libc/src/math/generic/exp10f.cpp @@ -14,6 +14,7 @@ #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY @@ -38,7 +39,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return static_cast(FPBits(FPBits::MIN_SUBNORMAL)); fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_UNDERFLOW); @@ -48,7 +49,7 @@ if (!xbits.get_sign() && (x_u >= 0x421a'209bU)) { // x is finite if (x_u < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); @@ -63,7 +64,7 @@ // When |x| <= log10(2)*2^-6 if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) { if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) { // x = -0x1.bcb7b2p-27f - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return 0x1.fffffep-1f; } // |x| < 2^-25 @@ -77,7 +78,7 @@ // Exceptional value. if (LIBC_UNLIKELY(x_u == 0x3d14'd956U)) { // x = 0x1.29b2acp-5f - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return 0x1.1657c4p+0f; } diff --git a/libc/src/math/generic/exp2f.cpp b/libc/src/math/generic/exp2f.cpp --- a/libc/src/math/generic/exp2f.cpp +++ b/libc/src/math/generic/exp2f.cpp @@ -12,6 +12,7 @@ #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY @@ -44,7 +45,7 @@ if (!xbits.get_sign()) { // x is finite if (x_u < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); @@ -62,7 +63,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return FPBits(FPBits::MIN_SUBNORMAL).get_val(); if (x != 0.0f) { fputil::set_errno_if_required(ERANGE); @@ -75,10 +76,10 @@ // Check exceptional values. if (LIBC_UNLIKELY((x_u & EXVAL_MASK) == EXVAL_MASK)) { if (LIBC_UNLIKELY(x_u == EXVAL1)) { // x = 0x1.853a6ep-9f - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return 0x1.00870ap+0f; } else if (LIBC_UNLIKELY(x_u == EXVAL2)) { // x = -0x1.e7526ep-6f - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return 0x1.f58d62p-1f; } } diff --git a/libc/src/math/generic/expf.cpp b/libc/src/math/generic/expf.cpp --- a/libc/src/math/generic/expf.cpp +++ b/libc/src/math/generic/expf.cpp @@ -14,6 +14,7 @@ #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY @@ -48,7 +49,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return static_cast(FPBits(FPBits::MIN_SUBNORMAL)); fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_UNDERFLOW); @@ -58,7 +59,7 @@ if (!xbits.get_sign() && (xbits.uintval() >= 0x42b2'0000)) { // x is finite if (xbits.uintval() < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); diff --git a/libc/src/math/generic/expm1f.cpp b/libc/src/math/generic/expm1f.cpp --- a/libc/src/math/generic/expm1f.cpp +++ b/libc/src/math/generic/expm1f.cpp @@ -15,6 +15,7 @@ #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA @@ -32,7 +33,7 @@ // Exceptional value if (LIBC_UNLIKELY(x_u == 0x3e35'bec5U)) { // x = 0x1.6b7d8ap-3f - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD) return 0x1.8dbe64p-3f; return 0x1.8dbe62p-3f; @@ -40,7 +41,7 @@ #if !defined(LIBC_TARGET_CPU_HAS_FMA) if (LIBC_UNLIKELY(x_u == 0xbdc1'c6cbU)) { // x = -0x1.838d96p-4f - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (round_mode == FE_TONEAREST || round_mode == FE_DOWNWARD) return -0x1.71c884p-4f; return -0x1.71c882p-4f; @@ -57,7 +58,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (round_mode == FE_UPWARD || round_mode == FE_TOWARDZERO) return -0x1.ffff'fep-1f; // -1.0f + 0x1.0p-24f return -1.0f; @@ -65,7 +66,7 @@ // x >= 89 or nan if (xbits.uintval() >= 0x42b2'0000) { if (xbits.uintval() < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); diff --git a/libc/src/math/generic/sincosf.cpp b/libc/src/math/generic/sincosf.cpp --- a/libc/src/math/generic/sincosf.cpp +++ b/libc/src/math/generic/sincosf.cpp @@ -11,6 +11,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA @@ -159,7 +160,7 @@ uint32_t s = EXCEPT_OUTPUTS_SIN[i][0]; // FE_TOWARDZERO uint32_t c = EXCEPT_OUTPUTS_COS[i][0]; // FE_TOWARDZERO bool x_sign = x < 0; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_UPWARD: s += x_sign ? EXCEPT_OUTPUTS_SIN[i][2] : EXCEPT_OUTPUTS_SIN[i][1]; c += EXCEPT_OUTPUTS_COS[i][1]; diff --git a/libc/src/math/generic/sinf.cpp b/libc/src/math/generic/sinf.cpp --- a/libc/src/math/generic/sinf.cpp +++ b/libc/src/math/generic/sinf.cpp @@ -13,6 +13,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA @@ -126,7 +127,7 @@ if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13 float r = -0x1.63f4bap-2f; - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); bool sign = xbits.get_sign(); if ((rounding == FE_DOWNWARD && !sign) || (rounding == FE_UPWARD && sign)) r = -0x1.63f4bcp-2f; diff --git a/libc/src/math/generic/sinhf.cpp b/libc/src/math/generic/sinhf.cpp --- a/libc/src/math/generic/sinhf.cpp +++ b/libc/src/math/generic/sinhf.cpp @@ -8,6 +8,7 @@ #include "src/math/sinhf.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/math/generic/explogxf.h" @@ -33,7 +34,7 @@ if (xbits.is_inf()) return x; - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (sign) { if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) return FPBits(FPBits::MAX_NORMAL | FPBits::FloatProp::SIGN_MASK) @@ -53,7 +54,7 @@ if (LIBC_UNLIKELY(x_abs <= 0x3da0'0000U)) { // |x| = 0.0005589424981735646724700927734375 if (LIBC_UNLIKELY(x_abs == 0x3a12'85ffU)) { - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return x; } diff --git a/libc/src/math/generic/tanhf.cpp b/libc/src/math/generic/tanhf.cpp --- a/libc/src/math/generic/tanhf.cpp +++ b/libc/src/math/generic/tanhf.cpp @@ -8,6 +8,7 @@ #include "src/math/tanhf.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA #include "src/math/generic/explogxf.h" @@ -52,7 +53,7 @@ } if (LIBC_UNLIKELY(xbits.bits == 0x4058'e0a3U)) { - if (fputil::get_round() == FE_DOWNWARD) + if (fputil::fenv_is_round_down()) return FPBits(0x3f7f'6ad9U).get_val(); } diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -93,6 +93,7 @@ libc.src.__support.CPP.string_view libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.rounding_mode libc.src.__support.common libc.src.__support.libc_assert libc.src.__support.uint diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -13,6 +13,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/FloatProperties.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/UInt.h" #include "src/__support/UInt128.h" #include "src/__support/common.h" @@ -600,7 +601,7 @@ (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), static_cast(requiredTwos))); - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (last_digit != 5) { @@ -774,7 +775,7 @@ (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), static_cast(requiredTwos))); - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (last_digit != 5) { @@ -1022,7 +1023,7 @@ (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), static_cast(requiredTwos))); - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (last_digit != 5) { diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h --- a/libc/src/stdio/printf_core/float_hex_converter.h +++ b/libc/src/stdio/printf_core/float_hex_converter.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/string_view.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/common.h" #include "src/stdio/printf_core/converter_utils.h" #include "src/stdio/printf_core/core_structs.h" @@ -113,7 +114,7 @@ mantissa >>= shift_amount; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (truncated_bits > halfway_const) diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt --- a/libc/test/src/__support/FPUtil/CMakeLists.txt +++ b/libc/test/src/__support/FPUtil/CMakeLists.txt @@ -21,3 +21,13 @@ libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.fpbits_str ) + +add_fp_unittest( + rounding_mode_test + SUITE + libc-fputil-tests + SRCS + rounding_mode_test.cpp + DEPENDS + libc.src.__support.FPUtil.rounding_mode +) diff --git a/libc/test/src/__support/FPUtil/rounding_mode_test.cpp b/libc/test/src/__support/FPUtil/rounding_mode_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/__support/FPUtil/rounding_mode_test.cpp @@ -0,0 +1,116 @@ +//===-- Unittests for the quick rounding mode checks ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/FPUtil/rounding_mode.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +#include + +using __llvm_libc::testing::mpfr::ForceRoundingMode; +using __llvm_libc::testing::mpfr::RoundingMode; + +TEST(LlvmLibcFEnvImplTest, QuickRoundingUpTest) { + using __llvm_libc::fputil::fenv_is_round_up; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_TRUE(fenv_is_round_up()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_FALSE(fenv_is_round_up()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_FALSE(fenv_is_round_up()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_FALSE(fenv_is_round_up()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickRoundingDownTest) { + using __llvm_libc::fputil::fenv_is_round_down; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_FALSE(fenv_is_round_down()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_TRUE(fenv_is_round_down()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_FALSE(fenv_is_round_down()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_FALSE(fenv_is_round_down()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickRoundingNearestTest) { + using __llvm_libc::fputil::fenv_is_round_to_nearest; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_FALSE(fenv_is_round_to_nearest()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_FALSE(fenv_is_round_to_nearest()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_TRUE(fenv_is_round_to_nearest()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_FALSE(fenv_is_round_to_nearest()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickRoundingTowardZeroTest) { + using __llvm_libc::fputil::fenv_is_round_to_zero; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_FALSE(fenv_is_round_to_zero()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_FALSE(fenv_is_round_to_zero()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_FALSE(fenv_is_round_to_zero()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_TRUE(fenv_is_round_to_zero()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickGetRoundTest) { + using __llvm_libc::fputil::quick_get_round; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_EQ(quick_get_round(), FE_UPWARD); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_EQ(quick_get_round(), FE_DOWNWARD); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_EQ(quick_get_round(), FE_TONEAREST); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_EQ(quick_get_round(), FE_TOWARDZERO); + } +} diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -444,6 +444,7 @@ ":__support_ctype_utils", ":__support_fputil_fenv_impl", ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", ":__support_str_to_integer", ":__support_str_to_num_result", ":__support_uint128", @@ -529,6 +530,7 @@ ":__support_cpp_optional", ":__support_fputil_fenv_impl", ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", ":libc_root", ], ) @@ -551,6 +553,15 @@ ], ) +libc_support_library( + name = "__support_fputil_rounding_mode", + hdrs = ["src/__support/FPUtil/rounding_mode.h"], + deps = [ + ":__support_macros_attributes", + ":libc_root", + ], +) + libc_support_library( name = "__support_fputil_float_properties", hdrs = ["src/__support/FPUtil/FloatProperties.h"], @@ -604,6 +615,7 @@ ":__support_fputil_basic_operations", ":__support_fputil_fenv_impl", ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", ":__support_uint128", ":libc_root", ], @@ -635,6 +647,7 @@ ":__support_cpp_type_traits", ":__support_fputil_fenv_impl", ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", ":libc_root", ], ) @@ -686,6 +699,7 @@ ":__support_fputil_fenv_impl", ":__support_fputil_fp_bits", ":__support_fputil_platform_defs", + ":__support_fputil_rounding_mode", ":__support_uint128", ":libc_root", ], @@ -714,6 +728,7 @@ ":__support_fputil_fenv_impl", ":__support_fputil_float_properties", ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", ":__support_macros_attributes", ":__support_macros_optimization", ":__support_macros_properties_cpu_features", @@ -1137,6 +1152,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":__support_macros_properties_cpu_features", ":common_constants", @@ -1150,6 +1166,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":common_constants", ], @@ -1162,6 +1179,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":common_constants", ":explogxf", @@ -1175,6 +1193,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":explogxf", ], @@ -1293,6 +1312,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":common_constants", ":explogxf", @@ -1306,6 +1326,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":common_constants", ":explogxf", @@ -1319,6 +1340,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":__support_macros_properties_cpu_features", ":common_constants", @@ -1401,6 +1423,7 @@ ":__support_fputil_multiply_add", ":__support_fputil_nearest_integer", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":inv_trigf_utils", ":math_utils", @@ -1583,6 +1606,7 @@ additional_deps = [ ":__support_fputil_fma", ":__support_fputil_multiply_add", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":__support_macros_properties_cpu_features", ":sincosf_utils", @@ -1595,6 +1619,7 @@ ":__support_fputil_fma", ":__support_fputil_multiply_add", ":__support_fputil_polyeval", + ":__support_fputil_rounding_mode", ":__support_macros_optimization", ":__support_macros_properties_cpu_features", ":range_reduction", @@ -2552,6 +2577,7 @@ ":__support_fputil_fenv_impl", ":__support_fputil_float_properties", ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", ":__support_integer_to_string", ":__support_libc_assert", ":__support_uint",