xref: /aosp_15_r20/external/llvm-libc/test/src/math/smoke/RoundToIntegerTest.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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