Skip to content

Commit 1d493ef

Browse files
lntueyuxuanchen1997
authored andcommitted
[libc][math] Update getpayload and fmul/fadd/fsub/ffma with NaN inputs. (#99812)
Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251352
1 parent f3c7149 commit 1d493ef

File tree

11 files changed

+111
-148
lines changed

11 files changed

+111
-148
lines changed

libc/config/linux/riscv/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ set(TARGET_LIBM_ENTRYPOINTS
377377
libc.src.math.cosf
378378
libc.src.math.coshf
379379
libc.src.math.cospif
380+
libc.src.math.dmull
380381
libc.src.math.dsqrtl
381382
libc.src.math.erff
382383
libc.src.math.exp
@@ -434,6 +435,7 @@ set(TARGET_LIBM_ENTRYPOINTS
434435
libc.src.math.fmodf
435436
libc.src.math.fmodl
436437
libc.src.math.fmul
438+
libc.src.math.fmull
437439
libc.src.math.frexp
438440
libc.src.math.frexpf
439441
libc.src.math.frexpl

libc/src/__support/FPUtil/BasicOperations.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
#include "FEnvImpl.h"
1313
#include "FPBits.h"
14+
#include "dyadic_float.h"
1415

15-
#include "FEnvImpl.h"
1616
#include "src/__support/CPP/type_traits.h"
1717
#include "src/__support/common.h"
1818
#include "src/__support/macros/config.h"
@@ -269,12 +269,21 @@ totalordermag(T x, T y) {
269269
template <typename T>
270270
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> getpayload(T x) {
271271
using FPBits = FPBits<T>;
272+
using StorageType = typename FPBits::StorageType;
272273
FPBits x_bits(x);
273274

274275
if (!x_bits.is_nan())
275276
return T(-1.0);
276277

277-
return T(x_bits.uintval() & (FPBits::FRACTION_MASK >> 1));
278+
StorageType payload = x_bits.uintval() & (FPBits::FRACTION_MASK >> 1);
279+
280+
if constexpr (is_big_int_v<StorageType>) {
281+
DyadicFloat<FPBits::STORAGE_LEN> payload_dfloat(Sign::POS, 0, payload);
282+
283+
return static_cast<T>(payload_dfloat);
284+
} else {
285+
return static_cast<T>(payload);
286+
}
278287
}
279288

280289
template <bool IsSignaling, typename T>

libc/src/__support/FPUtil/CMakeLists.txt

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,6 @@ add_header_library(
7575
libc.src.__support.common
7676
)
7777

78-
add_header_library(
79-
basic_operations
80-
HDRS
81-
BasicOperations.h
82-
DEPENDS
83-
.fp_bits
84-
.fenv_impl
85-
libc.src.__support.CPP.type_traits
86-
libc.src.__support.uint128
87-
libc.src.__support.common
88-
libc.src.__support.macros.optimization
89-
)
90-
9178
add_header_library(
9279
division_and_remainder_operations
9380
HDRS
@@ -113,21 +100,6 @@ add_header_library(
113100
)
114101

115102

116-
add_header_library(
117-
hypot
118-
HDRS
119-
Hypot.h
120-
DEPENDS
121-
.basic_operations
122-
.fenv_impl
123-
.fp_bits
124-
.rounding_mode
125-
libc.src.__support.common
126-
libc.src.__support.CPP.bit
127-
libc.src.__support.CPP.type_traits
128-
libc.src.__support.uint128
129-
)
130-
131103
add_header_library(
132104
sqrt
133105
HDRS
@@ -208,6 +180,35 @@ add_header_library(
208180
libc.src.__support.macros.optimization
209181
)
210182

183+
add_header_library(
184+
basic_operations
185+
HDRS
186+
BasicOperations.h
187+
DEPENDS
188+
.dyadic_float
189+
.fp_bits
190+
.fenv_impl
191+
libc.src.__support.CPP.type_traits
192+
libc.src.__support.uint128
193+
libc.src.__support.common
194+
libc.src.__support.macros.optimization
195+
)
196+
197+
add_header_library(
198+
hypot
199+
HDRS
200+
Hypot.h
201+
DEPENDS
202+
.basic_operations
203+
.fenv_impl
204+
.fp_bits
205+
.rounding_mode
206+
libc.src.__support.common
207+
libc.src.__support.CPP.bit
208+
libc.src.__support.CPP.type_traits
209+
libc.src.__support.uint128
210+
)
211+
211212
add_header_library(
212213
manipulation_functions
213214
HDRS

libc/src/__support/FPUtil/generic/FMA.h

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,27 +129,27 @@ fma(InType x, InType y, InType z) {
129129
raise_except_if_required(FE_INVALID);
130130

131131
if (x_bits.is_quiet_nan()) {
132-
InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
133-
if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
134-
return OutFPBits::quiet_nan(x_bits.sign(),
135-
static_cast<OutStorageType>(x_payload))
136-
.get_val();
132+
InStorageType x_payload = x_bits.get_mantissa();
133+
x_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
134+
return OutFPBits::quiet_nan(x_bits.sign(),
135+
static_cast<OutStorageType>(x_payload))
136+
.get_val();
137137
}
138138

139139
if (y_bits.is_quiet_nan()) {
140-
InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
141-
if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
142-
return OutFPBits::quiet_nan(y_bits.sign(),
143-
static_cast<OutStorageType>(y_payload))
144-
.get_val();
140+
InStorageType y_payload = y_bits.get_mantissa();
141+
y_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
142+
return OutFPBits::quiet_nan(y_bits.sign(),
143+
static_cast<OutStorageType>(y_payload))
144+
.get_val();
145145
}
146146

147147
if (z_bits.is_quiet_nan()) {
148-
InStorageType z_payload = static_cast<InStorageType>(getpayload(z));
149-
if ((z_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
150-
return OutFPBits::quiet_nan(z_bits.sign(),
151-
static_cast<OutStorageType>(z_payload))
152-
.get_val();
148+
InStorageType z_payload = z_bits.get_mantissa();
149+
z_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
150+
return OutFPBits::quiet_nan(z_bits.sign(),
151+
static_cast<OutStorageType>(z_payload))
152+
.get_val();
153153
}
154154

155155
return OutFPBits::quiet_nan().get_val();
@@ -163,18 +163,27 @@ fma(InType x, InType y, InType z) {
163163
int y_exp = 0;
164164
int z_exp = 0;
165165

166+
// Denormal scaling = 2^(fraction length).
167+
constexpr InStorageType IMPLICIT_MASK =
168+
InFPBits::SIG_MASK - InFPBits::FRACTION_MASK;
169+
170+
constexpr InType DENORMAL_SCALING =
171+
InFPBits::create_value(
172+
Sign::POS, InFPBits::FRACTION_LEN + InFPBits::EXP_BIAS, IMPLICIT_MASK)
173+
.get_val();
174+
166175
// Normalize denormal inputs.
167176
if (LIBC_UNLIKELY(InFPBits(x).is_subnormal())) {
168177
x_exp -= InFPBits::FRACTION_LEN;
169-
x *= InType(InStorageType(1) << InFPBits::FRACTION_LEN);
178+
x *= DENORMAL_SCALING;
170179
}
171180
if (LIBC_UNLIKELY(InFPBits(y).is_subnormal())) {
172181
y_exp -= InFPBits::FRACTION_LEN;
173-
y *= InType(InStorageType(1) << InFPBits::FRACTION_LEN);
182+
y *= DENORMAL_SCALING;
174183
}
175184
if (LIBC_UNLIKELY(InFPBits(z).is_subnormal())) {
176185
z_exp -= InFPBits::FRACTION_LEN;
177-
z *= InType(InStorageType(1) << InFPBits::FRACTION_LEN);
186+
z *= DENORMAL_SCALING;
178187
}
179188

180189
x_bits = InFPBits(x);

libc/src/__support/FPUtil/generic/add_sub.h

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,19 @@ add_or_sub(InType x, InType y) {
5656
raise_except_if_required(FE_INVALID);
5757

5858
if (x_bits.is_quiet_nan()) {
59-
InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
60-
if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
61-
return OutFPBits::quiet_nan(x_bits.sign(),
62-
static_cast<OutStorageType>(x_payload))
63-
.get_val();
59+
InStorageType x_payload = x_bits.get_mantissa();
60+
x_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
61+
return OutFPBits::quiet_nan(x_bits.sign(),
62+
static_cast<OutStorageType>(x_payload))
63+
.get_val();
6464
}
6565

6666
if (y_bits.is_quiet_nan()) {
67-
InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
68-
if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
69-
return OutFPBits::quiet_nan(y_bits.sign(),
70-
static_cast<OutStorageType>(y_payload))
71-
.get_val();
67+
InStorageType y_payload = y_bits.get_mantissa();
68+
y_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
69+
return OutFPBits::quiet_nan(y_bits.sign(),
70+
static_cast<OutStorageType>(y_payload))
71+
.get_val();
7272
}
7373

7474
return OutFPBits::quiet_nan().get_val();
@@ -174,10 +174,12 @@ add_or_sub(InType x, InType y) {
174174
else
175175
aligned_min_mant_sticky = true;
176176

177+
InStorageType min_mant_sticky(static_cast<int>(aligned_min_mant_sticky));
178+
177179
if (is_effectively_add)
178-
result_mant = max_mant + (aligned_min_mant | aligned_min_mant_sticky);
180+
result_mant = max_mant + (aligned_min_mant | min_mant_sticky);
179181
else
180-
result_mant = max_mant - (aligned_min_mant | aligned_min_mant_sticky);
182+
result_mant = max_mant - (aligned_min_mant | min_mant_sticky);
181183
}
182184

183185
int result_exp = max_bits.get_exponent() - RESULT_FRACTION_LEN;

libc/src/__support/FPUtil/generic/div.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ div(InType x, InType y) {
4949
raise_except_if_required(FE_INVALID);
5050

5151
if (x_bits.is_quiet_nan()) {
52-
InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
53-
if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
54-
return OutFPBits::quiet_nan(x_bits.sign(),
55-
static_cast<OutStorageType>(x_payload))
56-
.get_val();
52+
InStorageType x_payload = x_bits.get_mantissa();
53+
x_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
54+
return OutFPBits::quiet_nan(x_bits.sign(),
55+
static_cast<OutStorageType>(x_payload))
56+
.get_val();
5757
}
5858

5959
if (y_bits.is_quiet_nan()) {
60-
InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
61-
if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
62-
return OutFPBits::quiet_nan(y_bits.sign(),
63-
static_cast<OutStorageType>(y_payload))
64-
.get_val();
60+
InStorageType y_payload = y_bits.get_mantissa();
61+
y_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
62+
return OutFPBits::quiet_nan(y_bits.sign(),
63+
static_cast<OutStorageType>(y_payload))
64+
.get_val();
6565
}
6666

6767
return OutFPBits::quiet_nan().get_val();

libc/src/__support/FPUtil/generic/mul.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ mul(InType x, InType y) {
5050
raise_except_if_required(FE_INVALID);
5151

5252
if (x_bits.is_quiet_nan()) {
53-
InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
54-
if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
55-
return OutFPBits::quiet_nan(x_bits.sign(),
56-
static_cast<OutStorageType>(x_payload))
57-
.get_val();
53+
InStorageType x_payload = x_bits.get_mantissa();
54+
x_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
55+
return OutFPBits::quiet_nan(x_bits.sign(),
56+
static_cast<OutStorageType>(x_payload))
57+
.get_val();
5858
}
5959

6060
if (y_bits.is_quiet_nan()) {
61-
InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
62-
if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
63-
return OutFPBits::quiet_nan(y_bits.sign(),
64-
static_cast<OutStorageType>(y_payload))
65-
.get_val();
61+
InStorageType y_payload = y_bits.get_mantissa();
62+
y_payload >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
63+
return OutFPBits::quiet_nan(y_bits.sign(),
64+
static_cast<OutStorageType>(y_payload))
65+
.get_val();
6666
}
6767

6868
return OutFPBits::quiet_nan().get_val();

libc/test/src/math/smoke/AddTest.h

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,8 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
3838
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
3939

4040
InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
41-
EXPECT_FP_EQ(InType(0x42.0p+0),
42-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, zero)));
43-
EXPECT_FP_EQ(InType(0x42.0p+0),
44-
LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_42)));
45-
46-
if constexpr (sizeof(OutType) < sizeof(InType)) {
47-
InStorageType max_payload = InFPBits::FRACTION_MASK >> 1;
48-
InType qnan_max = InFPBits::quiet_nan(Sign::POS, max_payload).get_val();
49-
EXPECT_FP_EQ(zero,
50-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, zero)));
51-
EXPECT_FP_EQ(zero,
52-
LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_max)));
53-
EXPECT_FP_EQ(InType(0x42.0p+0),
54-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, qnan_42)));
55-
EXPECT_FP_EQ(InType(0x42.0p+0),
56-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, qnan_max)));
57-
}
41+
EXPECT_FP_IS_NAN(func(qnan_42, zero));
42+
EXPECT_FP_IS_NAN(func(zero, qnan_42));
5843

5944
EXPECT_FP_EQ(inf, func(inf, zero));
6045
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));

