1 //===-- Utility class to test different flavors of fma --------------------===// 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_FMATEST_H 10 #define LLVM_LIBC_TEST_SRC_MATH_FMATEST_H 11 12 #include "src/__support/CPP/type_traits.h" 13 #include "src/__support/FPUtil/cast.h" 14 #include "src/__support/macros/properties/types.h" 15 #include "test/UnitTest/FEnvSafeTest.h" 16 #include "test/UnitTest/FPMatcher.h" 17 #include "test/UnitTest/Test.h" 18 19 template <typename OutType, typename InType = OutType> 20 class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { 21 22 struct OutConstants { 23 DECLARE_SPECIAL_CONSTANTS(OutType) 24 }; 25 26 struct InConstants { 27 DECLARE_SPECIAL_CONSTANTS(InType) 28 }; 29 30 using OutFPBits = typename OutConstants::FPBits; 31 using OutStorageType = typename OutConstants::StorageType; 32 using InFPBits = typename InConstants::FPBits; 33 using InStorageType = typename InConstants::StorageType; 34 35 static constexpr OutStorageType OUT_MIN_NORMAL_U = 36 OutFPBits::min_normal().uintval(); 37 static constexpr InStorageType IN_MIN_NORMAL_U = 38 InFPBits::min_normal().uintval(); 39 40 OutConstants out; 41 InConstants in; 42 43 const InType in_out_min_normal = 44 LIBC_NAMESPACE::fputil::cast<InType>(out.min_normal); 45 const InType in_out_min_denormal = 46 LIBC_NAMESPACE::fputil::cast<InType>(out.min_denormal); 47 48 public: 49 using FmaFunc = OutType (*)(InType, InType, InType); 50 test_special_numbers(FmaFunc func)51 void test_special_numbers(FmaFunc func) { 52 EXPECT_FP_EQ(out.zero, func(in.zero, in.zero, in.zero)); 53 EXPECT_FP_EQ(out.neg_zero, func(in.zero, in.neg_zero, in.neg_zero)); 54 EXPECT_FP_EQ(out.inf, func(in.inf, in.inf, in.zero)); 55 EXPECT_FP_EQ(out.neg_inf, func(in.neg_inf, in.inf, in.neg_inf)); 56 EXPECT_FP_EQ(out.aNaN, func(in.inf, in.zero, in.zero)); 57 EXPECT_FP_EQ(out.aNaN, func(in.inf, in.neg_inf, in.inf)); 58 EXPECT_FP_EQ(out.aNaN, func(in.aNaN, in.zero, in.inf)); 59 EXPECT_FP_EQ(out.aNaN, func(in.inf, in.neg_inf, in.aNaN)); 60 61 // Test underflow rounding up. 62 EXPECT_FP_EQ(OutFPBits(OutStorageType(2)).get_val(), 63 func(InType(0.5), in_out_min_denormal, in_out_min_denormal)); 64 65 if constexpr (sizeof(OutType) < sizeof(InType)) { 66 EXPECT_FP_EQ(out.zero, 67 func(InType(0.5), in.min_denormal, in.min_denormal)); 68 } 69 70 // Test underflow rounding down. 71 OutType v = OutFPBits(static_cast<OutStorageType>(OUT_MIN_NORMAL_U + 72 OutStorageType(1))) 73 .get_val(); 74 EXPECT_FP_EQ(v, func(InType(1) / InType(OUT_MIN_NORMAL_U << 1), 75 LIBC_NAMESPACE::fputil::cast<InType>(v), 76 in_out_min_normal)); 77 78 if constexpr (sizeof(OutType) < sizeof(InType)) { 79 InFPBits tmp = InFPBits::one(); 80 tmp.set_biased_exponent(InFPBits::EXP_BIAS - InFPBits::FRACTION_LEN - 1); 81 InType reciprocal_value = tmp.get_val(); 82 83 InType v = InFPBits(static_cast<InStorageType>(IN_MIN_NORMAL_U + 84 InStorageType(1))) 85 .get_val(); 86 EXPECT_FP_EQ(out.min_normal, 87 func(reciprocal_value, v, in_out_min_normal)); 88 } 89 90 // Test overflow. 91 OutType z = out.max_normal; 92 InType in_z = LIBC_NAMESPACE::fputil::cast<InType>(out.max_normal); 93 #if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION) 94 // Rounding modes other than the default might not be usable with float16. 95 if constexpr (LIBC_NAMESPACE::cpp::is_same_v<OutType, float16>) 96 EXPECT_FP_EQ(OutType(0.75) * z, func(InType(1.75), in_z, -in_z)); 97 else 98 #endif 99 EXPECT_FP_EQ_ALL_ROUNDING(OutType(0.75) * z, 100 func(InType(1.75), in_z, -in_z)); 101 102 // Exact cancellation. 103 EXPECT_FP_EQ_ROUNDING_NEAREST( 104 out.zero, func(InType(3.0), InType(5.0), InType(-15.0))); 105 EXPECT_FP_EQ_ROUNDING_UPWARD(out.zero, 106 func(InType(3.0), InType(5.0), InType(-15.0))); 107 EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO( 108 out.zero, func(InType(3.0), InType(5.0), InType(-15.0))); 109 EXPECT_FP_EQ_ROUNDING_DOWNWARD( 110 out.neg_zero, func(InType(3.0), InType(5.0), InType(-15.0))); 111 112 EXPECT_FP_EQ_ROUNDING_NEAREST( 113 out.zero, func(InType(-3.0), InType(5.0), InType(15.0))); 114 EXPECT_FP_EQ_ROUNDING_UPWARD(out.zero, 115 func(InType(-3.0), InType(5.0), InType(15.0))); 116 EXPECT_FP_EQ_ROUNDING_TOWARD_ZERO( 117 out.zero, func(InType(-3.0), InType(5.0), InType(15.0))); 118 EXPECT_FP_EQ_ROUNDING_DOWNWARD( 119 out.neg_zero, func(InType(-3.0), InType(5.0), InType(15.0))); 120 } 121 }; 122 123 #define LIST_FMA_TESTS(T, func) \ 124 using LlvmLibcFmaTest = FmaTestTemplate<T>; \ 125 TEST_F(LlvmLibcFmaTest, SpecialNumbers) { test_special_numbers(&func); } 126 127 #define LIST_NARROWING_FMA_TESTS(OutType, InType, func) \ 128 using LlvmLibcFmaTest = FmaTestTemplate<OutType, InType>; \ 129 TEST_F(LlvmLibcFmaTest, SpecialNumbers) { test_special_numbers(&func); } 130 131 #endif // LLVM_LIBC_TEST_SRC_MATH_FMATEST_H 132