Skip to content

Commit 0504e93

Browse files
authored
[libc][math] Implement nan(f|l) functions (#76690)
Specification: https://en.cppreference.com/w/c/numeric/math/nan
1 parent f7f7574 commit 0504e93

File tree

23 files changed

+451
-20
lines changed

23 files changed

+451
-20
lines changed

libc/config/darwin/arm/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ set(TARGET_LIBM_ENTRYPOINTS
193193
libc.src.math.modf
194194
libc.src.math.modff
195195
libc.src.math.modfl
196+
libc.src.math.nan
197+
libc.src.math.nanf
198+
libc.src.math.nanl
196199
libc.src.math.nearbyint
197200
libc.src.math.nearbyintf
198201
libc.src.math.nearbyintl

libc/config/darwin/x86_64/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ set(TARGET_LIBM_ENTRYPOINTS
172172
#libc.src.math.modf
173173
#libc.src.math.modff
174174
#libc.src.math.modfl
175+
#libc.src.math.nan
176+
#libc.src.math.nanf
177+
#libc.src.math.nanl
175178
#libc.src.math.nearbyint
176179
#libc.src.math.nearbyintf
177180
#libc.src.math.nearbyintl

libc/config/gpu/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ set(TARGET_LIBM_ENTRYPOINTS
215215
libc.src.math.lroundf
216216
libc.src.math.modf
217217
libc.src.math.modff
218+
libc.src.math.nan
219+
libc.src.math.nanf
218220
libc.src.math.nearbyint
219221
libc.src.math.nearbyintf
220222
libc.src.math.nextafter

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ set(TARGET_LIBM_ENTRYPOINTS
313313
libc.src.math.modf
314314
libc.src.math.modff
315315
libc.src.math.modfl
316+
libc.src.math.nan
317+
libc.src.math.nanf
318+
libc.src.math.nanl
316319
libc.src.math.nearbyint
317320
libc.src.math.nearbyintf
318321
libc.src.math.nearbyintl

libc/config/linux/riscv/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ set(TARGET_LIBM_ENTRYPOINTS
322322
libc.src.math.modf
323323
libc.src.math.modff
324324
libc.src.math.modfl
325+
libc.src.math.nan
326+
libc.src.math.nanf
327+
libc.src.math.nanl
325328
libc.src.math.nearbyint
326329
libc.src.math.nearbyintf
327330
libc.src.math.nearbyintl

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ set(TARGET_LIBM_ENTRYPOINTS
323323
libc.src.math.modf
324324
libc.src.math.modff
325325
libc.src.math.modfl
326+
libc.src.math.nan
327+
libc.src.math.nanf
328+
libc.src.math.nanl
326329
libc.src.math.nearbyint
327330
libc.src.math.nearbyintf
328331
libc.src.math.nearbyintl

libc/config/windows/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ set(TARGET_LIBM_ENTRYPOINTS
192192
libc.src.math.modf
193193
libc.src.math.modff
194194
libc.src.math.modfl
195+
libc.src.math.nan
196+
libc.src.math.nanf
197+
libc.src.math.nanl
195198
libc.src.math.nearbyint
196199
libc.src.math.nearbyintf
197200
libc.src.math.nearbyintl

libc/docs/math/index.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,11 @@ Basic Operations
212212
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
213213
| modfl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
214214
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
215-
| nan | | | | | | | | | | | | |
215+
| nan | |check| | |check| | | |check| | |check| | | | |check| | | | | |
216216
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
217-
| nanf | | | | | | | | | | | | |
217+
| nanf | |check| | |check| | | |check| | |check| | | | |check| | | | | |
218218
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
219-
| nanl | | | | | | | | | | | | |
219+
| nanl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
220220
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
221221
| nearbyint | |check| | |check| | | |check| | |check| | | | |check| | | | | |
222222
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+

libc/spec/stdc.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,10 @@ def StdC : StandardSpec<"stdc"> {
515515
FunctionSpec<"scalbn", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>]>,
516516
FunctionSpec<"scalbnf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>]>,
517517
FunctionSpec<"scalbnl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>]>,
518+
519+
FunctionSpec<"nanf", RetValSpec<FloatType>, [ArgSpec<ConstCharPtr>]>,
520+
FunctionSpec<"nan", RetValSpec<DoubleType>, [ArgSpec<ConstCharPtr>]>,
521+
FunctionSpec<"nanl", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharPtr>]>,
518522
]
519523
>;
520524

libc/src/__support/str_to_float.h

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "src/__support/CPP/bit.h"
1313
#include "src/__support/CPP/limits.h"
1414
#include "src/__support/CPP/optional.h"
15+
#include "src/__support/CPP/string_view.h"
1516
#include "src/__support/FPUtil/FEnvImpl.h"
1617
#include "src/__support/FPUtil/FPBits.h"
1718
#include "src/__support/FPUtil/dyadic_float.h"
@@ -1044,6 +1045,27 @@ hexadecimal_string_to_float(const char *__restrict src,
10441045
return output;
10451046
}
10461047

1048+
LIBC_INLINE uint64_t
1049+
nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) {
1050+
uint64_t nan_mantissa = 0;
1051+
1052+
if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) {
1053+
// This is to prevent errors when StorageType is larger than 64
1054+
// bits, since strtointeger only supports up to 64 bits. This is
1055+
// actually more than is required by the specification, which says
1056+
// for the input type "NAN(n-char-sequence)" that "the meaning of
1057+
// the n-char sequence is implementation-defined."
1058+
auto strtoint_result = strtointeger<uint64_t>(ncharseq.data(), 0);
1059+
if (!strtoint_result.has_error())
1060+
nan_mantissa = strtoint_result.value;
1061+
1062+
if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(ncharseq.size()))
1063+
nan_mantissa = 0;
1064+
}
1065+
1066+
return nan_mantissa;
1067+
}
1068+
10471069
// Takes a pointer to a string and a pointer to a string pointer. This function
10481070
// is used as the backend for all of the string to float functions.
10491071
template <class T>
@@ -1136,31 +1158,18 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
11361158
++index;
11371159
if (src[index] == ')') {
11381160
++index;
1139-
if (isdigit(src[left_paren + 1])) {
1140-
// This is to prevent errors when StorageType is larger than 64
1141-
// bits, since strtointeger only supports up to 64 bits. This is
1142-
// actually more than is required by the specification, which says
1143-
// for the input type "NAN(n-char-sequence)" that "the meaning of
1144-
// the n-char sequence is implementation-defined."
1145-
1146-
auto strtoint_result =
1147-
strtointeger<uint64_t>(src + (left_paren + 1), 0);
1148-
if (strtoint_result.has_error()) {
1149-
error = strtoint_result.error;
1150-
}
1151-
nan_mantissa = static_cast<StorageType>(strtoint_result.value);
1152-
if (src[left_paren + 1 + strtoint_result.parsed_len] != ')')
1153-
nan_mantissa = 0;
1154-
}
1161+
auto nan_mantissa_result = nan_mantissa_from_ncharseq(
1162+
cpp::string_view(src + (left_paren + 1), index - left_paren - 2));
1163+
nan_mantissa = static_cast<StorageType>(nan_mantissa_result);
11551164
} else {
11561165
index = left_paren;
11571166
}
11581167
}
1168+
11591169
if (result.get_sign()) {
11601170
result = FPBits(result.build_quiet_nan(nan_mantissa));
11611171
result.set_sign(true);
11621172
} else {
1163-
result.set_sign(false);
11641173
result = FPBits(result.build_quiet_nan(nan_mantissa));
11651174
}
11661175
}
@@ -1195,6 +1204,28 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
11951204
return {T(result), index, error};
11961205
}
11971206

