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