Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- FPMatchers.h --------------------------------------------*- 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_UNITTEST_FPMATCHER_H |
10 | #define LLVM_LIBC_TEST_UNITTEST_FPMATCHER_H |
11 | |
12 | #include "src/__support/CPP/array.h" |
13 | #include "src/__support/CPP/type_traits.h" |
14 | #include "src/__support/FPUtil/FEnvImpl.h" |
15 | #include "src/__support/FPUtil/FPBits.h" |
16 | #include "src/__support/FPUtil/fpbits_str.h" |
17 | #include "src/__support/macros/config.h" |
18 | #include "src/__support/macros/properties/architectures.h" |
19 | #include "test/UnitTest/RoundingModeUtils.h" |
20 | #include "test/UnitTest/StringUtils.h" |
21 | #include "test/UnitTest/Test.h" |
22 | |
23 | #include "hdr/math_macros.h" |
24 | |
25 | using LIBC_NAMESPACE::Sign; |
26 | |
27 | namespace LIBC_NAMESPACE_DECL { |
28 | namespace testing { |
29 | |
30 | template <typename T, TestCond Condition> class FPMatcher : public Matcher<T> { |
31 | static_assert(cpp::is_floating_point_v<T>, |
32 | "FPMatcher can only be used with floating point values."); |
33 | static_assert(Condition == TestCond::EQ || Condition == TestCond::NE, |
34 | "Unsupported FPMatcher test condition."); |
35 | |
36 | T expected; |
37 | T actual; |
38 | |
39 | public: |
40 | FPMatcher(T expectedValue) : expected(expectedValue) {} |
41 | |
42 | bool match(T actualValue) { |
43 | actual = actualValue; |
44 | fputil::FPBits<T> actualBits(actual), expectedBits(expected); |
45 | if (Condition == TestCond::EQ) |
46 | return (actualBits.is_nan() && expectedBits.is_nan()) || |
47 | (actualBits.uintval() == expectedBits.uintval()); |
48 | |
49 | // If condition == TestCond::NE. |
50 | if (actualBits.is_nan()) |
51 | return !expectedBits.is_nan(); |
52 | return expectedBits.is_nan() || |
53 | (actualBits.uintval() != expectedBits.uintval()); |
54 | } |
55 | |
56 | void explainError() override { |
57 | tlog << "Expected floating point value: " |
58 | << str(fputil::FPBits<T>(expected)) << '\n'; |
59 | tlog << "Actual floating point value: " << str(fputil::FPBits<T>(actual)) |
60 | << '\n'; |
61 | } |
62 | }; |
63 | |
64 | template <typename T, TestCond Condition> class CFPMatcher : public Matcher<T> { |
65 | static_assert( |
66 | cpp::is_complex_v<T>, |
67 | "CFPMatcher can only be used with complex floating point values."); |
68 | static_assert(Condition == TestCond::EQ || Condition == TestCond::NE, |
69 | "Unsupported CFPMatcher test condition."); |
70 | |
71 | T expected; |
72 | T actual; |
73 | |
74 | public: |
75 | CFPMatcher(T expectedValue) : expected(expectedValue) {} |
76 | |
77 | template <typename CFT> bool matchComplex() { |
78 | CFT *actualCmplxPtr = reinterpret_cast<CFT *>(&actual); |
79 | CFT *expectedCmplxPtr = reinterpret_cast<CFT *>(&expected); |
80 | CFT actualReal = actualCmplxPtr[0]; |
81 | CFT actualImag = actualCmplxPtr[1]; |
82 | CFT expectedReal = expectedCmplxPtr[0]; |
83 | CFT expectedImag = expectedCmplxPtr[1]; |
84 | fputil::FPBits<CFT> actualRealBits(actualReal), |
85 | expectedRealBits(expectedReal); |
86 | fputil::FPBits<CFT> actualImagBits(actualImag), |
87 | expectedImagBits(expectedImag); |
88 | if (Condition == TestCond::EQ) |
89 | return ((actualRealBits.is_nan() && expectedRealBits.is_nan()) || |
90 | (actualRealBits.uintval() == expectedRealBits.uintval())) && |
91 | ((actualImagBits.is_nan() && expectedImagBits.is_nan()) || |
92 | (actualImagBits.uintval() == expectedImagBits.uintval())); |
93 | |
94 | // If condition == TestCond::NE. |
95 | if (actualRealBits.is_nan() && expectedRealBits.is_nan()) |
96 | return !expectedRealBits.is_nan() && !expectedImagBits.is_nan(); |
97 | if (actualRealBits.is_nan()) |
98 | return !expectedRealBits.is_nan(); |
99 | if (actualImagBits.is_nan()) |
100 | return !expectedImagBits.is_nan(); |
101 | return (expectedRealBits.is_nan() || |
102 | actualRealBits.uintval() != expectedRealBits.uintval()) && |
103 | (expectedImagBits.is_nan() || |
104 | actualImagBits.uintval() != expectedImagBits.uintval()); |
105 | } |
106 | |
107 | template <typename CFT> void explainErrorComplex() { |
108 | CFT *actualCmplxPtr = reinterpret_cast<CFT *>(&actual); |
109 | CFT *expectedCmplxPtr = reinterpret_cast<CFT *>(&expected); |
110 | CFT actualReal = actualCmplxPtr[0]; |
111 | CFT actualImag = actualCmplxPtr[1]; |
112 | CFT expectedReal = expectedCmplxPtr[0]; |
113 | CFT expectedImag = expectedCmplxPtr[1]; |
114 | tlog << "Expected complex floating point value: " |
115 | << str(fputil::FPBits<CFT>(expectedReal)) + " + " + |
116 | str(fputil::FPBits<CFT>(expectedImag)) + "i" |
117 | << '\n'; |
118 | tlog << "Actual complex floating point value: " |
119 | << str(fputil::FPBits<CFT>(actualReal)) + " + " + |
120 | str(fputil::FPBits<CFT>(actualImag)) + "i" |
121 | << '\n'; |
122 | } |
123 | |
124 | bool match(T actualValue) { |
125 | actual = actualValue; |
126 | if constexpr (cpp::is_complex_type_same<T, _Complex float>()) |
127 | return matchComplex<float>(); |
128 | else if constexpr (cpp::is_complex_type_same<T, _Complex double>()) |
129 | return matchComplex<double>(); |
130 | else if constexpr (cpp::is_complex_type_same<T, _Complex long double>()) |
131 | return matchComplex<long double>(); |
132 | #ifdef LIBC_TYPES_HAS_CFLOAT16 |
133 | else if constexpr (cpp::is_complex_type_same<T, cfloat16>()) |
134 | return matchComplex<float16>(); |
135 | #endif |
136 | #ifdef LIBC_TYPES_HAS_CFLOAT128 |
137 | else if constexpr (cpp::is_complex_type_same<T, cfloat128>()) |
138 | return matchComplex<float128>(); |
139 | #endif |
140 | } |
141 | |
142 | void explainError() override { |
143 | if constexpr (cpp::is_complex_type_same<T, _Complex float>()) |
144 | return explainErrorComplex<float>(); |
145 | else if constexpr (cpp::is_complex_type_same<T, _Complex double>()) |
146 | return explainErrorComplex<double>(); |
147 | else if constexpr (cpp::is_complex_type_same<T, _Complex long double>()) |
148 | return explainErrorComplex<long double>(); |
149 | #ifdef LIBC_TYPES_HAS_CFLOAT16 |
150 | else if constexpr (cpp::is_complex_type_same<T, cfloat16>()) |
151 | return explainErrorComplex<float16>(); |
152 | #endif |
153 | #ifdef LIBC_TYPES_HAS_CFLOAT128 |
154 | else if constexpr (cpp::is_complex_type_same<T, cfloat128>()) |
155 | return explainErrorComplex<float128>(); |
156 | #endif |
157 | } |
158 | }; |
159 | |
160 | template <TestCond C, typename T> FPMatcher<T, C> getMatcher(T expectedValue) { |
161 | return FPMatcher<T, C>(expectedValue); |
162 | } |
163 | |
164 | template <TestCond C, typename T> |
165 | CFPMatcher<T, C> getMatcherComplex(T expectedValue) { |
166 | return CFPMatcher<T, C>(expectedValue); |
167 | } |
168 | |
169 | template <typename T> struct FPTest : public Test { |
170 | using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>; |
171 | using StorageType = typename FPBits::StorageType; |
172 | static constexpr StorageType STORAGE_MAX = |
173 | LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max(); |
174 | static constexpr T zero = FPBits::zero(Sign::POS).get_val(); |
175 | static constexpr T neg_zero = FPBits::zero(Sign::NEG).get_val(); |
176 | static constexpr T aNaN = FPBits::quiet_nan(Sign::POS).get_val(); |
177 | static constexpr T neg_aNaN = FPBits::quiet_nan(Sign::NEG).get_val(); |
178 | static constexpr T sNaN = FPBits::signaling_nan().get_val(); |
179 | static constexpr T inf = FPBits::inf(Sign::POS).get_val(); |
180 | static constexpr T neg_inf = FPBits::inf(Sign::NEG).get_val(); |
181 | static constexpr T min_normal = FPBits::min_normal().get_val(); |
182 | static constexpr T max_normal = FPBits::max_normal(Sign::POS).get_val(); |
183 | static constexpr T neg_max_normal = FPBits::max_normal(Sign::NEG).get_val(); |
184 | static constexpr T min_denormal = FPBits::min_subnormal().get_val(); |
185 | static constexpr T max_denormal = FPBits::max_subnormal().get_val(); |
186 | |
187 | static constexpr int N_ROUNDING_MODES = 4; |
188 | static constexpr fputil::testing::RoundingMode ROUNDING_MODES[4] = { |
189 | fputil::testing::RoundingMode::Nearest, |
190 | fputil::testing::RoundingMode::Upward, |
191 | fputil::testing::RoundingMode::Downward, |
192 | fputil::testing::RoundingMode::TowardZero, |
193 | }; |
194 | }; |
195 | |
196 | // Add facility to test Flush-Denormal-To-Zero (FTZ) and Denormal-As-Zero (DAZ) |
197 | // modes. |
198 | // These tests to ensure that our implementations will not crash under these |
199 | // modes. |
200 | #if defined(LIBC_TARGET_ARCH_IS_X86_64) && __has_builtin(__builtin_ia32_stmxcsr) |
201 | |
202 | #define LIBC_TEST_FTZ_DAZ |
203 | |
204 | static constexpr unsigned FTZ = 0x8000; // Flush denormal to zero |
205 | static constexpr unsigned DAZ = 0x0040; // Denormal as zero |
206 | |
207 | struct ModifyMXCSR { |
208 | ModifyMXCSR(unsigned flags) { |
209 | old_mxcsr = __builtin_ia32_stmxcsr(); |
210 | __builtin_ia32_ldmxcsr(old_mxcsr | flags); |
211 | } |
212 | |
213 | ~ModifyMXCSR() { __builtin_ia32_ldmxcsr(old_mxcsr); } |
214 | |
215 | private: |
216 | unsigned old_mxcsr; |
217 | }; |
218 | |
219 | #endif |
220 | |
221 | } // namespace testing |
222 | } // namespace LIBC_NAMESPACE_DECL |
223 | |
224 | #define DECLARE_SPECIAL_CONSTANTS(T) \ |
225 | using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>; \ |
226 | using StorageType = typename FPBits::StorageType; \ |
227 | \ |
228 | static constexpr StorageType STORAGE_MAX = \ |
229 | LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max(); \ |
230 | const T zero = FPBits::zero(Sign::POS).get_val(); \ |
231 | const T neg_zero = FPBits::zero(Sign::NEG).get_val(); \ |
232 | const T aNaN = FPBits::quiet_nan(Sign::POS).get_val(); \ |
233 | const T neg_aNaN = FPBits::quiet_nan(Sign::NEG).get_val(); \ |
234 | const T sNaN = FPBits::signaling_nan(Sign::POS).get_val(); \ |
235 | const T neg_sNaN = FPBits::signaling_nan(Sign::NEG).get_val(); \ |
236 | const T inf = FPBits::inf(Sign::POS).get_val(); \ |
237 | const T neg_inf = FPBits::inf(Sign::NEG).get_val(); \ |
238 | const T min_normal = FPBits::min_normal().get_val(); \ |
239 | const T max_normal = FPBits::max_normal(Sign::POS).get_val(); \ |
240 | const T neg_max_normal = FPBits::max_normal(Sign::NEG).get_val(); \ |
241 | const T min_denormal = FPBits::min_subnormal(Sign::POS).get_val(); \ |
242 | const T neg_min_denormal = FPBits::min_subnormal(Sign::NEG).get_val(); \ |
243 | const T max_denormal = FPBits::max_subnormal().get_val(); \ |
244 | static constexpr int UNKNOWN_MATH_ROUNDING_DIRECTION = 99; \ |
245 | static constexpr LIBC_NAMESPACE::cpp::array<int, 6> \ |
246 | MATH_ROUNDING_DIRECTIONS_INCLUDING_UNKNOWN = { \ |
247 | FP_INT_UPWARD, FP_INT_DOWNWARD, \ |
248 | FP_INT_TOWARDZERO, FP_INT_TONEARESTFROMZERO, \ |
249 | FP_INT_TONEAREST, UNKNOWN_MATH_ROUNDING_DIRECTION, \ |
250 | }; |
251 | |
252 | #define EXPECT_FP_EQ(expected, actual) \ |
253 | EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \ |
254 | LIBC_NAMESPACE::testing::TestCond::EQ>(expected)) |
255 | |
256 | #define EXPECT_CFP_EQ(expected, actual) \ |
257 | EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcherComplex< \ |
258 | LIBC_NAMESPACE::testing::TestCond::EQ>(expected)) |
259 | |
260 | #define TEST_FP_EQ(expected, actual) \ |
261 | LIBC_NAMESPACE::testing::getMatcher<LIBC_NAMESPACE::testing::TestCond::EQ>( \ |
262 | expected) \ |
263 | .match(actual) |
264 | |
265 | #define EXPECT_FP_IS_NAN(actual) EXPECT_TRUE((actual) != (actual)) |
266 | |
267 | #define ASSERT_FP_EQ(expected, actual) \ |
268 | ASSERT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \ |
269 | LIBC_NAMESPACE::testing::TestCond::EQ>(expected)) |
270 | |
271 | #define EXPECT_FP_NE(expected, actual) \ |
272 | EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \ |
273 | LIBC_NAMESPACE::testing::TestCond::NE>(expected)) |
274 | |
275 | #define ASSERT_FP_NE(expected, actual) \ |
276 | ASSERT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \ |
277 | LIBC_NAMESPACE::testing::TestCond::NE>(expected)) |
278 | |
279 | #define EXPECT_MATH_ERRNO(expected) \ |
280 | do { \ |
281 | if (math_errhandling & MATH_ERRNO) { \ |
282 | int actual = libc_errno; \ |
283 | libc_errno = 0; \ |
284 | EXPECT_EQ(actual, expected); \ |
285 | } \ |
286 | } while (0) |
287 | |
288 | #define ASSERT_MATH_ERRNO(expected) \ |
289 | do { \ |
290 | if (math_errhandling & MATH_ERRNO) { \ |
291 | int actual = libc_errno; \ |
292 | libc_errno = 0; \ |
293 | ASSERT_EQ(actual, expected); \ |
294 | } \ |
295 | } while (0) |
296 | |
297 | #define EXPECT_FP_EXCEPTION(expected) \ |
298 | do { \ |
299 | if (math_errhandling & MATH_ERREXCEPT) { \ |
300 | EXPECT_EQ( \ |
301 | LIBC_NAMESPACE::fputil::test_except( \ |
302 | static_cast<int>(FE_ALL_EXCEPT)) & \ |
303 | ((expected) ? (expected) : static_cast<int>(FE_ALL_EXCEPT)), \ |
304 | (expected)); \ |
305 | } \ |
306 | } while (0) |
307 | |
308 | #define ASSERT_FP_EXCEPTION(expected) \ |
309 | do { \ |
310 | if (math_errhandling & MATH_ERREXCEPT) { \ |
311 | ASSERT_EQ( \ |
312 | LIBC_NAMESPACE::fputil::test_except( \ |
313 | static_cast<int>(FE_ALL_EXCEPT)) & \ |
314 | ((expected) ? (expected) : static_cast<int>(FE_ALL_EXCEPT)), \ |
315 | (expected)); \ |
316 | } \ |
317 | } while (0) |
318 | |
319 | #define EXPECT_FP_EQ_WITH_EXCEPTION(expected_val, actual_val, expected_except) \ |
320 | do { \ |
321 | LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \ |
322 | EXPECT_FP_EQ(expected_val, actual_val); \ |
323 | EXPECT_FP_EXCEPTION(expected_except); \ |
324 | } while (0) |
325 | |
326 | #define EXPECT_FP_IS_NAN_WITH_EXCEPTION(actual_val, expected_except) \ |
327 | do { \ |
328 | LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \ |
329 | EXPECT_FP_IS_NAN(actual_val); \ |
330 | EXPECT_FP_EXCEPTION(expected_except); \ |
331 | } while (0) |
332 | |
333 | #define EXPECT_FP_EQ_ROUNDING_MODE(expected, actual, rounding_mode) \ |
334 | do { \ |
335 | using namespace LIBC_NAMESPACE::fputil::testing; \ |
336 | ForceRoundingMode __r((rounding_mode)); \ |
337 | if (__r.success) { \ |
338 | EXPECT_FP_EQ((expected), (actual)); \ |
339 | } \ |
340 | } while (0) |
341 | |
342 | #define EXPECT_FP_EQ_ROUNDING_NEAREST(expected, actual) \ |
343 | EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Nearest) |
344 | |
345 | #define EXPECT_FP_EQ_ROUNDING_UPWARD(expected, actual) \ |
346 | EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Upward) |
347 | |
348 | #define EXPECT_FP_EQ_ROUNDING_DOWNWARD(expected, actual) \ |
349 | EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Downward) |
350 | |
351 | #define EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO(expected, actual) \ |
352 | EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::TowardZero) |
353 | |
354 | #define EXPECT_FP_EQ_ALL_ROUNDING_1(expected, actual) \ |
355 | do { \ |
356 | EXPECT_FP_EQ_ROUNDING_NEAREST((expected), (actual)); \ |
357 | EXPECT_FP_EQ_ROUNDING_UPWARD((expected), (actual)); \ |
358 | EXPECT_FP_EQ_ROUNDING_DOWNWARD((expected), (actual)); \ |
359 | EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO((expected), (actual)); \ |
360 | } while (0) |
361 | |
362 | #define EXPECT_FP_EQ_ALL_ROUNDING_4(expected_nearest, expected_upward, \ |
363 | expected_downward, expected_toward_zero, \ |
364 | actual) \ |
365 | do { \ |
366 | EXPECT_FP_EQ_ROUNDING_NEAREST((expected_nearest), (actual)); \ |
367 | EXPECT_FP_EQ_ROUNDING_UPWARD((expected_upward), (actual)); \ |
368 | EXPECT_FP_EQ_ROUNDING_DOWNWARD((expected_downward), (actual)); \ |
369 | EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO((expected_toward_zero), (actual)); \ |
370 | } while (0) |
371 | |
372 | #define EXPECT_FP_EQ_ALL_ROUNDING_UNSUPPORTED(...) \ |
373 | static_assert(false, "Unsupported number of arguments") |
374 | |
375 | #define EXPECT_FP_EQ_ALL_ROUNDING_GET_6TH_ARG(ARG1, ARG2, ARG3, ARG4, ARG5, \ |
376 | ARG6, ...) \ |
377 | ARG6 |
378 | |
379 | #define EXPECT_FP_EQ_ALL_ROUNDING_SELECTION(...) \ |
380 | EXPECT_FP_EQ_ALL_ROUNDING_GET_6TH_ARG( \ |
381 | __VA_ARGS__, EXPECT_FP_EQ_ALL_ROUNDING_4, \ |
382 | EXPECT_FP_EQ_ALL_ROUNDING_UNSUPPORTED, \ |
383 | EXPECT_FP_EQ_ALL_ROUNDING_UNSUPPORTED, EXPECT_FP_EQ_ALL_ROUNDING_1) |
384 | |
385 | #define EXPECT_FP_EQ_ALL_ROUNDING(...) \ |
386 | EXPECT_FP_EQ_ALL_ROUNDING_SELECTION(__VA_ARGS__)(__VA_ARGS__) |
387 | |
388 | #define ASSERT_FP_EQ_ROUNDING_MODE(expected, actual, rounding_mode) \ |
389 | do { \ |
390 | using namespace LIBC_NAMESPACE::fputil::testing; \ |
391 | ForceRoundingMode __r((rounding_mode)); \ |
392 | if (__r.success) { \ |
393 | ASSERT_FP_EQ((expected), (actual)); \ |
394 | } \ |
395 | } while (0) |
396 | |
397 | #define ASSERT_FP_EQ_ROUNDING_NEAREST(expected, actual) \ |
398 | ASSERT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Nearest) |
399 | |
400 | #define ASSERT_FP_EQ_ROUNDING_UPWARD(expected, actual) \ |
401 | ASSERT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Upward) |
402 | |
403 | #define ASSERT_FP_EQ_ROUNDING_DOWNWARD(expected, actual) \ |
404 | ASSERT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Downward) |
405 | |
406 | #define ASSERT_FP_EQ_ROUNDING_TOWARD_ZERO(expected, actual) \ |
407 | ASSERT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::TowardZero) |
408 | |
409 | #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ |
410 | expected, actual, expected_except, rounding_mode) \ |
411 | do { \ |
412 | using namespace LIBC_NAMESPACE::fputil::testing; \ |
413 | ForceRoundingMode __r((rounding_mode)); \ |
414 | if (__r.success) { \ |
415 | LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \ |
416 | EXPECT_FP_EQ((expected), (actual)); \ |
417 | EXPECT_FP_EXCEPTION(expected_except); \ |
418 | } \ |
419 | } while (0) |
420 | |
421 | #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(expected, actual, \ |
422 | expected_except) \ |
423 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ |
424 | (expected), (actual), (expected_except), RoundingMode::Nearest) |
425 | |
426 | #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(expected, actual, \ |
427 | expected_except) \ |
428 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ |
429 | (expected), (actual), (expected_except), RoundingMode::Upward) |
430 | |
431 | #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD(expected, actual, \ |
432 | expected_except) \ |
433 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ |
434 | (expected), (actual), (expected_except), RoundingMode::Downward) |
435 | |
436 | #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO(expected, actual, \ |
437 | expected_except) \ |
438 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ |
439 | (expected), (actual), (expected_except), RoundingMode::TowardZero) |
440 | |
441 | #define EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING(expected, actual, \ |
442 | expected_except) \ |
443 | do { \ |
444 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST((expected), (actual), \ |
445 | (expected_except)); \ |
446 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD((expected), (actual), \ |
447 | (expected_except)); \ |
448 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD((expected), (actual), \ |
449 | (expected_except)); \ |
450 | EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO((expected), (actual), \ |
451 | (expected_except)); \ |
452 | } while (0) |
453 | |
454 | #endif // LLVM_LIBC_TEST_UNITTEST_FPMATCHER_H |
455 |
Warning: This file is not a C or C++ file. It does not have highlighting.