diff options
author | Zakaria Fadli <fadli@adacore.com> | 2025-09-22 19:11:33 +0200 |
---|---|---|
committer | Jeff Johnston <jjohnstn@redhat.com> | 2025-09-22 14:54:00 -0400 |
commit | 63dc988ac7454b701ee923590f18df4103587994 (patch) | |
tree | cef15e41c706117180943e674a7ce8ec056b069b /newlib/libc/stdlib/strtold.c | |
parent | 8a5d39527f9a56d1a623e86d30af6b590fd1472d (diff) | |
download | newlib-main.zip newlib-main.tar.gz newlib-main.tar.bz2 |
The implementation of strtorQ is imported from FreeBSD's gdtoa library (By David
M. Gay) with some adaptations to fit with newlib.
`strtorQ.c` enables `strtold` to perform correct parsing on targets where long
double uses the IEEE754 binary128 format (113-bit mantissa), such as AArch64.
Without this patch, strtold would wrongly fallback to `strtorx` which will
parse into a 80-bit long double and give invalid result.
* libc/stdlib/strtorQ.c: New file, adapted from FreeBSD gdtoa.
* libc/stdlib/strtold.c (_strtold_impl): New helper selecting strtorx
for 80-bit and strtorQ for 128-bit long double.
(_strtold_r, strtold_l, strtold): Use _strtold_impl.
* libc/stdlib/mprec.h (_strtorQ_l): Declare.
* libc/stdlib/Makefile.inc (libc_a_SOURCES): Add strtorQ.c.
* newlib/Makefile.in: Regenerate with automake
Signed-off-by: Zakaria Fadli <fadli@adacore.com>
Diffstat (limited to 'newlib/libc/stdlib/strtold.c')
-rw-r--r-- | newlib/libc/stdlib/strtold.c | 56 |
1 files changed, 27 insertions, 29 deletions
diff --git a/newlib/libc/stdlib/strtold.c b/newlib/libc/stdlib/strtold.c index 6bd1c2c..57cc38e 100644 --- a/newlib/libc/stdlib/strtold.c +++ b/newlib/libc/stdlib/strtold.c @@ -58,47 +58,45 @@ __flt_rounds(void) #define FLT_ROUNDS 0 #endif -long double -_strtold_r (struct _reent *ptr, const char *__restrict s00, - char **__restrict se) -{ -#ifdef _LDBL_EQ_DBL - /* On platforms where long double is as wide as double. */ - return _strtod_l (ptr, s00, se, __get_current_locale ()); -#else +/* + * The core implementation for the strtold family of functions, handling + * different long double formats. + */ +static long double +_strtold_impl(struct _reent *ptr, const char *__restrict s00, + char **__restrict se, locale_t loc) { +#if defined(_LDBL_EQ_DBL) + /* On platforms where long double is as wide as double. */ + return _strtod_l(ptr, s00, se, loc); +#elif LDBL_MANT_DIG == 64 /* For 80 bit long doubles */ long double result; - - _strtorx_l (ptr, s00, se, FLT_ROUNDS, &result, __get_current_locale ()); + _strtorx_l(ptr, s00, se, FLT_ROUNDS, &result, loc); return result; +#elif LDBL_MANT_DIG == 113 /* For 128bit long doubles */ + long double result; + _strtorQ_l(ptr, s00, se, FLT_ROUNDS, &result, loc); + return result; +#else +#warning "strtold not implemented for this long double format" + return (long double)_strtod_l(ptr, s00, se, loc); #endif } long double -strtold_l (const char *__restrict s00, char **__restrict se, locale_t loc) -{ -#ifdef _LDBL_EQ_DBL - /* On platforms where long double is as wide as double. */ - return _strtod_l (_REENT, s00, se, loc); -#else - long double result; +_strtold_r(struct _reent *ptr, const char *__restrict s00, + char **__restrict se) { + return _strtold_impl(ptr, s00, se, __get_current_locale()); +} - _strtorx_l (_REENT, s00, se, FLT_ROUNDS, &result, loc); - return result; -#endif +long double +strtold_l(const char *__restrict s00, char **__restrict se, locale_t loc) { + return _strtold_impl(_REENT, s00, se, loc); } long double strtold (const char *__restrict s00, char **__restrict se) { -#ifdef _LDBL_EQ_DBL - /* On platforms where long double is as wide as double. */ - return _strtod_l (_REENT, s00, se, __get_current_locale ()); -#else - long double result; - - _strtorx_l (_REENT, s00, se, FLT_ROUNDS, &result, __get_current_locale ()); - return result; -#endif + return _strtold_impl(_REENT, s00, se, __get_current_locale()); } #endif /* _HAVE_LONG_DOUBLE */ |