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_NAMESPACE::libc_errno; \ 283 LIBC_NAMESPACE::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_NAMESPACE::libc_errno; \ 292 LIBC_NAMESPACE::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_ALL_ROUNDING(expected, actual) \ 334 do { \ 335 using namespace LIBC_NAMESPACE::fputil::testing; \ 336 ForceRoundingMode __r1(RoundingMode::Nearest); \ 337 if (__r1.success) { \ 338 EXPECT_FP_EQ((expected), (actual)); \ 339 } \ 340 ForceRoundingMode __r2(RoundingMode::Upward); \ 341 if (__r2.success) { \ 342 EXPECT_FP_EQ((expected), (actual)); \ 343 } \ 344 ForceRoundingMode __r3(RoundingMode::Downward); \ 345 if (__r3.success) { \ 346 EXPECT_FP_EQ((expected), (actual)); \ 347 } \ 348 ForceRoundingMode __r4(RoundingMode::TowardZero); \ 349 if (__r4.success) { \ 350 EXPECT_FP_EQ((expected), (actual)); \ 351 } \ 352 } while (0) 353 354 #define EXPECT_FP_EQ_ROUNDING_MODE(expected, actual, rounding_mode) \ 355 do { \ 356 using namespace LIBC_NAMESPACE::fputil::testing; \ 357 ForceRoundingMode __r((rounding_mode)); \ 358 if (__r.success) { \ 359 EXPECT_FP_EQ((expected), (actual)); \ 360 } \ 361 } while (0) 362 363 #define EXPECT_FP_EQ_ROUNDING_NEAREST(expected, actual) \ 364 EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Nearest) 365 366 #define EXPECT_FP_EQ_ROUNDING_UPWARD(expected, actual) \ 367 EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Upward) 368 369 #define EXPECT_FP_EQ_ROUNDING_DOWNWARD(expected, actual) \ 370 EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::Downward) 371 372 #define EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO(expected, actual) \ 373 EXPECT_FP_EQ_ROUNDING_MODE((expected), (actual), RoundingMode::TowardZero) 374 375 #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ 376 expected, actual, expected_except, rounding_mode) \ 377 do { \ 378 using namespace LIBC_NAMESPACE::fputil::testing; \ 379 ForceRoundingMode __r((rounding_mode)); \ 380 if (__r.success) { \ 381 LIBC_NAMESPACE::fputil::clear_except(static_cast<int>(FE_ALL_EXCEPT)); \ 382 EXPECT_FP_EQ((expected), (actual)); \ 383 EXPECT_FP_EXCEPTION(expected_except); \ 384 } \ 385 } while (0) 386 387 #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST(expected, actual, \ 388 expected_except) \ 389 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ 390 (expected), (actual), (expected_except), RoundingMode::Nearest) 391 392 #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD(expected, actual, \ 393 expected_except) \ 394 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ 395 (expected), (actual), (expected_except), RoundingMode::Upward) 396 397 #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD(expected, actual, \ 398 expected_except) \ 399 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ 400 (expected), (actual), (expected_except), RoundingMode::Downward) 401 402 #define EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO(expected, actual, \ 403 expected_except) \ 404 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_MODE( \ 405 (expected), (actual), (expected_except), RoundingMode::TowardZero) 406 407 #define EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING(expected, actual, \ 408 expected_except) \ 409 do { \ 410 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_NEAREST((expected), (actual), \ 411 (expected_except)); \ 412 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_UPWARD((expected), (actual), \ 413 (expected_except)); \ 414 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_DOWNWARD((expected), (actual), \ 415 (expected_except)); \ 416 EXPECT_FP_EQ_WITH_EXCEPTION_ROUNDING_TOWARD_ZERO((expected), (actual), \ 417 (expected_except)); \ 418 } while (0) 419 420 #endif // LLVM_LIBC_TEST_UNITTEST_FPMATCHER_H 421