1207+
template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) {
1208+
using FPBits = typename fputil::FPBits<T>;
1209+
using StorageType = typename FPBits::StorageType;
1210+
1211+
FPBits result;
1212+
int error = 0;
1213+
StorageType nan_mantissa = 0;
1214+
1215+
ptrdiff_t index = 0;
1216+
while (isalnum(arg[index]) || arg[index] == '_')
1217+
++index;
1218+
1219+
if (arg[index] == '\0') {
1220+
auto nan_mantissa_result =
1221+
nan_mantissa_from_ncharseq(cpp::string_view(arg, index));
1222+
nan_mantissa = static_cast<StorageType>(nan_mantissa_result);
1223+
}
1224+
1225+
result = FPBits(result.build_quiet_nan(nan_mantissa));
1226+
return {T(result), 0, error};
1227+
}
1228+
11981229
} // namespace internal
11991230
} // namespace LIBC_NAMESPACE
12001231

libc/src/math/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ add_math_entrypoint_object(modf)
179179
add_math_entrypoint_object(modff)
180180
add_math_entrypoint_object(modfl)
181181

182+
add_math_entrypoint_object(nan)
183+
add_math_entrypoint_object(nanf)
184+
add_math_entrypoint_object(nanl)
185+
182186
add_math_entrypoint_object(nearbyint)
183187
add_math_entrypoint_object(nearbyintf)
184188
add_math_entrypoint_object(nearbyintl)

