1//===-- Utility class to test different flavors of float div --------------===//
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_DIVTEST_H
10#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_DIVTEST_H
11
12#include "hdr/errno_macros.h"
13#include "hdr/fenv_macros.h"
14#include "test/UnitTest/FEnvSafeTest.h"
15#include "test/UnitTest/FPMatcher.h"
16#include "test/UnitTest/RoundingModeUtils.h"
17#include "test/UnitTest/Test.h"
18
19using LIBC_NAMESPACE::Sign;
20
21template <typename OutType, typename InType>
22class DivTest : 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 DivFunc = OutType (*)(InType, InType);
37
38 void test_special_numbers(DivFunc 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(neg_inf, func(in.inf, in.neg_zero));
49 EXPECT_FP_EQ(inf, func(in.neg_inf, in.neg_zero));
50 }
51
52 void test_division_by_zero(DivFunc func) {
53 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), in.zero), FE_DIVBYZERO);
54 EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(-1.0), in.zero),
55 FE_DIVBYZERO);
56 EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(1.0), in.neg_zero),
57 FE_DIVBYZERO);
58 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), in.zero), FE_DIVBYZERO);
59 }
60
61 void test_invalid_operations(DivFunc func) {
62 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.zero, in.zero), FE_INVALID);
63 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_zero, in.zero), FE_INVALID);
64 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.zero, in.neg_zero), FE_INVALID);
65 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_zero, in.neg_zero), FE_INVALID);
66
67 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.inf), FE_INVALID);
68 EXPECT_MATH_ERRNO(EDOM);
69 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.inf), FE_INVALID);
70 EXPECT_MATH_ERRNO(EDOM);
71 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_inf), FE_INVALID);
72 EXPECT_MATH_ERRNO(EDOM);
73 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_inf), FE_INVALID);
74 EXPECT_MATH_ERRNO(EDOM);
75 }
76
77 void test_range_errors(DivFunc func) {
78 using namespace LIBC_NAMESPACE::fputil::testing;
79
80 if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
81 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.min_normal),
82 FE_OVERFLOW | FE_INEXACT);
83 EXPECT_MATH_ERRNO(ERANGE);
84 EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
85 func(in.neg_max_normal, in.min_denormal),
86 FE_OVERFLOW | FE_INEXACT);
87 EXPECT_MATH_ERRNO(ERANGE);
88
89 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
90 FE_UNDERFLOW | FE_INEXACT);
91 EXPECT_MATH_ERRNO(ERANGE);
92 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
93 func(in.neg_min_denormal, in.max_normal),
94 FE_UNDERFLOW | FE_INEXACT);
95 EXPECT_MATH_ERRNO(ERANGE);
96 }
97
98 if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
99 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
100 func(in.max_normal, in.min_normal),
101 FE_OVERFLOW | FE_INEXACT);
102 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
103 func(in.neg_max_normal, in.min_denormal),
104 FE_OVERFLOW | FE_INEXACT);
105
106 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
107 FE_UNDERFLOW | FE_INEXACT);
108 EXPECT_MATH_ERRNO(ERANGE);
109 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
110 func(in.neg_min_denormal, in.max_normal),
111 FE_UNDERFLOW | FE_INEXACT);
112 EXPECT_MATH_ERRNO(ERANGE);
113 }
114
115 if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
116 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
117 func(in.max_normal, in.min_normal),
118 FE_OVERFLOW | FE_INEXACT);
119 EXPECT_FP_EQ_WITH_EXCEPTION(-inf,
120 func(in.neg_max_normal, in.min_denormal),
121 FE_OVERFLOW | FE_INEXACT);
122 EXPECT_MATH_ERRNO(ERANGE);
123
124 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.max_normal),
125 FE_UNDERFLOW | FE_INEXACT);
126 EXPECT_MATH_ERRNO(ERANGE);
127 EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal,
128 func(in.neg_min_denormal, in.max_normal),
129 FE_UNDERFLOW | FE_INEXACT);
130 EXPECT_MATH_ERRNO(ERANGE);
131 }
132
133 if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
134 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.min_normal),
135 FE_OVERFLOW | FE_INEXACT);
136 EXPECT_MATH_ERRNO(ERANGE);
137 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
138 func(in.neg_max_normal, in.min_denormal),
139 FE_OVERFLOW | FE_INEXACT);
140
141 EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
142 func(in.min_denormal, in.max_normal),
143 FE_UNDERFLOW | FE_INEXACT);
144 EXPECT_MATH_ERRNO(ERANGE);
145 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
146 func(in.neg_min_denormal, in.max_normal),
147 FE_UNDERFLOW | FE_INEXACT);
148 EXPECT_MATH_ERRNO(ERANGE);
149 }
150 }
151
152 void test_inexact_results(DivFunc func) {
153 func(InType(1.0), InType(3.0));
154 EXPECT_FP_EXCEPTION(FE_INEXACT);
155 }
156};
157
158#define LIST_DIV_TESTS(OutType, InType, func) \
159 using LlvmLibcDivTest = DivTest<OutType, InType>; \
160 TEST_F(LlvmLibcDivTest, SpecialNumbers) { test_special_numbers(&func); } \
161 TEST_F(LlvmLibcDivTest, DivisionByZero) { test_division_by_zero(&func); } \
162 TEST_F(LlvmLibcDivTest, InvalidOperations) { \
163 test_invalid_operations(&func); \
164 } \
165 TEST_F(LlvmLibcDivTest, RangeErrors) { test_range_errors(&func); } \
166 TEST_F(LlvmLibcDivTest, InexactResults) { test_inexact_results(&func); }
167
168#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_DIVTEST_H
169

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