diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -90,8 +90,13 @@ static_assert(sizeof(T) == sizeof(UIntType), "Data type and integral representation have different sizes."); - static constexpr int EXPONENT_BIAS = (1 << (ExponentWidth::VALUE - 1)) - 1; - static constexpr int MAX_EXPONENT = (1 << ExponentWidth::VALUE) - 1; + static constexpr int EXPONENT_BIAS = + (UIntType(1) << (ExponentWidth::VALUE - 1)) - 1; + static constexpr int MAX_EXPONENT = + (UIntType(1) << ExponentWidth::VALUE) - 1; + + static constexpr UIntType QUIET_BIT = + (UIntType(1) << (MantissaWidth::VALUE - 1)); static constexpr UIntType MIN_SUBNORMAL = UIntType(1); static constexpr UIntType MAX_SUBNORMAL = @@ -164,9 +169,17 @@ return bits; } + // Always generate quiet NaNs to avoid transformation of signaling NaNs: + // C17 F10.9.2: "if just one argument is a NaN, the [fmin/fmax] functions + // return the other argument" + // IEEE 754-2019 6.2, 9.6: "if either operand is a signaling NaN, an invalid + // operation exception is signaled... under default exception handling, any + // operation signaling an invalid operation exception and for which a + // floating-point result is to be delivered, except as stated otherwise, + // shall deliver a quiet NaN." static constexpr T build_nan(UIntType v) { FPBits bits = inf(); - bits.set_mantissa(v); + bits.set_mantissa(QUIET_BIT | v); return T(bits); } diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h --- a/libc/test/src/math/RoundToIntegerTest.h +++ b/libc/test/src/math/RoundToIntegerTest.h @@ -84,7 +84,10 @@ void do_infinity_and_na_n_test(RoundToIntegerFunc func) { test_one_input(func, inf, INTEGER_MAX, true); test_one_input(func, neg_inf, INTEGER_MIN, true); +#ifndef LLVM_LIBC_NO_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR + // Result is not well-defined, we always returns INTEGER_MAX test_one_input(func, nan, INTEGER_MAX, true); +#endif } void testInfinityAndNaN(RoundToIntegerFunc func) { diff --git a/libc/utils/UnitTest/FPMatcher.h b/libc/utils/UnitTest/FPMatcher.h --- a/libc/utils/UnitTest/FPMatcher.h +++ b/libc/utils/UnitTest/FPMatcher.h @@ -67,12 +67,22 @@ } // namespace fputil } // namespace __llvm_libc +// Always generate quiet NaNs to avoid transformation of signaling NaNs: +// C17 F10.9.2: "if just one argument is a NaN, the [fmin/fmax] functions return +// the other argument" +// IEEE 754-2019 6.2, 9.6: "if either operand is a signaling NaN, an invalid +// operation exception is signaled.. under default exception handling, any +// operation signaling an invalid operation exception and for which a +// floating-point result is to be delivered, except as stated otherwise, shall +// deliver a quiet NaN." #define DECLARE_SPECIAL_CONSTANTS(T) \ using FPBits = __llvm_libc::fputil::FPBits; \ + using MantissaWidth = __llvm_libc::fputil::MantissaWidth; \ using UIntType = typename FPBits::UIntType; \ const T zero = T(FPBits::zero()); \ const T neg_zero = T(FPBits::neg_zero()); \ - const T aNaN = T(FPBits::build_nan(1)); \ + const T aNaN = \ + T(FPBits::build_nan((1UL << (MantissaWidth::VALUE - 1)) | 1)); \ const T inf = T(FPBits::inf()); \ const T neg_inf = T(FPBits::neg_inf());