1//===-- Utility class to test different flavors of float add ----*- 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_SRC_MATH_SMOKE_ADDTEST_H
10#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H
11
12#include "hdr/errno_macros.h"
13#include "hdr/fenv_macros.h"
14#include "src/__support/macros/properties/os.h"
15#include "test/UnitTest/FEnvSafeTest.h"
16#include "test/UnitTest/FPMatcher.h"
17#include "test/UnitTest/Test.h"
18
19using LIBC_NAMESPACE::Sign;
20
21template <typename OutType, typename InType>
22class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
23
24 DECLARE_SPECIAL_CONSTANTS(OutType)
25
26 struct InConstants {
27 DECLARE_SPECIAL_CONSTANTS(InType)
28 };
29
30 using InFPBits = typename InConstants::FPBits;
31 using InStorageType = typename InConstants::StorageType;
32
33 InConstants in;
34
35public:
36 using AddFunc = OutType (*)(InType, InType);
37
38 void test_special_numbers(AddFunc func) {
39 EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
40 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);
41
42 InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
43 EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
44 EXPECT_FP_IS_NAN(func(in.zero, qnan_42));
45
46 EXPECT_FP_EQ(inf, func(in.inf, in.zero));
47 EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
48 EXPECT_FP_EQ(inf, func(in.inf, in.neg_zero));
49 EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.neg_zero));
50 }
51
52 void test_invalid_operations(AddFunc func) {
53 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
54 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
55 }
56
57 void test_range_errors(AddFunc func) {
58#ifndef LIBC_TARGET_OS_IS_WINDOWS
59 using namespace LIBC_NAMESPACE::fputil::testing;
60
61 if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() ==
62 LIBC_NAMESPACE::fputil::get_fp_type<InType>())
63 return;
64
65 if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
66 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
67 FE_OVERFLOW | FE_INEXACT);
68 EXPECT_MATH_ERRNO(ERANGE);
69 EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
70 func(in.neg_max_normal, in.neg_max_normal),
71 FE_OVERFLOW | FE_INEXACT);
72 EXPECT_MATH_ERRNO(ERANGE);
73
74 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
75 FE_UNDERFLOW | FE_INEXACT);
76 EXPECT_MATH_ERRNO(ERANGE);
77 EXPECT_FP_EQ_WITH_EXCEPTION(
78 neg_zero, func(in.neg_min_denormal, in.neg_min_denormal),
79 FE_UNDERFLOW | FE_INEXACT);
80 EXPECT_MATH_ERRNO(ERANGE);
81 }
82
83 if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
84 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
85 func(in.max_normal, in.max_normal),
86 FE_OVERFLOW | FE_INEXACT);
87 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
88 func(in.neg_max_normal, in.neg_max_normal),
89 FE_OVERFLOW | FE_INEXACT);
90
91 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
92 FE_UNDERFLOW | FE_INEXACT);
93 EXPECT_MATH_ERRNO(ERANGE);
94 EXPECT_FP_EQ_WITH_EXCEPTION(
95 neg_zero, func(in.neg_min_denormal, in.neg_min_denormal),
96 FE_UNDERFLOW | FE_INEXACT);
97 EXPECT_MATH_ERRNO(ERANGE);
98 }
99
100 if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
101 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
102 func(in.max_normal, in.max_normal),
103 FE_OVERFLOW | FE_INEXACT);
104 EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
105 func(in.neg_max_normal, in.neg_max_normal),
106 FE_OVERFLOW | FE_INEXACT);
107 EXPECT_MATH_ERRNO(ERANGE);
108
109 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
110 FE_UNDERFLOW | FE_INEXACT);
111 EXPECT_MATH_ERRNO(ERANGE);
112 EXPECT_FP_EQ_WITH_EXCEPTION(
113 neg_min_denormal, func(in.neg_min_denormal, in.neg_min_denormal),
114 FE_UNDERFLOW | FE_INEXACT);
115 EXPECT_MATH_ERRNO(ERANGE);
116 }
117
118 if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
119 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
120 FE_OVERFLOW | FE_INEXACT);
121 EXPECT_MATH_ERRNO(ERANGE);
122 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
123 func(in.neg_max_normal, in.neg_max_normal),
124 FE_OVERFLOW | FE_INEXACT);
125
126 EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
127 func(in.min_denormal, in.min_denormal),
128 FE_UNDERFLOW | FE_INEXACT);
129 EXPECT_MATH_ERRNO(ERANGE);
130 EXPECT_FP_EQ_WITH_EXCEPTION(
131 neg_zero, func(in.neg_min_denormal, in.neg_min_denormal),
132 FE_UNDERFLOW | FE_INEXACT);
133 EXPECT_MATH_ERRNO(ERANGE);
134 }
135#endif
136 }
137
138 void test_inexact_results(AddFunc func) {
139 func(InType(1.0), in.min_denormal);
140 EXPECT_FP_EXCEPTION(FE_INEXACT);
141 }
142
143 void test_mixed_normality(AddFunc func) {
144 if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() !=
145 LIBC_NAMESPACE::fputil::get_fp_type<InType>())
146 return;
147
148 EXPECT_FP_EQ(FPBits::create_value(Sign::POS, 2U, 0b1U).get_val(),
149 func(InFPBits::create_value(Sign::POS, 2U, 0U).get_val(),
150 InFPBits::create_value(Sign::POS, 0U, 0b10U).get_val()));
151 }
152};
153
154#define LIST_ADD_TESTS(OutType, InType, func) \
155 using LlvmLibcAddTest = AddTest<OutType, InType>; \
156 TEST_F(LlvmLibcAddTest, SpecialNumbers) { test_special_numbers(&func); } \
157 TEST_F(LlvmLibcAddTest, InvalidOperations) { \
158 test_invalid_operations(&func); \
159 } \
160 TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); } \
161 TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); } \
162 TEST_F(LlvmLibcAddTest, MixedNormality) { test_mixed_normality(&func); }
163
164#define LIST_ADD_SAME_TYPE_TESTS(suffix, OutType, InType, func) \
165 using LlvmLibcAddTest##suffix = AddTest<OutType, InType>; \
166 TEST_F(LlvmLibcAddTest##suffix, SpecialNumbers) { \
167 test_special_numbers(&func); \
168 } \
169 TEST_F(LlvmLibcAddTest##suffix, InvalidOperations) { \
170 test_invalid_operations(&func); \
171 } \
172 TEST_F(LlvmLibcAddTest##suffix, RangeErrors) { test_range_errors(&func); } \
173 TEST_F(LlvmLibcAddTest##suffix, InexactResults) { \
174 test_inexact_results(&func); \
175 } \
176 TEST_F(LlvmLibcAddTest##suffix, MixedNormality) { \
177 test_mixed_normality(&func); \
178 }
179
180#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H
181

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