libc/src/math/generic/CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,45 @@ add_entrypoint_object(
14371437
-O3
14381438
)
14391439

1440+
add_entrypoint_object(
1441+
nan
1442+
SRCS
1443+
nan.cpp
1444+
HDRS
1445+
../nan.h
1446+
DEPENDS
1447+
libc.src.__support.str_to_float
1448+
libc.src.errno.errno
1449+
COMPILE_OPTIONS
1450+
-O3
1451+
)
1452+
1453+
add_entrypoint_object(
1454+
nanf
1455+
SRCS
1456+
nanf.cpp
1457+
HDRS
1458+
../nanf.h
1459+
DEPENDS
1460+
libc.src.__support.str_to_float
1461+
libc.src.errno.errno
1462+
COMPILE_OPTIONS
1463+
-O3
1464+
)
1465+
1466+
add_entrypoint_object(
1467+
nanl
1468+
SRCS
1469+
nanl.cpp
1470+
HDRS
1471+
../nanl.h
1472+
DEPENDS
1473+
libc.src.__support.str_to_float
1474+
libc.src.errno.errno
1475+
COMPILE_OPTIONS
1476+
-O3
1477+
)
1478+
14401479
add_entrypoint_object(
14411480
nextafter
14421481
SRCS

libc/src/math/generic/nan.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation of nan function ------------------------------------===//
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+
#include "src/math/nan.h"
10+
#include "src/__support/common.h"
11+
#include "src/__support/str_to_float.h"
12+
#include "src/errno/libc_errno.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
LLVM_LIBC_FUNCTION(double, nan, (const char *arg)) {
17+
auto result = internal::strtonan<double>(arg);
18+
if (result.has_error())
19+
libc_errno = result.error;
20+
return result.value;
21+
}
22+
23+
} // namespace LIBC_NAMESPACE

libc/src/math/generic/nanf.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation of nanf function -----------------------------------===//
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+
#include "src/math/nanf.h"
10+
#include "src/__support/common.h"
11+
#include "src/__support/str_to_float.h"
12+
#include "src/errno/libc_errno.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
LLVM_LIBC_FUNCTION(float, nanf, (const char *arg)) {
17+
auto result = internal::strtonan<float>(arg);
18+
if (result.has_error())
19+
libc_errno = result.error;
20+
return result.value;
21+
}
22+
23+
} // namespace LIBC_NAMESPACE

libc/src/math/generic/nanl.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- Implementation of nanl function -----------------------------------===//
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+
#include "src/math/nanl.h"
10+
#include "src/__support/common.h"
11+
#include "src/__support/str_to_float.h"
12+
#include "src/errno/libc_errno.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
LLVM_LIBC_FUNCTION(long double, nanl, (const char *arg)) {
17+
auto result = internal::strtonan<long double>(arg);
18+
if (result.has_error())
19+
libc_errno = result.error;
20+
return result.value;
21+
}
22+
23+
} // namespace LIBC_NAMESPACE

libc/src/math/nan.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for nan ---------------------------*- 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_SRC_MATH_NAN_H
10+
#define LLVM_LIBC_SRC_MATH_NAN_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
double nan(const char *arg);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_NAN_H

libc/src/math/nanf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for nanf --------------------------*- 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_SRC_MATH_NANF_H
10+
#define LLVM_LIBC_SRC_MATH_NANF_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
float nanf(const char *arg);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_NANF_H

libc/src/math/nanl.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for nanl --------------------------*- 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_SRC_MATH_NANL_H
10+
#define LLVM_LIBC_SRC_MATH_NANL_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
long double nanl(const char *arg);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_NANL_H

0 commit comments

Comments
 (0)