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