xref: /aosp_15_r20/external/llvm-libc/test/src/math/smoke/AddTest.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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/FPUtil/BasicOperations.h"
15 #include "src/__support/macros/properties/os.h"
16 #include "test/UnitTest/FEnvSafeTest.h"
17 #include "test/UnitTest/FPMatcher.h"
18 #include "test/UnitTest/Test.h"
19 
20 using LIBC_NAMESPACE::Sign;
21 
22 template <typename OutType, typename InType>
23 class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
24 
25   DECLARE_SPECIAL_CONSTANTS(OutType)
26 
27   struct InConstants {
28     DECLARE_SPECIAL_CONSTANTS(InType)
29   };
30 
31   using InFPBits = typename InConstants::FPBits;
32   using InStorageType = typename InConstants::StorageType;
33 
34   InConstants in;
35 
36 public:
37   using AddFunc = OutType (*)(InType, InType);
38 
test_special_numbers(AddFunc func)39   void test_special_numbers(AddFunc func) {
40     EXPECT_FP_IS_NAN(func(in.aNaN, in.aNaN));
41     EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.sNaN, in.sNaN), FE_INVALID);
42 
43     InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
44     EXPECT_FP_IS_NAN(func(qnan_42, in.zero));
45     EXPECT_FP_IS_NAN(func(in.zero, qnan_42));
46 
47     EXPECT_FP_EQ(inf, func(in.inf, in.zero));
48     EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.zero));
49     EXPECT_FP_EQ(inf, func(in.inf, in.neg_zero));
50     EXPECT_FP_EQ(neg_inf, func(in.neg_inf, in.neg_zero));
51   }
52 
test_invalid_operations(AddFunc func)53   void test_invalid_operations(AddFunc func) {
54     EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
55     EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
56   }
57 
test_range_errors(AddFunc func)58   void test_range_errors(AddFunc func) {
59 #ifndef LIBC_TARGET_OS_IS_WINDOWS
60     using namespace LIBC_NAMESPACE::fputil::testing;
61 
62     if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
63       EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
64                                   FE_OVERFLOW | FE_INEXACT);
65       EXPECT_MATH_ERRNO(ERANGE);
66       EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
67                                   func(in.neg_max_normal, in.neg_max_normal),
68                                   FE_OVERFLOW | FE_INEXACT);
69       EXPECT_MATH_ERRNO(ERANGE);
70 
71       EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
72                                   FE_UNDERFLOW | FE_INEXACT);
73       EXPECT_MATH_ERRNO(ERANGE);
74       EXPECT_FP_EQ_WITH_EXCEPTION(
75           neg_zero, func(in.neg_min_denormal, in.neg_min_denormal),
76           FE_UNDERFLOW | FE_INEXACT);
77       EXPECT_MATH_ERRNO(ERANGE);
78     }
79 
80     if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
81       EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
82                                   func(in.max_normal, in.max_normal),
83                                   FE_OVERFLOW | FE_INEXACT);
84       EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
85                                   func(in.neg_max_normal, in.neg_max_normal),
86                                   FE_OVERFLOW | FE_INEXACT);
87 
88       EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
89                                   FE_UNDERFLOW | FE_INEXACT);
90       EXPECT_MATH_ERRNO(ERANGE);
91       EXPECT_FP_EQ_WITH_EXCEPTION(
92           neg_zero, func(in.neg_min_denormal, in.neg_min_denormal),
93           FE_UNDERFLOW | FE_INEXACT);
94       EXPECT_MATH_ERRNO(ERANGE);
95     }
96 
97     if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
98       EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
99                                   func(in.max_normal, in.max_normal),
100                                   FE_OVERFLOW | FE_INEXACT);
101       EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
102                                   func(in.neg_max_normal, in.neg_max_normal),
103                                   FE_OVERFLOW | FE_INEXACT);
104       EXPECT_MATH_ERRNO(ERANGE);
105 
106       EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
107                                   FE_UNDERFLOW | FE_INEXACT);
108       EXPECT_MATH_ERRNO(ERANGE);
109       EXPECT_FP_EQ_WITH_EXCEPTION(
110           neg_min_denormal, func(in.neg_min_denormal, in.neg_min_denormal),
111           FE_UNDERFLOW | FE_INEXACT);
112       EXPECT_MATH_ERRNO(ERANGE);
113     }
114 
115     if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
116       EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
117                                   FE_OVERFLOW | FE_INEXACT);
118       EXPECT_MATH_ERRNO(ERANGE);
119       EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
120                                   func(in.neg_max_normal, in.neg_max_normal),
121                                   FE_OVERFLOW | FE_INEXACT);
122 
123       EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
124                                   func(in.min_denormal, in.min_denormal),
125                                   FE_UNDERFLOW | FE_INEXACT);
126       EXPECT_MATH_ERRNO(ERANGE);
127       EXPECT_FP_EQ_WITH_EXCEPTION(
128           neg_zero, func(in.neg_min_denormal, in.neg_min_denormal),
129           FE_UNDERFLOW | FE_INEXACT);
130       EXPECT_MATH_ERRNO(ERANGE);
131     }
132 #endif
133   }
134 
test_inexact_results(AddFunc func)135   void test_inexact_results(AddFunc func) {
136     func(InType(1.0), in.min_denormal);
137     EXPECT_FP_EXCEPTION(FE_INEXACT);
138   }
139 };
140 
141 #define LIST_ADD_TESTS(OutType, InType, func)                                  \
142   using LlvmLibcAddTest = AddTest<OutType, InType>;                            \
143   TEST_F(LlvmLibcAddTest, SpecialNumbers) { test_special_numbers(&func); }     \
144   TEST_F(LlvmLibcAddTest, InvalidOperations) {                                 \
145     test_invalid_operations(&func);                                            \
146   }                                                                            \
147   TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); }           \
148   TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }
149 
150 #endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H
151