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 @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_HYPOT_H #include "BasicOperations.h" +#include "FEnvImpl.h" #include "FPBits.h" #include "src/__support/CPP/TypeTraits.h" @@ -143,11 +144,22 @@ if ((x_bits.get_unbiased_exponent() >= y_bits.get_unbiased_exponent() + MantissaWidth::VALUE + 2) || (y == 0)) { + // Check if the rounding mode is FE_UPWARD, will need -frounding-math so + // that the compiler does not optimize it away. + if ((y != 0) && (0x1p0f + 0x1p-24f != 0x1p0f)) { + UIntType out_bits = FPBits_t(abs(x)).uintval(); + return T(FPBits_t(++out_bits)); + } return abs(x); } else if ((y_bits.get_unbiased_exponent() >= x_bits.get_unbiased_exponent() + MantissaWidth::VALUE + 2) || (x == 0)) { - y_bits.set_sign(0); + // Check if the rounding mode is FE_UPWARD, will need -frounding-math so + // that the compiler does not optimize it away. + if ((x != 0) && (0x1p0f + 0x1p-24f != 0x1p0f)) { + UIntType out_bits = FPBits_t(abs(y)).uintval(); + return T(FPBits_t(++out_bits)); + } return abs(y); } @@ -250,8 +262,16 @@ y_new >>= 1; // Round to the nearest, tie to even. - if (round_bit && (lsb || sticky_bits || (r != 0))) { - ++y_new; + switch (get_round()) { + case FE_TONEAREST: + // Round to nearest, ties to even + if (round_bit && (lsb || sticky_bits || (r != 0))) + ++y_new; + break; + case FE_UPWARD: + if (round_bit || sticky_bits || (r != 0)) + ++y_new; + break; } if (y_new >= (ONE >> 1)) { 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 @@ -954,7 +954,9 @@ DEPENDS libc.src.__support.FPUtil.fputil COMPILE_OPTIONS - -O2 + -O3 + -frounding-math + -Wno-c++17-extensions ) add_entrypoint_object( @@ -1002,7 +1004,9 @@ DEPENDS libc.src.__support.FPUtil.fputil COMPILE_OPTIONS - -O2 + -O3 + -frounding-math + -Wno-c++17-extensions ) add_entrypoint_object( diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1060,6 +1060,8 @@ libc.include.math libc.src.math.hypotf libc.src.__support.FPUtil.fputil + COMPILE_OPTIONS + -Wno-c++17-extensions ) add_fp_unittest( @@ -1073,6 +1075,8 @@ libc.include.math libc.src.math.hypot libc.src.__support.FPUtil.fputil + COMPILE_OPTIONS + -Wno-c++17-extensions ) add_fp_unittest( diff --git a/libc/test/src/math/HypotTest.h b/libc/test/src/math/HypotTest.h --- a/libc/test/src/math/HypotTest.h +++ b/libc/test/src/math/HypotTest.h @@ -10,7 +10,6 @@ #define LLVM_LIBC_TEST_SRC_MATH_HYPOTTEST_H #include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/Hypot.h" #include "utils/MPFRWrapper/MPFRUtils.h" #include "utils/UnitTest/FPMatcher.h" #include "utils/UnitTest/Test.h" @@ -62,9 +61,9 @@ y = -y; } - T result = func(x, y); mpfr::BinaryInput input{x, y}; - ASSERT_MPFR_MATCH(mpfr::Operation::Hypot, input, result, 0.5); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Hypot, input, + func(x, y), 0.5); } } } @@ -85,12 +84,38 @@ y = -y; } - T result = func(x, y); mpfr::BinaryInput input{x, y}; - ASSERT_MPFR_MATCH(mpfr::Operation::Hypot, input, result, 0.5); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Hypot, input, + func(x, y), 0.5); } } } + + void test_tricky_inputs(Func func) { + constexpr int N = 15; + constexpr mpfr::BinaryInput INPUTS[N] = { + {0x1.ffffecp-1f, 0x1.000002p+27}, + {0x1.900004p+34, 0x1.400002p+23}, /* 45 identical bits */ + {0x1.05555p+34, 0x1.bffffep+23}, /* 44 identical bits */ + {0x1.e5fffap+34, 0x1.affffep+23}, /* 45 identical bits */ + {0x1.260002p+34, 0x1.500002p+23}, /* 45 identical bits */ + {0x1.fffffap+34, 0x1.fffffep+23}, /* 45 identical bits */ + {0x1.8ffffap+34, 0x1.3ffffep+23}, /* 45 identical bits */ + {0x1.87fffcp+35, 0x1.bffffep+23}, /* 47 identical bits */ + {0x1.b8e50ap-52, -0x1.db1e78p-64}, + {0x1.03b54cp-33, 0x1.6ca6bep-45}, + {0x1.e2eff6p+97, -0x1.044cb2p+108}, + {-0x1.6b05c4p-127, 0x1.6b3146p-126}, + {-0x1.6b05c4p-127, 0x1.6b3146p-126}, + {0x1.26b188p-127, -0x1.a4f2fp-128}, + {0x1.e2eff6p+97, -0x1.044cb2p+108}, + }; + + for (int i = 0; i < N; ++i) { + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Hypot, INPUTS[i], + func(INPUTS[i].x, INPUTS[i].y), 0.5); + } + } }; #endif // LLVM_LIBC_TEST_SRC_MATH_HYPOTTEST_H diff --git a/libc/test/src/math/differential_testing/CMakeLists.txt b/libc/test/src/math/differential_testing/CMakeLists.txt --- a/libc/test/src/math/differential_testing/CMakeLists.txt +++ b/libc/test/src/math/differential_testing/CMakeLists.txt @@ -406,6 +406,7 @@ libc.src.math.hypotf COMPILE_OPTIONS -fno-builtin + -Wno-c++17-extensions ) add_diff_binary( @@ -417,4 +418,5 @@ libc.src.math.hypot COMPILE_OPTIONS -fno-builtin + -Wno-c++17-extensions ) diff --git a/libc/test/src/math/hypotf_test.cpp b/libc/test/src/math/hypotf_test.cpp --- a/libc/test/src/math/hypotf_test.cpp +++ b/libc/test/src/math/hypotf_test.cpp @@ -23,3 +23,7 @@ TEST_F(LlvmLibcHypotfTest, NormalRange) { test_normal_range(&__llvm_libc::hypotf); } + +TEST_F(LlvmLibcHypotfTest, TrickyInputs) { + test_tricky_inputs(&__llvm_libc::hypotf); +}