brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · c0b326e Raw
182 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDTOINTEGERTEST_H10#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDTOINTEGERTEST_H11 12#include "src/__support/CPP/algorithm.h"13#include "src/__support/FPUtil/FEnvImpl.h"14#include "src/__support/FPUtil/FPBits.h"15#include "src/__support/libc_errno.h"16#include "test/UnitTest/FEnvSafeTest.h"17#include "test/UnitTest/FPMatcher.h"18#include "test/UnitTest/Test.h"19 20#include "hdr/math_macros.h"21 22static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,23                                          FE_TONEAREST};24 25template <typename FloatType, typename IntType, bool TestModes = false>26class RoundToIntegerTestTemplate27    : public LIBC_NAMESPACE::testing::FEnvSafeTest {28public:29  typedef IntType (*RoundToIntegerFunc)(FloatType);30 31private:32  DECLARE_SPECIAL_CONSTANTS(FloatType)33 34  static constexpr StorageType MAX_SUBNORMAL =35      FPBits::max_subnormal().uintval();36  static constexpr StorageType MIN_SUBNORMAL =37      FPBits::min_subnormal().uintval();38 39  static constexpr IntType INTEGER_MIN = IntType(1)40                                         << (sizeof(IntType) * 8 - 1);41  static constexpr IntType INTEGER_MAX = -(INTEGER_MIN + 1);42 43  void test_one_input(RoundToIntegerFunc func, FloatType input,44                      IntType expected, bool expectError) {45    libc_errno = 0;46    LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);47 48    ASSERT_EQ(func(input), expected);49 50    // TODO: Handle the !expectError case. It used to expect51    // 0 for errno and exceptions, but this doesn't hold for52    // all math functions using RoundToInteger test:53    // https://github.com/llvm/llvm-project/pull/8881654    if (expectError) {55      ASSERT_FP_EXCEPTION(FE_INVALID);56      ASSERT_MATH_ERRNO(EDOM);57    }58  }59 60public:61  void SetUp() override {62    LIBC_NAMESPACE::testing::FEnvSafeTest::SetUp();63 64    if (math_errhandling & MATH_ERREXCEPT) {65      // We will disable all exceptions so that the test will not66      // crash with SIGFPE. We can still use fetestexcept to check67      // if the appropriate flag was raised.68      LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);69    }70  }71 72  void do_infinity_and_na_n_test(RoundToIntegerFunc func) {73    test_one_input(func, inf, INTEGER_MAX, true);74    test_one_input(func, neg_inf, INTEGER_MIN, true);75    // This is currently never enabled, the76    // LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR CMake option in77    // libc/CMakeLists.txt is not forwarded to C++.78#if LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR79    // Result is not well-defined, we always returns INTEGER_MAX80    test_one_input(func, aNaN, INTEGER_MAX, true);81#endif // LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR82  }83 84  void testInfinityAndNaN(RoundToIntegerFunc func) {85    if (TestModes) {86      for (int mode : ROUNDING_MODES) {87        LIBC_NAMESPACE::fputil::set_round(mode);88        do_infinity_and_na_n_test(func);89      }90    } else {91      do_infinity_and_na_n_test(func);92    }93  }94 95  void do_round_numbers_test(RoundToIntegerFunc func) {96    test_one_input(func, zero, IntType(0), false);97    test_one_input(func, neg_zero, IntType(0), false);98    test_one_input(func, FloatType(1.0), IntType(1), false);99    test_one_input(func, FloatType(-1.0), IntType(-1), false);100    test_one_input(func, FloatType(10.0), IntType(10), false);101    test_one_input(func, FloatType(-10.0), IntType(-10), false);102    test_one_input(func, FloatType(1232.0), IntType(1232), false);103    test_one_input(func, FloatType(-1232.0), IntType(-1232), false);104  }105 106  void testRoundNumbers(RoundToIntegerFunc func) {107    if (TestModes) {108      for (int mode : ROUNDING_MODES) {109        LIBC_NAMESPACE::fputil::set_round(mode);110        do_round_numbers_test(func);111      }112    } else {113      do_round_numbers_test(func);114    }115  }116 117  void testSubnormalRange(RoundToIntegerFunc func) {118    // Arbitrary, trades off completeness with testing time (esp. on failure)119    constexpr int COUNT = 1'000;120    constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(121        static_cast<StorageType>((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT),122        StorageType(1));123    for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {124      FloatType x = FPBits(i).get_val();125      if (x == FloatType(0.0))126        continue;127      // All subnormal numbers should round to zero.128      if (TestModes) {129        if (x > zero) {130          LIBC_NAMESPACE::fputil::set_round(FE_UPWARD);131          test_one_input(func, x, IntType(1), false);132          LIBC_NAMESPACE::fputil::set_round(FE_DOWNWARD);133          test_one_input(func, x, IntType(0), false);134          LIBC_NAMESPACE::fputil::set_round(FE_TOWARDZERO);135          test_one_input(func, x, IntType(0), false);136          LIBC_NAMESPACE::fputil::set_round(FE_TONEAREST);137          test_one_input(func, x, IntType(0), false);138        } else {139          LIBC_NAMESPACE::fputil::set_round(FE_UPWARD);140          test_one_input(func, x, IntType(0), false);141          LIBC_NAMESPACE::fputil::set_round(FE_DOWNWARD);142          test_one_input(func, x, IntType(-1), false);143          LIBC_NAMESPACE::fputil::set_round(FE_TOWARDZERO);144          test_one_input(func, x, IntType(0), false);145          LIBC_NAMESPACE::fputil::set_round(FE_TONEAREST);146          test_one_input(func, x, IntType(0), false);147        }148      } else {149        test_one_input(func, x, 0L, false);150      }151    }152  }153};154 155#define LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func,           \156                                           TestModes)                          \157  using LlvmLibcRoundToIntegerTest =                                           \158      RoundToIntegerTestTemplate<FloatType, IntType, TestModes>;               \159  TEST_F(LlvmLibcRoundToIntegerTest, InfinityAndNaN) {                         \160    testInfinityAndNaN(&func);                                                 \161  }                                                                            \162  TEST_F(LlvmLibcRoundToIntegerTest, RoundNumbers) {                           \163    testRoundNumbers(&func);                                                   \164  }                                                                            \165  TEST_F(LlvmLibcRoundToIntegerTest, SubnormalRange) {                         \166    testSubnormalRange(&func);                                                 \167  }168 169#define LIST_ROUND_TO_INTEGER_TESTS(FloatType, IntType, func)                  \170  LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func, false)171 172// The GPU target does not support different rounding modes.173#ifdef LIBC_TARGET_ARCH_IS_GPU174#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(FloatType, IntType, func)       \175  LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func, false)176#else177#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(FloatType, IntType, func)       \178  LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func, true)179#endif180 181#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDTOINTEGERTEST_H182