1*71db0c75SAndroid Build Coastguard Worker //===-- Utility class to test different flavors of [l|ll]round --*- C++ -*-===// 2*71db0c75SAndroid Build Coastguard Worker // 3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*71db0c75SAndroid Build Coastguard Worker // 7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*71db0c75SAndroid Build Coastguard Worker 9*71db0c75SAndroid Build Coastguard Worker #ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDTOINTEGERTEST_H 10*71db0c75SAndroid Build Coastguard Worker #define LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDTOINTEGERTEST_H 11*71db0c75SAndroid Build Coastguard Worker 12*71db0c75SAndroid Build Coastguard Worker #include "src/__support/CPP/algorithm.h" 13*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/FEnvImpl.h" 14*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/FPBits.h" 15*71db0c75SAndroid Build Coastguard Worker #include "test/UnitTest/FEnvSafeTest.h" 16*71db0c75SAndroid Build Coastguard Worker #include "test/UnitTest/FPMatcher.h" 17*71db0c75SAndroid Build Coastguard Worker #include "test/UnitTest/Test.h" 18*71db0c75SAndroid Build Coastguard Worker 19*71db0c75SAndroid Build Coastguard Worker #include "hdr/math_macros.h" 20*71db0c75SAndroid Build Coastguard Worker 21*71db0c75SAndroid Build Coastguard Worker static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, 22*71db0c75SAndroid Build Coastguard Worker FE_TONEAREST}; 23*71db0c75SAndroid Build Coastguard Worker 24*71db0c75SAndroid Build Coastguard Worker template <typename F, typename I, bool TestModes = false> 25*71db0c75SAndroid Build Coastguard Worker class RoundToIntegerTestTemplate 26*71db0c75SAndroid Build Coastguard Worker : public LIBC_NAMESPACE::testing::FEnvSafeTest { 27*71db0c75SAndroid Build Coastguard Worker public: 28*71db0c75SAndroid Build Coastguard Worker typedef I (*RoundToIntegerFunc)(F); 29*71db0c75SAndroid Build Coastguard Worker 30*71db0c75SAndroid Build Coastguard Worker private: 31*71db0c75SAndroid Build Coastguard Worker DECLARE_SPECIAL_CONSTANTS(F) 32*71db0c75SAndroid Build Coastguard Worker 33*71db0c75SAndroid Build Coastguard Worker static constexpr StorageType MAX_SUBNORMAL = 34*71db0c75SAndroid Build Coastguard Worker FPBits::max_subnormal().uintval(); 35*71db0c75SAndroid Build Coastguard Worker static constexpr StorageType MIN_SUBNORMAL = 36*71db0c75SAndroid Build Coastguard Worker FPBits::min_subnormal().uintval(); 37*71db0c75SAndroid Build Coastguard Worker 38*71db0c75SAndroid Build Coastguard Worker static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1); 39*71db0c75SAndroid Build Coastguard Worker static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1); 40*71db0c75SAndroid Build Coastguard Worker test_one_input(RoundToIntegerFunc func,F input,I expected,bool expectError)41*71db0c75SAndroid Build Coastguard Worker void test_one_input(RoundToIntegerFunc func, F input, I expected, 42*71db0c75SAndroid Build Coastguard Worker bool expectError) { 43*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::libc_errno = 0; 44*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); 45*71db0c75SAndroid Build Coastguard Worker 46*71db0c75SAndroid Build Coastguard Worker ASSERT_EQ(func(input), expected); 47*71db0c75SAndroid Build Coastguard Worker 48*71db0c75SAndroid Build Coastguard Worker // TODO: Handle the !expectError case. It used to expect 49*71db0c75SAndroid Build Coastguard Worker // 0 for errno and exceptions, but this doesn't hold for 50*71db0c75SAndroid Build Coastguard Worker // all math functions using RoundToInteger test: 51*71db0c75SAndroid Build Coastguard Worker // https://github.com/llvm/llvm-project/pull/88816 52*71db0c75SAndroid Build Coastguard Worker if (expectError) { 53*71db0c75SAndroid Build Coastguard Worker ASSERT_FP_EXCEPTION(FE_INVALID); 54*71db0c75SAndroid Build Coastguard Worker ASSERT_MATH_ERRNO(EDOM); 55*71db0c75SAndroid Build Coastguard Worker } 56*71db0c75SAndroid Build Coastguard Worker } 57*71db0c75SAndroid Build Coastguard Worker 58*71db0c75SAndroid Build Coastguard Worker public: SetUp()59*71db0c75SAndroid Build Coastguard Worker void SetUp() override { 60*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::testing::FEnvSafeTest::SetUp(); 61*71db0c75SAndroid Build Coastguard Worker 62*71db0c75SAndroid Build Coastguard Worker if (math_errhandling & MATH_ERREXCEPT) { 63*71db0c75SAndroid Build Coastguard Worker // We will disable all exceptions so that the test will not 64*71db0c75SAndroid Build Coastguard Worker // crash with SIGFPE. We can still use fetestexcept to check 65*71db0c75SAndroid Build Coastguard Worker // if the appropriate flag was raised. 66*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT); 67*71db0c75SAndroid Build Coastguard Worker } 68*71db0c75SAndroid Build Coastguard Worker } 69*71db0c75SAndroid Build Coastguard Worker do_infinity_and_na_n_test(RoundToIntegerFunc func)70*71db0c75SAndroid Build Coastguard Worker void do_infinity_and_na_n_test(RoundToIntegerFunc func) { 71*71db0c75SAndroid Build Coastguard Worker test_one_input(func, inf, INTEGER_MAX, true); 72*71db0c75SAndroid Build Coastguard Worker test_one_input(func, neg_inf, INTEGER_MIN, true); 73*71db0c75SAndroid Build Coastguard Worker // This is currently never enabled, the 74*71db0c75SAndroid Build Coastguard Worker // LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR CMake option in 75*71db0c75SAndroid Build Coastguard Worker // libc/CMakeLists.txt is not forwarded to C++. 76*71db0c75SAndroid Build Coastguard Worker #if LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR 77*71db0c75SAndroid Build Coastguard Worker // Result is not well-defined, we always returns INTEGER_MAX 78*71db0c75SAndroid Build Coastguard Worker test_one_input(func, aNaN, INTEGER_MAX, true); 79*71db0c75SAndroid Build Coastguard Worker #endif // LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR 80*71db0c75SAndroid Build Coastguard Worker } 81*71db0c75SAndroid Build Coastguard Worker testInfinityAndNaN(RoundToIntegerFunc func)82*71db0c75SAndroid Build Coastguard Worker void testInfinityAndNaN(RoundToIntegerFunc func) { 83*71db0c75SAndroid Build Coastguard Worker if (TestModes) { 84*71db0c75SAndroid Build Coastguard Worker for (int mode : ROUNDING_MODES) { 85*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(mode); 86*71db0c75SAndroid Build Coastguard Worker do_infinity_and_na_n_test(func); 87*71db0c75SAndroid Build Coastguard Worker } 88*71db0c75SAndroid Build Coastguard Worker } else { 89*71db0c75SAndroid Build Coastguard Worker do_infinity_and_na_n_test(func); 90*71db0c75SAndroid Build Coastguard Worker } 91*71db0c75SAndroid Build Coastguard Worker } 92*71db0c75SAndroid Build Coastguard Worker do_round_numbers_test(RoundToIntegerFunc func)93*71db0c75SAndroid Build Coastguard Worker void do_round_numbers_test(RoundToIntegerFunc func) { 94*71db0c75SAndroid Build Coastguard Worker test_one_input(func, zero, I(0), false); 95*71db0c75SAndroid Build Coastguard Worker test_one_input(func, neg_zero, I(0), false); 96*71db0c75SAndroid Build Coastguard Worker test_one_input(func, F(1.0), I(1), false); 97*71db0c75SAndroid Build Coastguard Worker test_one_input(func, F(-1.0), I(-1), false); 98*71db0c75SAndroid Build Coastguard Worker test_one_input(func, F(10.0), I(10), false); 99*71db0c75SAndroid Build Coastguard Worker test_one_input(func, F(-10.0), I(-10), false); 100*71db0c75SAndroid Build Coastguard Worker test_one_input(func, F(1234.0), I(1234), false); 101*71db0c75SAndroid Build Coastguard Worker test_one_input(func, F(-1234.0), I(-1234), false); 102*71db0c75SAndroid Build Coastguard Worker } 103*71db0c75SAndroid Build Coastguard Worker testRoundNumbers(RoundToIntegerFunc func)104*71db0c75SAndroid Build Coastguard Worker void testRoundNumbers(RoundToIntegerFunc func) { 105*71db0c75SAndroid Build Coastguard Worker if (TestModes) { 106*71db0c75SAndroid Build Coastguard Worker for (int mode : ROUNDING_MODES) { 107*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(mode); 108*71db0c75SAndroid Build Coastguard Worker do_round_numbers_test(func); 109*71db0c75SAndroid Build Coastguard Worker } 110*71db0c75SAndroid Build Coastguard Worker } else { 111*71db0c75SAndroid Build Coastguard Worker do_round_numbers_test(func); 112*71db0c75SAndroid Build Coastguard Worker } 113*71db0c75SAndroid Build Coastguard Worker } 114*71db0c75SAndroid Build Coastguard Worker testSubnormalRange(RoundToIntegerFunc func)115*71db0c75SAndroid Build Coastguard Worker void testSubnormalRange(RoundToIntegerFunc func) { 116*71db0c75SAndroid Build Coastguard Worker constexpr int COUNT = 1'000'001; 117*71db0c75SAndroid Build Coastguard Worker constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max( 118*71db0c75SAndroid Build Coastguard Worker static_cast<StorageType>((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT), 119*71db0c75SAndroid Build Coastguard Worker StorageType(1)); 120*71db0c75SAndroid Build Coastguard Worker for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) { 121*71db0c75SAndroid Build Coastguard Worker F x = FPBits(i).get_val(); 122*71db0c75SAndroid Build Coastguard Worker if (x == F(0.0)) 123*71db0c75SAndroid Build Coastguard Worker continue; 124*71db0c75SAndroid Build Coastguard Worker // All subnormal numbers should round to zero. 125*71db0c75SAndroid Build Coastguard Worker if (TestModes) { 126*71db0c75SAndroid Build Coastguard Worker if (x > 0) { 127*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_UPWARD); 128*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(1), false); 129*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_DOWNWARD); 130*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(0), false); 131*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_TOWARDZERO); 132*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(0), false); 133*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_TONEAREST); 134*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(0), false); 135*71db0c75SAndroid Build Coastguard Worker } else { 136*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_UPWARD); 137*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(0), false); 138*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_DOWNWARD); 139*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(-1), false); 140*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_TOWARDZERO); 141*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(0), false); 142*71db0c75SAndroid Build Coastguard Worker LIBC_NAMESPACE::fputil::set_round(FE_TONEAREST); 143*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, I(0), false); 144*71db0c75SAndroid Build Coastguard Worker } 145*71db0c75SAndroid Build Coastguard Worker } else { 146*71db0c75SAndroid Build Coastguard Worker test_one_input(func, x, 0L, false); 147*71db0c75SAndroid Build Coastguard Worker } 148*71db0c75SAndroid Build Coastguard Worker } 149*71db0c75SAndroid Build Coastguard Worker } 150*71db0c75SAndroid Build Coastguard Worker }; 151*71db0c75SAndroid Build Coastguard Worker 152*71db0c75SAndroid Build Coastguard Worker #define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes) \ 153*71db0c75SAndroid Build Coastguard Worker using LlvmLibcRoundToIntegerTest = \ 154*71db0c75SAndroid Build Coastguard Worker RoundToIntegerTestTemplate<F, I, TestModes>; \ 155*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcRoundToIntegerTest, InfinityAndNaN) { \ 156*71db0c75SAndroid Build Coastguard Worker testInfinityAndNaN(&func); \ 157*71db0c75SAndroid Build Coastguard Worker } \ 158*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcRoundToIntegerTest, RoundNumbers) { \ 159*71db0c75SAndroid Build Coastguard Worker testRoundNumbers(&func); \ 160*71db0c75SAndroid Build Coastguard Worker } \ 161*71db0c75SAndroid Build Coastguard Worker TEST_F(LlvmLibcRoundToIntegerTest, SubnormalRange) { \ 162*71db0c75SAndroid Build Coastguard Worker testSubnormalRange(&func); \ 163*71db0c75SAndroid Build Coastguard Worker } 164*71db0c75SAndroid Build Coastguard Worker 165*71db0c75SAndroid Build Coastguard Worker #define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \ 166*71db0c75SAndroid Build Coastguard Worker LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false) 167*71db0c75SAndroid Build Coastguard Worker 168*71db0c75SAndroid Build Coastguard Worker // The GPU target does not support different rounding modes. 169*71db0c75SAndroid Build Coastguard Worker #ifdef LIBC_TARGET_ARCH_IS_GPU 170*71db0c75SAndroid Build Coastguard Worker #define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func) \ 171*71db0c75SAndroid Build Coastguard Worker LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false) 172*71db0c75SAndroid Build Coastguard Worker #else 173*71db0c75SAndroid Build Coastguard Worker #define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func) \ 174*71db0c75SAndroid Build Coastguard Worker LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true) 175*71db0c75SAndroid Build Coastguard Worker #endif 176*71db0c75SAndroid Build Coastguard Worker 177*71db0c75SAndroid Build Coastguard Worker #endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDTOINTEGERTEST_H 178