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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of libc/test/src/math/smoke/FmaTest.h