1//===-- Utility class to test different flavors of float sub ----*- 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_SUBTEST_H
10#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_SUBTEST_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 SubTest : 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 SubFunc = OutType (*)(InType, InType);
37
38 void test_special_numbers(SubFunc 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(SubFunc func) {
53 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.inf), FE_INVALID);
54 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_inf), FE_INVALID);
55 }
56
57 void test_range_errors(SubFunc 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.neg_max_normal),
67 FE_OVERFLOW | FE_INEXACT);
68 EXPECT_MATH_ERRNO(ERANGE);
69 EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(in.neg_max_normal, in.max_normal),
70 FE_OVERFLOW | FE_INEXACT);
71 EXPECT_MATH_ERRNO(ERANGE);
72
73 EXPECT_FP_EQ_WITH_EXCEPTION(zero,
74 func(in.min_denormal, in.neg_min_denormal),
75 FE_UNDERFLOW | FE_INEXACT);
76 EXPECT_MATH_ERRNO(ERANGE);
77 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
78 func(in.neg_min_denormal, in.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.neg_max_normal),
86 FE_OVERFLOW | FE_INEXACT);
87 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
88 func(in.neg_max_normal, in.max_normal),
89 FE_OVERFLOW | FE_INEXACT);
90
91 EXPECT_FP_EQ_WITH_EXCEPTION(zero,
92 func(in.min_denormal, in.neg_min_denormal),
93 FE_UNDERFLOW | FE_INEXACT);
94 EXPECT_MATH_ERRNO(ERANGE);
95 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
96 func(in.neg_min_denormal, in.min_denormal),
97 FE_UNDERFLOW | FE_INEXACT);
98 EXPECT_MATH_ERRNO(ERANGE);
99 }
100
101 if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
102 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
103 func(in.max_normal, in.neg_max_normal),
104 FE_OVERFLOW | FE_INEXACT);
105 EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(in.neg_max_normal, in.max_normal),
106 FE_OVERFLOW | FE_INEXACT);
107 EXPECT_MATH_ERRNO(ERANGE);
108
109 EXPECT_FP_EQ_WITH_EXCEPTION(zero,
110 func(in.min_denormal, in.neg_min_denormal),
111 FE_UNDERFLOW | FE_INEXACT);
112 EXPECT_MATH_ERRNO(ERANGE);
113 EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal,
114 func(in.neg_min_denormal, in.min_denormal),
115 FE_UNDERFLOW | FE_INEXACT);
116 EXPECT_MATH_ERRNO(ERANGE);
117 }
118
119 if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
120 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.neg_max_normal),
121 FE_OVERFLOW | FE_INEXACT);
122 EXPECT_MATH_ERRNO(ERANGE);
123 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
124 func(in.neg_max_normal, in.max_normal),
125 FE_OVERFLOW | FE_INEXACT);
126
127 EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
128 func(in.min_denormal, in.neg_min_denormal),
129 FE_UNDERFLOW | FE_INEXACT);
130 EXPECT_MATH_ERRNO(ERANGE);
131 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
132 func(in.neg_min_denormal, in.min_denormal),
133 FE_UNDERFLOW | FE_INEXACT);
134 EXPECT_MATH_ERRNO(ERANGE);
135 }
136#endif
137 }
138
139 void test_inexact_results(SubFunc func) {
140 func(InType(1.0), in.min_denormal);
141 EXPECT_FP_EXCEPTION(FE_INEXACT);
142 }
143};
144
145#define LIST_SUB_TESTS(OutType, InType, func) \
146 using LlvmLibcSubTest = SubTest<OutType, InType>; \
147 TEST_F(LlvmLibcSubTest, SpecialNumbers) { test_special_numbers(&func); } \
148 TEST_F(LlvmLibcSubTest, InvalidOperations) { \
149 test_invalid_operations(&func); \
150 } \
151 TEST_F(LlvmLibcSubTest, RangeErrors) { test_range_errors(&func); } \
152 TEST_F(LlvmLibcSubTest, InexactResults) { test_inexact_results(&func); }
153
154#define LIST_SUB_SAME_TYPE_TESTS(suffix, OutType, InType, func) \
155 using LlvmLibcSubTest##suffix = SubTest<OutType, InType>; \
156 TEST_F(LlvmLibcSubTest##suffix, SpecialNumbers) { \
157 test_special_numbers(&func); \
158 } \
159 TEST_F(LlvmLibcSubTest##suffix, InvalidOperations) { \
160 test_invalid_operations(&func); \
161 } \
162 TEST_F(LlvmLibcSubTest##suffix, RangeErrors) { test_range_errors(&func); } \
163 TEST_F(LlvmLibcSubTest##suffix, InexactResults) { \
164 test_inexact_results(&func); \
165 }
166
167#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_SUBTEST_H
168

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