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 "test/UnitTest/RoundingModeUtils.h"
18#include "test/UnitTest/StringUtils.h"
19#include "test/UnitTest/Test.h"
20
21#include "hdr/math_macros.h"
22
23namespace LIBC_NAMESPACE {
24namespace testing {
25
26template <typename T, TestCond Condition> class FPMatcher : public Matcher<T> {
27 static_assert(cpp::is_floating_point_v<T>,
28 "FPMatcher can only be used with floating point values.");
29 static_assert(Condition == TestCond::EQ || Condition == TestCond::NE,
30 "Unsupported FPMatcher test condition.");
31
32 T expected;
33 T actual;
34
35public:
36 FPMatcher(T expectedValue) : expected(expectedValue) {}
37
38 bool match(T actualValue) {
39 actual = actualValue;
40 fputil::FPBits<T> actualBits(actual), expectedBits(expected);
41 if (Condition == TestCond::EQ)
42 return (actualBits.is_nan() && expectedBits.is_nan()) ||
43 (actualBits.uintval() == expectedBits.uintval());
44
45 // If condition == TestCond::NE.
46 if (actualBits.is_nan())
47 return !expectedBits.is_nan();
48 return expectedBits.is_nan() ||
49 (actualBits.uintval() != expectedBits.uintval());
50 }
51
52 void explainError() override {
53 tlog << "Expected floating point value: "
54 << str(fputil::FPBits<T>(expected)) << '\n';
55 tlog << "Actual floating point value: " << str(fputil::FPBits<T>(actual))
56 << '\n';
57 }
58};
59
60template <TestCond C, typename T> FPMatcher<T, C> getMatcher(T expectedValue) {
61 return FPMatcher<T, C>(expectedValue);
62}
63
64template <typename T> struct FPTest : public Test {
65 using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
66 using StorageType = typename FPBits::StorageType;
67 static constexpr StorageType STORAGE_MAX =
68 LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max();
69 static constexpr T zero = FPBits::zero(Sign::POS).get_val();
70 static constexpr T neg_zero = FPBits::zero(Sign::NEG).get_val();
71 static constexpr T aNaN = FPBits::quiet_nan().get_val();
72 static constexpr T sNaN = FPBits::signaling_nan().get_val();
73 static constexpr T inf = FPBits::inf(Sign::POS).get_val();
74 static constexpr T neg_inf = FPBits::inf(Sign::NEG).get_val();
75 static constexpr T min_normal = FPBits::min_normal().get_val();
76 static constexpr T max_normal = FPBits::max_normal().get_val();
77 static constexpr T min_denormal = FPBits::min_subnormal().get_val();
78 static constexpr T max_denormal = FPBits::max_subnormal().get_val();
79
80 static constexpr int N_ROUNDING_MODES = 4;
81 static constexpr fputil::testing::RoundingMode ROUNDING_MODES[4] = {
82 fputil::testing::RoundingMode::Nearest,
83 fputil::testing::RoundingMode::Upward,
84 fputil::testing::RoundingMode::Downward,
85 fputil::testing::RoundingMode::TowardZero,
86 };
87};
88
89} // namespace testing
90} // namespace LIBC_NAMESPACE
91
92#define DECLARE_SPECIAL_CONSTANTS(T) \
93 using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>; \
94 using StorageType = typename FPBits::StorageType; \
95 \
96 static constexpr StorageType STORAGE_MAX = \
97 LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max(); \
98 const T zero = FPBits::zero(Sign::POS).get_val(); \
99 const T neg_zero = FPBits::zero(Sign::NEG).get_val(); \
100 const T aNaN = FPBits::quiet_nan().get_val(); \
101 const T sNaN = FPBits::signaling_nan().get_val(); \
102 const T inf = FPBits::inf(Sign::POS).get_val(); \
103 const T neg_inf = FPBits::inf(Sign::NEG).get_val(); \
104 const T min_normal = FPBits::min_normal().get_val(); \
105 const T max_normal = FPBits::max_normal(Sign::POS).get_val(); \
106 const T neg_max_normal = FPBits::max_normal(Sign::NEG).get_val(); \
107 const T min_denormal = FPBits::min_subnormal(Sign::POS).get_val(); \
108 const T neg_min_denormal = FPBits::min_subnormal(Sign::NEG).get_val(); \
109 const T max_denormal = FPBits::max_subnormal().get_val(); \
110 static constexpr int UNKNOWN_MATH_ROUNDING_DIRECTION = 99; \
111 static constexpr LIBC_NAMESPACE::cpp::array<int, 6> \
112 MATH_ROUNDING_DIRECTIONS_INCLUDING_UNKNOWN = { \
113 FP_INT_UPWARD, FP_INT_DOWNWARD, \
114 FP_INT_TOWARDZERO, FP_INT_TONEARESTFROMZERO, \
115 FP_INT_TONEAREST, UNKNOWN_MATH_ROUNDING_DIRECTION, \
116 };
117
118#define EXPECT_FP_EQ(expected, actual) \
119 EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \
120 LIBC_NAMESPACE::testing::TestCond::EQ>(expected))
121
122#define TEST_FP_EQ(expected, actual) \
123 LIBC_NAMESPACE::testing::getMatcher<LIBC_NAMESPACE::testing::TestCond::EQ>( \
124 expected) \
125 .match(actual)
126
127#define EXPECT_FP_IS_NAN(actual) EXPECT_TRUE((actual) != (actual))
128
129#define ASSERT_FP_EQ(expected, actual) \
130 ASSERT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \
131 LIBC_NAMESPACE::testing::TestCond::EQ>(expected))
132
133#define EXPECT_FP_NE(expected, actual) \
134 EXPECT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \
135 LIBC_NAMESPACE::testing::TestCond::NE>(expected))
136
137#define ASSERT_FP_NE(expected, actual) \
138 ASSERT_THAT(actual, LIBC_NAMESPACE::testing::getMatcher< \
139 LIBC_NAMESPACE::testing::TestCond::NE>(expected))
140
141#define EXPECT_MATH_ERRNO(expected) \
142 do { \
143 if (math_errhandling & MATH_ERRNO) { \
144 int actual = LIBC_NAMESPACE::libc_errno; \
145 LIBC_NAMESPACE::libc_errno = 0; \
146 EXPECT_EQ(actual, expected); \
147 } \
148 } while (0)
149
150#define ASSERT_MATH_ERRNO(expected) \
151 do { \
152 if (math_errhandling & MATH_ERRNO) { \
153 int actual = LIBC_NAMESPACE::libc_errno; \
154 LIBC_NAMESPACE::libc_errno = 0; \
155 ASSERT_EQ(actual, expected); \
156 } \
157 } while (0)
158
159#define EXPECT_FP_EXCEPTION(expected) \
160 do { \
161 if (math_errhandling & MATH_ERREXCEPT) { \
162 EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
163 (expected), \
164 expected); \
165 } \
166 } while (0)
167
168#define ASSERT_FP_EXCEPTION(expected) \
169 do { \
170 if (math_errhandling & MATH_ERREXCEPT) { \
171 ASSERT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
172 (expected), \
173 expected); \
174 } \
175 } while (0)
176
177#define EXPECT_FP_EQ_WITH_EXCEPTION(expected_val, actual_val, expected_except) \
178 do { \
179 LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
180 EXPECT_FP_EQ(expected_val, actual_val); \
181 if (math_errhandling & MATH_ERREXCEPT) { \
182 EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
183 (expected_except), \
184 expected_except); \
185 LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
186 } \
187 } while (0)
188
189#define EXPECT_FP_IS_NAN_WITH_EXCEPTION(actual_val, expected_except) \
190 do { \
191 LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
192 EXPECT_FP_IS_NAN(actual_val); \
193 if (math_errhandling & MATH_ERREXCEPT) { \
194 EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \
195 (expected_except), \
196 expected_except); \
197 LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \
198 } \
199 } while (0)
200
201#define EXPECT_FP_EQ_ALL_ROUNDING(expected, actual) \
202 do { \
203 using namespace LIBC_NAMESPACE::fputil::testing; \
204 ForceRoundingMode __r1(RoundingMode::Nearest); \
205 if (__r1.success) { \
206 EXPECT_FP_EQ((expected), (actual)); \
207 } \
208 ForceRoundingMode __r2(RoundingMode::Upward); \
209 if (__r2.success) { \
210 EXPECT_FP_EQ((expected), (actual)); \
211 } \
212 ForceRoundingMode __r3(RoundingMode::Downward); \
213 if (__r3.success) { \
214 EXPECT_FP_EQ((expected), (actual)); \
215 } \
216 ForceRoundingMode __r4(RoundingMode::TowardZero); \
217 if (__r4.success) { \
218 EXPECT_FP_EQ((expected), (actual)); \
219 } \
220 } while (0)
221
222#endif // LLVM_LIBC_TEST_UNITTEST_FPMATCHER_H
223

source code of libc/test/UnitTest/FPMatcher.h