• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Utility class to test different flavors of nexttoward ---*- 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_NEXTTOWARDTEST_H
10 #define LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
11 
12 #include "src/__support/CPP/bit.h"
13 #include "src/__support/FPUtil/FEnvImpl.h"
14 #include "src/__support/FPUtil/FPBits.h"
15 #include "test/UnitTest/FEnvSafeTest.h"
16 #include "test/UnitTest/FPMatcher.h"
17 #include "test/UnitTest/Test.h"
18 
19 #include "hdr/fenv_macros.h"
20 
21 // TODO: Strengthen errno,exception checks and remove these assert macros
22 // after new matchers/test fixtures are added
23 #define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception)      \
24   ASSERT_FP_EQ(result, expected);                                              \
25   ASSERT_FP_EXCEPTION(expected_exception);                                     \
26   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT)
27 
28 #define ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected)                          \
29   ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, FE_INEXACT | FE_UNDERFLOW)
30 
31 #define ASSERT_FP_EQ_WITH_OVERFLOW(result, expected)                           \
32   ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, FE_INEXACT | FE_OVERFLOW)
33 
34 template <typename T>
35 class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
36   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
37   using ToFPBits = LIBC_NAMESPACE::fputil::FPBits<long double>;
38   using StorageType = typename FPBits::StorageType;
39 
40   const T inf = FPBits::inf(Sign::POS).get_val();
41   const T neg_inf = FPBits::inf(Sign::NEG).get_val();
42   const T zero = FPBits::zero(Sign::POS).get_val();
43   const T neg_zero = FPBits::zero(Sign::NEG).get_val();
44   const T nan = FPBits::quiet_nan().get_val();
45 
46   const long double to_zero = ToFPBits::zero().get_val();
47   const long double to_neg_zero = ToFPBits::zero(Sign::NEG).get_val();
48   const long double to_nan = ToFPBits::quiet_nan().get_val();
49 
50   static constexpr StorageType min_subnormal =
51       FPBits::min_subnormal().uintval();
52   static constexpr StorageType max_subnormal =
53       FPBits::max_subnormal().uintval();
54   static constexpr StorageType min_normal = FPBits::min_normal().uintval();
55   static constexpr StorageType max_normal = FPBits::max_normal().uintval();
56 
57 public:
58   typedef T (*NextTowardFunc)(T, long double);
59 
testNaN(NextTowardFunc func)60   void testNaN(NextTowardFunc func) {
61     ASSERT_FP_EQ(func(nan, 0), nan);
62     ASSERT_FP_EQ(func(0, to_nan), nan);
63   }
64 
testBoundaries(NextTowardFunc func)65   void testBoundaries(NextTowardFunc func) {
66     ASSERT_FP_EQ(func(zero, to_neg_zero), neg_zero);
67     ASSERT_FP_EQ(func(neg_zero, to_zero), zero);
68 
69     // 'from' is zero|neg_zero.
70     T x = zero;
71     T result = func(x, 1);
72     StorageType expected_bits = 1;
73     T expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
74     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
75 
76     result = func(x, -1);
77     expected_bits = FPBits::SIGN_MASK + 1;
78     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
79     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
80 
81     x = neg_zero;
82     result = func(x, 1);
83     expected_bits = 1;
84     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
85     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
86 
87     result = func(x, -1);
88     expected_bits = FPBits::SIGN_MASK + 1;
89     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
90     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
91 
92     // 'from' is max subnormal value.
93     x = LIBC_NAMESPACE::cpp::bit_cast<T>(max_subnormal);
94     result = func(x, 1);
95     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(min_normal);
96     ASSERT_FP_EQ(result, expected);
97 
98     result = func(x, 0);
99     expected_bits = max_subnormal - 1;
100     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
101     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
102 
103     x = -x;
104 
105     result = func(x, -1);
106     expected_bits = FPBits::SIGN_MASK + min_normal;
107     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
108     ASSERT_FP_EQ(result, expected);
109 
110     result = func(x, 0);
111     expected_bits = FPBits::SIGN_MASK + max_subnormal - 1;
112     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
113     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
114 
115     // 'from' is min subnormal value.
116     x = LIBC_NAMESPACE::cpp::bit_cast<T>(min_subnormal);
117     result = func(x, 1);
118     expected_bits = min_subnormal + 1;
119     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
120     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
121     ASSERT_FP_EQ_WITH_UNDERFLOW(func(x, 0), 0);
122 
123     x = -x;
124     result = func(x, -1);
125     expected_bits = FPBits::SIGN_MASK + min_subnormal + 1;
126     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
127     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
128     ASSERT_FP_EQ_WITH_UNDERFLOW(func(x, 0), T(-0.0));
129 
130     // 'from' is min normal.
131     x = LIBC_NAMESPACE::cpp::bit_cast<T>(min_normal);
132     result = func(x, 0);
133     expected_bits = max_subnormal;
134     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
135     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
136 
137     result = func(x, inf);
138     expected_bits = min_normal + 1;
139     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
140     ASSERT_FP_EQ(result, expected);
141 
142     x = -x;
143     result = func(x, 0);
144     expected_bits = FPBits::SIGN_MASK + max_subnormal;
145     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
146     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
147 
148     result = func(x, -inf);
149     expected_bits = FPBits::SIGN_MASK + min_normal + 1;
150     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
151     ASSERT_FP_EQ(result, expected);
152 
153     // 'from' is max normal
154     x = LIBC_NAMESPACE::cpp::bit_cast<T>(max_normal);
155     result = func(x, 0);
156     expected_bits = max_normal - 1;
157     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
158     ASSERT_FP_EQ(result, expected);
159     ASSERT_FP_EQ_WITH_OVERFLOW(func(x, inf), inf);
160 
161     x = -x;
162     result = func(x, 0);
163     expected_bits = FPBits::SIGN_MASK + max_normal - 1;
164     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
165     ASSERT_FP_EQ(result, expected);
166     ASSERT_FP_EQ_WITH_OVERFLOW(func(x, -inf), -inf);
167 
168     // 'from' is infinity.
169     x = inf;
170     result = func(x, 0);
171     expected_bits = max_normal;
172     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
173     ASSERT_FP_EQ(result, expected);
174     ASSERT_FP_EQ(func(x, inf), inf);
175 
176     x = neg_inf;
177     result = func(x, 0);
178     expected_bits = FPBits::SIGN_MASK + max_normal;
179     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
180     ASSERT_FP_EQ(result, expected);
181     ASSERT_FP_EQ(func(x, neg_inf), neg_inf);
182 
183     // 'from' is a power of 2.
184     x = T(32.0);
185     result = func(x, 0);
186     FPBits x_bits = FPBits(x);
187     FPBits result_bits = FPBits(result);
188     ASSERT_EQ(result_bits.get_biased_exponent(),
189               uint16_t(x_bits.get_biased_exponent() - 1));
190     ASSERT_EQ(result_bits.get_mantissa(), FPBits::FRACTION_MASK);
191 
192     result = func(x, 33.0);
193     result_bits = FPBits(result);
194     ASSERT_EQ(result_bits.get_biased_exponent(), x_bits.get_biased_exponent());
195     ASSERT_EQ(result_bits.get_mantissa(),
196               static_cast<StorageType>(x_bits.get_mantissa() + StorageType(1)));
197 
198     x = -x;
199 
200     result = func(x, 0);
201     result_bits = FPBits(result);
202     ASSERT_EQ(result_bits.get_biased_exponent(),
203               uint16_t(x_bits.get_biased_exponent() - 1));
204     ASSERT_EQ(result_bits.get_mantissa(), FPBits::FRACTION_MASK);
205 
206     result = func(x, -33.0);
207     result_bits = FPBits(result);
208     ASSERT_EQ(result_bits.get_biased_exponent(), x_bits.get_biased_exponent());
209     ASSERT_EQ(result_bits.get_mantissa(),
210               static_cast<StorageType>(x_bits.get_mantissa() + StorageType(1)));
211   }
212 };
213 
214 #define LIST_NEXTTOWARD_TESTS(T, func)                                         \
215   using LlvmLibcNextTowardTest = NextTowardTestTemplate<T>;                    \
216   TEST_F(LlvmLibcNextTowardTest, TestNaN) { testNaN(&func); }                  \
217   TEST_F(LlvmLibcNextTowardTest, TestBoundaries) { testBoundaries(&func); }
218 
219 #endif // LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
220