1//===-- Utility class to test different flavors of float mul ----*- 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_MULTEST_H
10#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H
11
12#include "hdr/errno_macros.h"
13#include "hdr/fenv_macros.h"
14#include "src/__support/FPUtil/BasicOperations.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 MulTest : 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 MulFunc = OutType (*)(InType, InType);
37
38 void test_special_numbers(MulFunc 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, InType(1.0)));
47 EXPECT_FP_EQ(neg_inf, func(in.neg_inf, InType(1.0)));
48 EXPECT_FP_EQ(neg_inf, func(in.inf, InType(-1.0)));
49 EXPECT_FP_EQ(inf, func(in.neg_inf, InType(-1.0)));
50
51 EXPECT_FP_EQ_ALL_ROUNDING(zero, func(in.zero, in.zero));
52 EXPECT_FP_EQ_ALL_ROUNDING(zero, func(in.neg_zero, in.neg_zero));
53 EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.zero, in.neg_zero));
54 EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.neg_zero, in.zero));
55
56 EXPECT_FP_EQ_ALL_ROUNDING(OutType(1.0), func(1.0, 1.0));
57 EXPECT_FP_EQ_ALL_ROUNDING(OutType(15.0), func(3.0, 5.0));
58 EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-13), func(0x1.0p+1, 0x1.0p-14));
59 EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-10), func(0x1.0p+2, 0x1.0p-12));
60 }
61
62 void test_invalid_operations(MulFunc func) {
63 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.zero), FE_INVALID);
64 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.inf, in.neg_zero), FE_INVALID);
65 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.zero), FE_INVALID);
66 EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(in.neg_inf, in.neg_zero), FE_INVALID);
67 }
68
69 void test_range_errors(MulFunc func) {
70 using namespace LIBC_NAMESPACE::fputil::testing;
71
72 if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
73 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
74 FE_OVERFLOW | FE_INEXACT);
75 EXPECT_MATH_ERRNO(ERANGE);
76 EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf,
77 func(in.neg_max_normal, in.max_normal),
78 FE_OVERFLOW | FE_INEXACT);
79 EXPECT_MATH_ERRNO(ERANGE);
80
81 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
82 FE_UNDERFLOW | FE_INEXACT);
83 EXPECT_MATH_ERRNO(ERANGE);
84 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
85 func(in.neg_min_denormal, in.min_denormal),
86 FE_UNDERFLOW | FE_INEXACT);
87 EXPECT_MATH_ERRNO(ERANGE);
88 }
89
90 if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
91 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
92 func(in.max_normal, in.max_normal),
93 FE_OVERFLOW | FE_INEXACT);
94 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
95 func(in.neg_max_normal, in.max_normal),
96 FE_OVERFLOW | FE_INEXACT);
97
98 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
99 FE_UNDERFLOW | FE_INEXACT);
100 EXPECT_MATH_ERRNO(ERANGE);
101 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
102 func(in.neg_min_denormal, in.min_denormal),
103 FE_UNDERFLOW | FE_INEXACT);
104 EXPECT_MATH_ERRNO(ERANGE);
105 }
106
107 if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
108 EXPECT_FP_EQ_WITH_EXCEPTION(max_normal,
109 func(in.max_normal, in.max_normal),
110 FE_OVERFLOW | FE_INEXACT);
111 EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf,
112 func(in.neg_max_normal, in.max_normal),
113 FE_OVERFLOW | FE_INEXACT);
114 EXPECT_MATH_ERRNO(ERANGE);
115
116 EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(in.min_denormal, in.min_denormal),
117 FE_UNDERFLOW | FE_INEXACT);
118 EXPECT_MATH_ERRNO(ERANGE);
119 EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal,
120 func(in.neg_min_denormal, in.min_denormal),
121 FE_UNDERFLOW | FE_INEXACT);
122 EXPECT_MATH_ERRNO(ERANGE);
123 }
124
125 if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
126 EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
127 FE_OVERFLOW | FE_INEXACT);
128 EXPECT_MATH_ERRNO(ERANGE);
129 EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal,
130 func(in.neg_max_normal, in.max_normal),
131 FE_OVERFLOW | FE_INEXACT);
132
133 EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal,
134 func(in.min_denormal, in.min_denormal),
135 FE_UNDERFLOW | FE_INEXACT);
136 EXPECT_MATH_ERRNO(ERANGE);
137 EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero,
138 func(in.neg_min_denormal, in.min_denormal),
139 FE_UNDERFLOW | FE_INEXACT);
140 EXPECT_MATH_ERRNO(ERANGE);
141 }
142 }
143
144 void test_inexact_results(MulFunc func) {
145 InFPBits x_bits = InFPBits::one();
146 x_bits.set_mantissa(InFPBits::SIG_MASK);
147 InType x = x_bits.get_val();
148 func(x, x);
149 EXPECT_FP_EXCEPTION(FE_INEXACT);
150 }
151};
152
153#define LIST_MUL_TESTS(OutType, InType, func) \
154 using LlvmLibcMulTest = MulTest<OutType, InType>; \
155 TEST_F(LlvmLibcMulTest, SpecialNumbers) { test_special_numbers(&func); } \
156 TEST_F(LlvmLibcMulTest, InvalidOperations) { \
157 test_invalid_operations(&func); \
158 } \
159 TEST_F(LlvmLibcMulTest, RangeErrors) { test_range_errors(&func); } \
160 TEST_F(LlvmLibcMulTest, InexactResults) { test_inexact_results(&func); }
161
162#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_MULTEST_H
163

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