libc/test/src/math/smoke/DivTest.h

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,8 @@ class DivTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
3636
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
3737

3838
InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
39-
EXPECT_FP_EQ(InType(0x42.0p+0),
40-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, zero)));
41-
EXPECT_FP_EQ(InType(0x42.0p+0),
42-
LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_42)));
43-
44-
if constexpr (sizeof(OutType) < sizeof(InType)) {
45-
InStorageType max_payload = InFPBits::FRACTION_MASK >> 1;
46-
InType qnan_max = InFPBits::quiet_nan(Sign::POS, max_payload).get_val();
47-
EXPECT_FP_EQ(zero,
48-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, zero)));
49-
EXPECT_FP_EQ(zero,
50-
LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_max)));
51-
EXPECT_FP_EQ(InType(0x42.0p+0),
52-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, qnan_42)));
53-
EXPECT_FP_EQ(InType(0x42.0p+0),
54-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, qnan_max)));
55-
}
39+
EXPECT_FP_IS_NAN(func(qnan_42, zero));
40+
EXPECT_FP_IS_NAN(func(zero, qnan_42));
5641

5742
EXPECT_FP_EQ(inf, func(inf, zero));
5843
EXPECT_FP_EQ(neg_inf, func(neg_inf, zero));

libc/test/src/math/smoke/MulTest.h

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,8 @@ class MulTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
3838
EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID);
3939

4040
InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val();
41-
EXPECT_FP_EQ(InType(0x42.0p+0),
42-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, zero)));
43-
EXPECT_FP_EQ(InType(0x42.0p+0),
44-
LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_42)));
45-
46-
if constexpr (sizeof(OutType) < sizeof(InType)) {
47-
InStorageType max_payload = InFPBits::FRACTION_MASK >> 1;
48-
InType qnan_max = InFPBits::quiet_nan(Sign::POS, max_payload).get_val();
49-
EXPECT_FP_EQ(zero,
50-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, zero)));
51-
EXPECT_FP_EQ(zero,
52-
LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_max)));
53-
EXPECT_FP_EQ(InType(0x42.0p+0),
54-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, qnan_42)));
55-
EXPECT_FP_EQ(InType(0x42.0p+0),
56-
LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, qnan_max)));
57-
}
41+
EXPECT_FP_IS_NAN(func(qnan_42, zero));
42+
EXPECT_FP_IS_NAN(func(zero, qnan_42));
5843

5944
EXPECT_FP_EQ(inf, func(inf, InType(1.0)));
6045
EXPECT_FP_EQ(neg_inf, func(neg_inf, InType(1.0)));

0 commit comments

Comments
 (0)