Skip to content

Commit fdf2094

Browse files
authored
[libc][math] Fix signaling NaN handling for math functions. (#133347)
Add tests for signaling NaNs, and fix function behavior for handling signaling NaN input. Fixes #124812
1 parent dae0ef5 commit fdf2094

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+399
-12
lines changed

libc/src/math/generic/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4169,7 +4169,9 @@ add_entrypoint_object(
41694169
atan2f_float.h
41704170
DEPENDS
41714171
.inv_trigf_utils
4172+
libc.hdr.fenv_macros
41724173
libc.src.__support.FPUtil.double_double
4174+
libc.src.__support.FPUtil.fenv_impl
41734175
libc.src.__support.FPUtil.fp_bits
41744176
libc.src.__support.FPUtil.multiply_add
41754177
libc.src.__support.FPUtil.nearest_integer
@@ -4187,6 +4189,7 @@ add_entrypoint_object(
41874189
DEPENDS
41884190
.atan_utils
41894191
libc.src.__support.FPUtil.double_double
4192+
libc.src.__support.FPUtil.fenv_impl
41904193
libc.src.__support.FPUtil.fp_bits
41914194
libc.src.__support.FPUtil.multiply_add
41924195
libc.src.__support.FPUtil.nearest_integer

libc/src/math/generic/acosf.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,17 @@ LLVM_LIBC_FUNCTION(float, acosf, (float x)) {
8484
0x1.921fb6p+1f)
8585
: /* x == 1.0f */ 0.0f;
8686

87+
if (xbits.is_signaling_nan()) {
88+
fputil::raise_except_if_required(FE_INVALID);
89+
return FPBits::quiet_nan().get_val();
90+
}
91+
92+
// |x| <= +/-inf
8793
if (x_abs <= 0x7f80'0000U) {
8894
fputil::set_errno_if_required(EDOM);
8995
fputil::raise_except_if_required(FE_INVALID);
9096
}
97+
9198
return x + FPBits::quiet_nan().get_val();
9299
}
93100

libc/src/math/generic/asinf.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,16 @@ LLVM_LIBC_FUNCTION(float, asinf, (float x)) {
108108

109109
// |x| > 1, return NaNs.
110110
if (LIBC_UNLIKELY(x_abs > 0x3f80'0000U)) {
111+
if (xbits.is_signaling_nan()) {
112+
fputil::raise_except_if_required(FE_INVALID);
113+
return FPBits::quiet_nan().get_val();
114+
}
115+
111116
if (x_abs <= 0x7f80'0000U) {
112117
fputil::set_errno_if_required(EDOM);
113118
fputil::raise_except_if_required(FE_INVALID);
114119
}
120+
115121
return FPBits::quiet_nan().get_val();
116122
}
117123

libc/src/math/generic/asinhf.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,14 @@ LLVM_LIBC_FUNCTION(float, asinhf, (float x)) {
6161
};
6262

6363
if (LIBC_UNLIKELY(x_abs >= 0x4bdd'65a5U)) {
64-
if (LIBC_UNLIKELY(xbits.is_inf_or_nan()))
64+
if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) {
65+
if (xbits.is_signaling_nan()) {
66+
fputil::raise_except_if_required(FE_INVALID);
67+
return FPBits_t::quiet_nan().get_val();
68+
}
69+
6570
return x;
71+
}
6672

6773
// Exceptional cases when x > 2^24.
6874
switch (x_abs) {

libc/src/math/generic/atan2.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "src/math/atan2.h"
1010
#include "atan_utils.h"
11+
#include "src/__support/FPUtil/FEnvImpl.h"
1112
#include "src/__support/FPUtil/FPBits.h"
1213
#include "src/__support/FPUtil/double_double.h"
1314
#include "src/__support/FPUtil/multiply_add.h"
@@ -111,8 +112,11 @@ LLVM_LIBC_FUNCTION(double, atan2, (double y, double x)) {
111112
// Check for exceptional cases, whether inputs are 0, inf, nan, or close to
112113
// overflow, or close to underflow.
113114
if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) {
114-
if (x_bits.is_nan() || y_bits.is_nan())
115+
if (x_bits.is_nan() || y_bits.is_nan()) {
116+
if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
117+
fputil::raise_except_if_required(FE_INVALID);
115118
return FPBits::quiet_nan().get_val();
119+
}
116120
unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
117121
unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
118122

libc/src/math/generic/atan2f.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "src/math/atan2f.h"
10+
#include "hdr/fenv_macros.h"
1011
#include "inv_trigf_utils.h"
12+
#include "src/__support/FPUtil/FEnvImpl.h"
1113
#include "src/__support/FPUtil/FPBits.h"
1214
#include "src/__support/FPUtil/PolyEval.h"
1315
#include "src/__support/FPUtil/double_double.h"
@@ -264,8 +266,11 @@ LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
264266
double den_d = static_cast<double>(den_f);
265267

266268
if (LIBC_UNLIKELY(max_abs >= 0x7f80'0000U || num_d == 0.0)) {
267-
if (x_bits.is_nan() || y_bits.is_nan())
269+
if (x_bits.is_nan() || y_bits.is_nan()) {
270+
if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
271+
fputil::raise_except_if_required(FE_INVALID);
268272
return FPBits::quiet_nan().get_val();
273+
}
269274
double x_d = static_cast<double>(x);
270275
double y_d = static_cast<double>(y);
271276
size_t x_except = (x_d == 0.0) ? 0 : (x_abs == 0x7f80'0000 ? 2 : 1);

libc/src/math/generic/atanhf.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ LLVM_LIBC_FUNCTION(float, atanhf, (float x)) {
2424
// |x| >= 1.0
2525
if (LIBC_UNLIKELY(x_abs >= 0x3F80'0000U)) {
2626
if (xbits.is_nan()) {
27+
if (xbits.is_signaling_nan()) {
28+
fputil::raise_except_if_required(FE_INVALID);
29+
return FPBits::quiet_nan().get_val();
30+
}
2731
return x;
2832
}
2933
// |x| == 1.0

libc/src/math/generic/cos.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ LLVM_LIBC_FUNCTION(double, cos, (double x)) {
6565
} else {
6666
// Inf or NaN
6767
if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) {
68-
// sin(+-Inf) = NaN
68+
if (xbits.is_signaling_nan()) {
69+
fputil::raise_except_if_required(FE_INVALID);
70+
return FPBits::quiet_nan().get_val();
71+
}
72+
// cos(+-Inf) = NaN
6973
if (xbits.get_mantissa() == 0) {
7074
fputil::set_errno_if_required(EDOM);
7175
fputil::raise_except_if_required(FE_INVALID);

libc/src/math/generic/cosf.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ LLVM_LIBC_FUNCTION(float, cosf, (float x)) {
117117

118118
// x is inf or nan.
119119
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
120+
if (xbits.is_signaling_nan()) {
121+
fputil::raise_except_if_required(FE_INVALID);
122+
return FPBits::quiet_nan().get_val();
123+
}
124+
120125
if (x_abs == 0x7f80'0000U) {
121126
fputil::set_errno_if_required(EDOM);
122127
fputil::raise_except_if_required(FE_INVALID);

libc/src/math/generic/cosf16.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ LLVM_LIBC_FUNCTION(float16, cosf16, (float16 x)) {
6767

6868
// cos(+/-inf) = NaN, and cos(NaN) = NaN
6969
if (xbits.is_inf_or_nan()) {
70+
if (xbits.is_signaling_nan()) {
71+
fputil::raise_except_if_required(FE_INVALID);
72+
return FPBits::quiet_nan().get_val();
73+
}
74+
7075
if (xbits.is_inf()) {
7176
fputil::set_errno_if_required(EDOM);
7277
fputil::raise_except_if_required(FE_INVALID);

0 commit comments

Comments
 (0)