1 //===-- Utility class to test different flavors of [l|ll]round --*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H 10 #define LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H 11 12 #include "src/__support/FPUtil/FEnvImpl.h" 13 #include "src/__support/FPUtil/FPBits.h" 14 #include "utils/MPFRWrapper/MPFRUtils.h" 15 #include "utils/UnitTest/FPMatcher.h" 16 #include "utils/UnitTest/Test.h" 17 18 #include <errno.h> 19 #include <math.h> 20 21 namespace mpfr = __llvm_libc::testing::mpfr; 22 23 static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, 24 FE_TONEAREST}; 25 26 template <typename F, typename I, bool TestModes = false> 27 class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test { 28 public: 29 typedef I (*RoundToIntegerFunc)(F); 30 31 private: 32 using FPBits = __llvm_libc::fputil::FPBits<F>; 33 using UIntType = typename FPBits::UIntType; 34 35 const F zero = F(__llvm_libc::fputil::FPBits<F>::zero()); 36 const F neg_zero = F(__llvm_libc::fputil::FPBits<F>::neg_zero()); 37 const F inf = F(__llvm_libc::fputil::FPBits<F>::inf()); 38 const F neg_inf = F(__llvm_libc::fputil::FPBits<F>::neg_inf()); 39 const F nan = F(__llvm_libc::fputil::FPBits<F>::build_nan(1)); 40 static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1); 41 static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1); 42 test_one_input(RoundToIntegerFunc func,F input,I expected,bool expectError)43 void test_one_input(RoundToIntegerFunc func, F input, I expected, 44 bool expectError) { 45 errno = 0; 46 __llvm_libc::fputil::clear_except(FE_ALL_EXCEPT); 47 48 ASSERT_EQ(func(input), expected); 49 50 if (expectError) { 51 ASSERT_FP_EXCEPTION(FE_INVALID); 52 ASSERT_MATH_ERRNO(EDOM); 53 } else { 54 ASSERT_FP_EXCEPTION(0); 55 ASSERT_MATH_ERRNO(0); 56 } 57 } 58 to_mpfr_rounding_mode(int mode)59 static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) { 60 switch (mode) { 61 case FE_UPWARD: 62 return mpfr::RoundingMode::Upward; 63 case FE_DOWNWARD: 64 return mpfr::RoundingMode::Downward; 65 case FE_TOWARDZERO: 66 return mpfr::RoundingMode::TowardZero; 67 case FE_TONEAREST: 68 return mpfr::RoundingMode::Nearest; 69 default: 70 __builtin_unreachable(); 71 } 72 } 73 74 public: SetUp()75 void SetUp() override { 76 if (math_errhandling & MATH_ERREXCEPT) { 77 // We will disable all exceptions so that the test will not 78 // crash with SIGFPE. We can still use fetestexcept to check 79 // if the appropriate flag was raised. 80 __llvm_libc::fputil::disable_except(FE_ALL_EXCEPT); 81 } 82 } 83 do_infinity_and_na_n_test(RoundToIntegerFunc func)84 void do_infinity_and_na_n_test(RoundToIntegerFunc func) { 85 test_one_input(func, inf, INTEGER_MAX, true); 86 test_one_input(func, neg_inf, INTEGER_MIN, true); 87 test_one_input(func, nan, INTEGER_MAX, true); 88 } 89 testInfinityAndNaN(RoundToIntegerFunc func)90 void testInfinityAndNaN(RoundToIntegerFunc func) { 91 if (TestModes) { 92 for (int mode : ROUNDING_MODES) { 93 __llvm_libc::fputil::set_round(mode); 94 do_infinity_and_na_n_test(func); 95 } 96 } else { 97 do_infinity_and_na_n_test(func); 98 } 99 } 100 do_round_numbers_test(RoundToIntegerFunc func)101 void do_round_numbers_test(RoundToIntegerFunc func) { 102 test_one_input(func, zero, I(0), false); 103 test_one_input(func, neg_zero, I(0), false); 104 test_one_input(func, F(1.0), I(1), false); 105 test_one_input(func, F(-1.0), I(-1), false); 106 test_one_input(func, F(10.0), I(10), false); 107 test_one_input(func, F(-10.0), I(-10), false); 108 test_one_input(func, F(1234.0), I(1234), false); 109 test_one_input(func, F(-1234.0), I(-1234), false); 110 111 // The rest of this this function compares with an equivalent MPFR function 112 // which rounds floating point numbers to long values. There is no MPFR 113 // function to round to long long or wider integer values. So, we will 114 // the remaining tests only if the width of I less than equal to that of 115 // long. 116 if (sizeof(I) > sizeof(long)) 117 return; 118 119 constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1; 120 // We start with 1.0 so that the implicit bit for x86 long doubles 121 // is set. 122 FPBits bits(F(1.0)); 123 bits.set_unbiased_exponent(EXPONENT_LIMIT + FPBits::EXPONENT_BIAS); 124 bits.set_sign(1); 125 bits.set_mantissa(0); 126 127 F x = F(bits); 128 long mpfr_result; 129 bool erangeflag = mpfr::round_to_long(x, mpfr_result); 130 ASSERT_FALSE(erangeflag); 131 test_one_input(func, x, mpfr_result, false); 132 } 133 testRoundNumbers(RoundToIntegerFunc func)134 void testRoundNumbers(RoundToIntegerFunc func) { 135 if (TestModes) { 136 for (int mode : ROUNDING_MODES) { 137 __llvm_libc::fputil::set_round(mode); 138 do_round_numbers_test(func); 139 } 140 } else { 141 do_round_numbers_test(func); 142 } 143 } 144 do_fractions_test(RoundToIntegerFunc func,int mode)145 void do_fractions_test(RoundToIntegerFunc func, int mode) { 146 constexpr F FRACTIONS[] = {0.5, -0.5, 0.115, -0.115, 0.715, -0.715}; 147 for (F x : FRACTIONS) { 148 long mpfr_long_result; 149 bool erangeflag; 150 if (TestModes) 151 erangeflag = mpfr::round_to_long(x, to_mpfr_rounding_mode(mode), 152 mpfr_long_result); 153 else 154 erangeflag = mpfr::round_to_long(x, mpfr_long_result); 155 ASSERT_FALSE(erangeflag); 156 I mpfr_result = mpfr_long_result; 157 test_one_input(func, x, mpfr_result, false); 158 } 159 } 160 testFractions(RoundToIntegerFunc func)161 void testFractions(RoundToIntegerFunc func) { 162 if (TestModes) { 163 for (int mode : ROUNDING_MODES) { 164 __llvm_libc::fputil::set_round(mode); 165 do_fractions_test(func, mode); 166 } 167 } else { 168 // Passing 0 for mode has no effect as it is not used in doFractionsTest 169 // when `TestModes` is false; 170 do_fractions_test(func, 0); 171 } 172 } 173 testIntegerOverflow(RoundToIntegerFunc func)174 void testIntegerOverflow(RoundToIntegerFunc func) { 175 // This function compares with an equivalent MPFR function which rounds 176 // floating point numbers to long values. There is no MPFR function to 177 // round to long long or wider integer values. So, we will peform the 178 // comparisons in this function only if the width of I less than equal to 179 // that of long. 180 if (sizeof(I) > sizeof(long)) 181 return; 182 183 constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1; 184 // We start with 1.0 so that the implicit bit for x86 long doubles 185 // is set. 186 FPBits bits(F(1.0)); 187 bits.set_unbiased_exponent(EXPONENT_LIMIT + FPBits::EXPONENT_BIAS); 188 bits.set_sign(1); 189 bits.set_mantissa(UIntType(0x1) 190 << (__llvm_libc::fputil::MantissaWidth<F>::VALUE - 1)); 191 192 F x = F(bits); 193 if (TestModes) { 194 for (int m : ROUNDING_MODES) { 195 __llvm_libc::fputil::set_round(m); 196 long mpfr_long_result; 197 bool erangeflag = 198 mpfr::round_to_long(x, to_mpfr_rounding_mode(m), mpfr_long_result); 199 ASSERT_TRUE(erangeflag); 200 test_one_input(func, x, INTEGER_MIN, true); 201 } 202 } else { 203 long mpfr_long_result; 204 bool erangeflag = mpfr::round_to_long(x, mpfr_long_result); 205 ASSERT_TRUE(erangeflag); 206 test_one_input(func, x, INTEGER_MIN, true); 207 } 208 } 209 testSubnormalRange(RoundToIntegerFunc func)210 void testSubnormalRange(RoundToIntegerFunc func) { 211 constexpr UIntType COUNT = 1000001; 212 constexpr UIntType STEP = 213 (FPBits::MAX_SUBNORMAL - FPBits::MIN_SUBNORMAL) / COUNT; 214 for (UIntType i = FPBits::MIN_SUBNORMAL; i <= FPBits::MAX_SUBNORMAL; 215 i += STEP) { 216 F x = F(FPBits(i)); 217 if (x == F(0.0)) 218 continue; 219 // All subnormal numbers should round to zero. 220 if (TestModes) { 221 if (x > 0) { 222 __llvm_libc::fputil::set_round(FE_UPWARD); 223 test_one_input(func, x, I(1), false); 224 __llvm_libc::fputil::set_round(FE_DOWNWARD); 225 test_one_input(func, x, I(0), false); 226 __llvm_libc::fputil::set_round(FE_TOWARDZERO); 227 test_one_input(func, x, I(0), false); 228 __llvm_libc::fputil::set_round(FE_TONEAREST); 229 test_one_input(func, x, I(0), false); 230 } else { 231 __llvm_libc::fputil::set_round(FE_UPWARD); 232 test_one_input(func, x, I(0), false); 233 __llvm_libc::fputil::set_round(FE_DOWNWARD); 234 test_one_input(func, x, I(-1), false); 235 __llvm_libc::fputil::set_round(FE_TOWARDZERO); 236 test_one_input(func, x, I(0), false); 237 __llvm_libc::fputil::set_round(FE_TONEAREST); 238 test_one_input(func, x, I(0), false); 239 } 240 } else { 241 test_one_input(func, x, 0L, false); 242 } 243 } 244 } 245 testNormalRange(RoundToIntegerFunc func)246 void testNormalRange(RoundToIntegerFunc func) { 247 // This function compares with an equivalent MPFR function which rounds 248 // floating point numbers to long values. There is no MPFR function to 249 // round to long long or wider integer values. So, we will peform the 250 // comparisons in this function only if the width of I less than equal to 251 // that of long. 252 if (sizeof(I) > sizeof(long)) 253 return; 254 255 constexpr UIntType COUNT = 1000001; 256 constexpr UIntType STEP = (FPBits::MAX_NORMAL - FPBits::MIN_NORMAL) / COUNT; 257 for (UIntType i = FPBits::MIN_NORMAL; i <= FPBits::MAX_NORMAL; i += STEP) { 258 F x = F(FPBits(i)); 259 // In normal range on x86 platforms, the long double implicit 1 bit can be 260 // zero making the numbers NaN. We will skip them. 261 if (isnan(x)) { 262 continue; 263 } 264 265 if (TestModes) { 266 for (int m : ROUNDING_MODES) { 267 long mpfr_long_result; 268 bool erangeflag = mpfr::round_to_long(x, to_mpfr_rounding_mode(m), 269 mpfr_long_result); 270 I mpfr_result = mpfr_long_result; 271 __llvm_libc::fputil::set_round(m); 272 if (erangeflag) 273 test_one_input(func, x, x > 0 ? INTEGER_MAX : INTEGER_MIN, true); 274 else 275 test_one_input(func, x, mpfr_result, false); 276 } 277 } else { 278 long mpfr_long_result; 279 bool erangeflag = mpfr::round_to_long(x, mpfr_long_result); 280 I mpfr_result = mpfr_long_result; 281 if (erangeflag) 282 test_one_input(func, x, x > 0 ? INTEGER_MAX : INTEGER_MIN, true); 283 else 284 test_one_input(func, x, mpfr_result, false); 285 } 286 } 287 } 288 }; 289 290 #define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes) \ 291 using LlvmLibcRoundToIntegerTest = \ 292 RoundToIntegerTestTemplate<F, I, TestModes>; \ 293 TEST_F(LlvmLibcRoundToIntegerTest, InfinityAndNaN) { \ 294 testInfinityAndNaN(&func); \ 295 } \ 296 TEST_F(LlvmLibcRoundToIntegerTest, RoundNumbers) { \ 297 testRoundNumbers(&func); \ 298 } \ 299 TEST_F(LlvmLibcRoundToIntegerTest, Fractions) { testFractions(&func); } \ 300 TEST_F(LlvmLibcRoundToIntegerTest, IntegerOverflow) { \ 301 testIntegerOverflow(&func); \ 302 } \ 303 TEST_F(LlvmLibcRoundToIntegerTest, SubnormalRange) { \ 304 testSubnormalRange(&func); \ 305 } \ 306 TEST_F(LlvmLibcRoundToIntegerTest, NormalRange) { testNormalRange(&func); } 307 308 #define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \ 309 LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false) 310 311 #define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func) \ 312 LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true) 313 314 #endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H 315