On Sat, Feb 20, 2021 at 06:33:12PM -0600, Segher Boessenkool wrote: > Hi! > > On Tue, Feb 09, 2021 at 02:35:05AM -0500, Michael Meissner wrote: > > This patch implements conversions between _Float128 and the 3 Decimal > > floating > > types. It does this by extendending the dfp-bit conversions to add a new > > binary floating point type (KF), and doing the conversions in the same > > manner > > as the other binary/decimal conversions. > > > For conversions from _Float128 to Decimal, this patch uses a function > > (__sprintfkf) instead of the sprintf function to convert long double values > > to > > strings. The __sprintfkf function determines if GLIBC 2.32 or newer is used > > and calls the IEEE 128-bit version of sprintf (__sprintfieee128). If the > > GLIBC > > is earlier than 2.32, the code will convert _Float128 to __ibm128 and then > > use > > the normal sprintf to convert this value. > > So if built with a glibc version before 2.32 (less than a year old) it > will give the wrong answer. This needs improving, or it will be another > eight or so years until this is generally usable.
But until the long double format default is changed to be IEEE 128-bit floating point, only the people who explicitly convert between __float128/_Float128 and the decimal types will see the issue. In order to switch to the IEEE 128-bit floating point long double, you need at least GLIBC 2.32, and you will get full accuracy. > > The compilers built fine providing I recompiled gmp, mpc, and mpfr with the > > appropriate long double options. There were a few differences in the test > > suite runs that will be addressed in later patches, but over all it works > > well. > > What kind of differences? I assume you checked all, and all differences > are an improvement, or the differences are inconsequential and the test > is not very good? I have submitted patches for these before, and I will shortly ping or resubmit them again. But I felt this was more import to get in before worrying about changes to the testsuite. The changes are: * C test c-c++-common/dfp/convert-bfp-11.c fails * C test gcc.target/powerpc/pr70117.c fails * C test gcc.dg/torture/float128-nan.c fails * C test gcc.target/powerpc/nan128-1.c fails * C++ test c-c++-common/dfp/convert-bfp-11.c fails * C++ tests all modules tests fails * Fortran test gfortran.dg/default_format_2.f90 now passes * Fortran test gfortran.dg/default_format_denormal_2.f90 now passes * Fortran test gfortran.dg/ieee/large_2.f90 now passes The following two tests test facets of the IBM 128-bit long double implementation. Since they are hard wired to use IBM 128-bit long double, I've added options in the patches to run these tests with -mabi=ibmlongdouble if the default is -mabi=ieeelongdouble. * c-c++-common/dfp/convert-bfp-11.c * gcc.target/powerpc/pr70117.c The following two tests fail because they are testing the old libquadmath 'q' built-ins, and there is a subtle difference between using the _Float128 built-in function for the nans function and the long double built-in function for nans. In particular, the signalling NaN is silently converted to a quiet NaN. * gcc.dg/torture/float128-nan.c * gcc.target/powerpc/nan128-1.c The modules failures are PR c++/98645, and are not a back end feature. The 3 fortran tests now pass if long double uses the IEEE 128-bit representation: * gfortran.dg/default_format_2.f90 * gfortran.dg/default_format_denormal_2.f90 * gfortran.dg/ieee/large_2.f90 > > > --- /dev/null > > +++ b/libgcc/config/rs6000/_sprintfkf.c > > @@ -0,0 +1,57 @@ > > + If we are linked against an earlier library, we will have fake it by > > + converting the value to long double, and using sprinf to do the > > conversion. > > (typo, sprintf) Fixed. > > + This isn't ideal, as IEEE 128-bit has more exponent range than IBM > > + 128-bit. */ > > And that results in some numbers being printed as Inf that are not. But > also, the significand has more bits, so there is a loss of precision as > well. Yes. > > +int __sprintfkf (char *restrict string, > > + const char *restrict format, > > + _Float128 number) > > +{ > > + if (__sprintfieee128) > > + return __sprintfieee128 (string, format, number); > > + > > + return sprintf (string, format, (long double)number); > > Space after cast. Fixed. > > +_Float128 > > +__strtokf (const char *string, char **endptr) > > +{ > > + long double num; > > + > > + if (__strtoieee128) > > + return __strtoieee128 (string, endptr); > > + > > + num = strtold (string, endptr); > > + return (_Float128) num; > > Do not cast return values please. All casts you do should be *needed*, > have a purpose. Well it is changing type (num is long double, i.e. IBM 128-bit long double) and the return is _Float128. > > + /* Use the sprintf library function to write the floating point value to > > a string. > Line too long. I missed this. I will do a second patch. > Okay for trunk with those fixes. Thanks! I'll attach the patch as committed. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797
>From 781183595acba67a37c66f59a0c1d9b5fee7e248 Mon Sep 17 00:00:00 2001 From: Michael Meissner <meiss...@linux.ibm.com> Date: Mon, 22 Feb 2021 15:33:29 -0500 Subject: [PATCH] Add conversions between _Float128 and Decimal. This patch implements conversions between _Float128 and the 3 Decimal floating types. It does this by extendending the dfp-bit conversions to add a new binary floating point type (KF), and doing the conversions in the same manner as the other binary/decimal conversions. For conversions from _Float128 to Decimal, this patch uses a function (__sprintfkf) instead of the sprintf function to convert long double values to strings. The __sprintfkf function determines if GLIBC 2.32 or newer is used and calls the IEEE 128-bit version of sprintf (__sprintfieee128). If the GLIBC is earlier than 2.32, the code will convert _Float128 to __ibm128 and then use the normal sprintf to convert this value. For conversions from Decimal to _Float128, this patch uses a function (__strtokf) instead of strtold to convert the strings from the Decimal conversion to long double. The __strtokf function determines if GLIBC 2.32 or newer is used, and if it is, calls the IEEE 128-bit version (__strtoieee128). If the GLIBC is earlier than 2.32, the code will call strtold and convert the __ibm128 value to _Float128. These functions will primarily be used if/when the default PowerPC long double type is changed to IEEE 128-bit, but they could also be used if the user explicitly converts _Float128 to/from a Decimal type. libgcc/ 2021-02-22 Michael Meissner <meiss...@linux.ibm.com> * config/rs6000/_dd_to_kf.c: New file. * config/rs6000/_kf_to_dd.c: New file. * config/rs6000/_kf_to_sd.c: New file. * config/rs6000/_kf_to_td.c: New file. * config/rs6000/_sd_to_kf.c: New file. * config/rs6000/_sprintfkf.c: New file. * config/rs6000/_sprintfkf.h: New file. * config/rs6000/_strtokf.h: New file. * config/rs6000/_strtokf.c: New file. * config/rs6000/_td_to_kf.c: New file. * config/rs6000/quad-float128.h: Add new declarations. * config/rs6000/t-float128 (fp128_dec_funcs): New macro. (fp128_decstr_funcs): New macro. (ibm128_dec_funcs): New macro. (fp128_ppc_funcs): Add the new conversions. (fp128_dec_objs): Force Decimal <-> __float128 conversions to be compiled with -mabi=ieeelongdouble. (fp128_decstr_objs): Force __float128 <-> string conversions to be compiled with -mabi=ibmlongdouble. (ibm128_dec_objs): Force Decimal <-> __float128 conversions to be compiled with -mabi=ieeelongdouble. (FP128_CFLAGS_DECIMAL): New macro. (IBM128_CFLAGS_DECIMAL): New macro. * dfp-bit.c (DFP_TO_BFP): Add PowerPC _Float128 support. (BFP_TO_DFP): Add PowerPC _Float128 support. * dfp-bit.h (BFP_KIND): Add new binary floating point kind for IEEE 128-bit floating point. (DFP_TO_BFP): Add PowerPC _Float128 support. (BFP_TO_DFP): Add PowerPC _Float128 support. (BFP_SPRINTF): New macro. --- libgcc/config/rs6000/_dd_to_kf.c | 37 ++++++++++++++++++ libgcc/config/rs6000/_kf_to_dd.c | 37 ++++++++++++++++++ libgcc/config/rs6000/_kf_to_sd.c | 37 ++++++++++++++++++ libgcc/config/rs6000/_kf_to_td.c | 37 ++++++++++++++++++ libgcc/config/rs6000/_sd_to_kf.c | 37 ++++++++++++++++++ libgcc/config/rs6000/_sprintfkf.c | 57 ++++++++++++++++++++++++++++ libgcc/config/rs6000/_sprintfkf.h | 28 ++++++++++++++ libgcc/config/rs6000/_strtokf.c | 53 ++++++++++++++++++++++++++ libgcc/config/rs6000/_strtokf.h | 27 +++++++++++++ libgcc/config/rs6000/_td_to_kf.c | 37 ++++++++++++++++++ libgcc/config/rs6000/quad-float128.h | 8 ++++ libgcc/config/rs6000/t-float128 | 37 +++++++++++++++++- libgcc/dfp-bit.c | 12 +++++- libgcc/dfp-bit.h | 26 +++++++++++++ 14 files changed, 467 insertions(+), 3 deletions(-) create mode 100644 libgcc/config/rs6000/_dd_to_kf.c create mode 100644 libgcc/config/rs6000/_kf_to_dd.c create mode 100644 libgcc/config/rs6000/_kf_to_sd.c create mode 100644 libgcc/config/rs6000/_kf_to_td.c create mode 100644 libgcc/config/rs6000/_sd_to_kf.c create mode 100644 libgcc/config/rs6000/_sprintfkf.c create mode 100644 libgcc/config/rs6000/_sprintfkf.h create mode 100644 libgcc/config/rs6000/_strtokf.c create mode 100644 libgcc/config/rs6000/_strtokf.h create mode 100644 libgcc/config/rs6000/_td_to_kf.c diff --git a/libgcc/config/rs6000/_dd_to_kf.c b/libgcc/config/rs6000/_dd_to_kf.c new file mode 100644 index 00000000000..6613c4483f8 --- /dev/null +++ b/libgcc/config/rs6000/_dd_to_kf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Decimal64 -> _Float128 conversion. */ + +/* FINE_GRAINED_LIBRARIES is used so we can isolate just to dd_to_tf conversion + function from dp-bits.c. */ +#define FINE_GRAINED_LIBRARIES 1 +#define L_dd_to_kf 1 +#define WIDTH 64 + +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IEEE128__) +#error "Long double is not IEEE 128-bit" +#endif + +/* Use dfp-bit.c to do the real work. */ +#include "dfp-bit.c" diff --git a/libgcc/config/rs6000/_kf_to_dd.c b/libgcc/config/rs6000/_kf_to_dd.c new file mode 100644 index 00000000000..93a10435e6f --- /dev/null +++ b/libgcc/config/rs6000/_kf_to_dd.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* _Float128 -> Decimal64 conversion. */ + +/* FINE_GRAINED_LIBRARIES is used so we can isolate just to tf_to_dd conversion + function from dp-bits.c. */ +#define FINE_GRAINED_LIBRARIES 1 +#define L_kf_to_dd 1 +#define WIDTH 64 + +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IEEE128__) +#error "Long double is not IEEE 128-bit" +#endif + +/* Use dfp-bit.c to do the real work. */ +#include "dfp-bit.c" diff --git a/libgcc/config/rs6000/_kf_to_sd.c b/libgcc/config/rs6000/_kf_to_sd.c new file mode 100644 index 00000000000..01396da814b --- /dev/null +++ b/libgcc/config/rs6000/_kf_to_sd.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* _Float128 -> Decimal32 conversion. */ + +/* FINE_GRAINED_LIBRARIES is used so we can isolate just to tf_to_sd conversion + function from dp-bits.c. */ +#define FINE_GRAINED_LIBRARIES 1 +#define L_kf_to_sd 1 +#define WIDTH 32 + +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IEEE128__) +#error "Long double is not IEEE 128-bit" +#endif + +/* Use dfp-bit.c to do the real work. */ +#include "dfp-bit.c" diff --git a/libgcc/config/rs6000/_kf_to_td.c b/libgcc/config/rs6000/_kf_to_td.c new file mode 100644 index 00000000000..45bba925f9a --- /dev/null +++ b/libgcc/config/rs6000/_kf_to_td.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* _Float128 -> Decimal128 conversion. */ + +/* FINE_GRAINED_LIBRARIES is used so we can isolate just to tf_to_td conversion + function from dp-bits.c. */ +#define FINE_GRAINED_LIBRARIES 1 +#define L_kf_to_td 1 +#define WIDTH 128 + +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IEEE128__) +#error "Long double is not IEEE 128-bit" +#endif + +/* Use dfp-bit.c to do the real work. */ +#include "dfp-bit.c" diff --git a/libgcc/config/rs6000/_sd_to_kf.c b/libgcc/config/rs6000/_sd_to_kf.c new file mode 100644 index 00000000000..92244442050 --- /dev/null +++ b/libgcc/config/rs6000/_sd_to_kf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Decimal32 -> _Float128 conversion. */ + +/* FINE_GRAINED_LIBRARIES is used so we can isolate just to sd_to_tf conversion + function from dp-bits.c. */ +#define FINE_GRAINED_LIBRARIES 1 +#define L_sd_to_kf 1 +#define WIDTH 32 + +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IEEE128__) +#error "Long double is not IEEE 128-bit" +#endif + +/* Use dfp-bit.c to do the real work. */ +#include "dfp-bit.c" diff --git a/libgcc/config/rs6000/_sprintfkf.c b/libgcc/config/rs6000/_sprintfkf.c new file mode 100644 index 00000000000..a7fdfb483c9 --- /dev/null +++ b/libgcc/config/rs6000/_sprintfkf.c @@ -0,0 +1,57 @@ +/* Copyright (C) 1989-2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Conversion to IEEE 128-bit floating point from string using snprintf. */ + +#include <stddef.h> +#include <stdlib.h> +#include <soft-fp.h> +#include <quad-float128.h> +#include <stdio.h> + +/* This function must be built with IBM 128-bit as long double, so that we can + access the strfroml function if do not have an IEEE 128-bit version, and if + that is not available, use sprintf. */ +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IBM128__) +#error "Long double is not IBM 128-bit" +#endif + +/* If the user is using GLIBC 2.32, we can use the __snprintfieee128 function. + + If we are linked against an earlier library, we will have fake it by + converting the value to long double, and using sprintf to do the conversion. + This isn't ideal, as IEEE 128-bit has more exponent range than IBM + 128-bit. */ + +extern int __sprintfieee128 (char *restrict, const char *restrict, ...) + __attribute__ ((__weak__)); + +int __sprintfkf (char *restrict string, + const char *restrict format, + _Float128 number) +{ + if (__sprintfieee128) + return __sprintfieee128 (string, format, number); + + return sprintf (string, format, (long double) number); +} diff --git a/libgcc/config/rs6000/_sprintfkf.h b/libgcc/config/rs6000/_sprintfkf.h new file mode 100644 index 00000000000..637d104c882 --- /dev/null +++ b/libgcc/config/rs6000/_sprintfkf.h @@ -0,0 +1,28 @@ +/* Copyright (C) 1989-2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Declaration of the conversion function to IEEE 128-bit floating point from + string using snprintf. */ + +extern int __sprintfkf (char *restrict, const char *restrict, ...); + diff --git a/libgcc/config/rs6000/_strtokf.c b/libgcc/config/rs6000/_strtokf.c new file mode 100644 index 00000000000..dc13534cdc2 --- /dev/null +++ b/libgcc/config/rs6000/_strtokf.c @@ -0,0 +1,53 @@ +/* Copyright (C) 1989-2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Conversion to IEEE 128-bit floating point from string. */ + +#include <stddef.h> +#include <stdlib.h> +#include <soft-fp.h> +#include <quad-float128.h> + +/* This function must be built with IBM 128-bit as long double, so that we can + access the strtold function if do not have an IEEE 128-bit version. */ +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IBM128__) +#error "Long double is not IBM 128-bit" +#endif + +/* If the user is using GLIBC 2.32, we can use the __strtoieee128 function. + + If we are linked against an earlier library, we will have fake it by + converting the string to IBM 128-bit long double, and then converting that to + __float128. This isn't ideal, as IEEE 128-bit has more exponent range than + IBM 128-bit. */ + +extern _Float128 __strtoieee128 (const char *, char **) __attribute__ ((__weak__)); + +_Float128 +__strtokf (const char *string, char **endptr) +{ + if (__strtoieee128) + return __strtoieee128 (string, endptr); + + return strtold (string, endptr); +} diff --git a/libgcc/config/rs6000/_strtokf.h b/libgcc/config/rs6000/_strtokf.h new file mode 100644 index 00000000000..a7ca8e09244 --- /dev/null +++ b/libgcc/config/rs6000/_strtokf.h @@ -0,0 +1,27 @@ +/* Copyright (C) 1989-2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Declaration of the conversion function to IEEE 128-bit floating point from + string. */ + +extern _Float128 __strtokf (const char *, char **); diff --git a/libgcc/config/rs6000/_td_to_kf.c b/libgcc/config/rs6000/_td_to_kf.c new file mode 100644 index 00000000000..0134581207f --- /dev/null +++ b/libgcc/config/rs6000/_td_to_kf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +/* Decimal128 -> _Float128 conversion. */ + +/* FINE_GRAINED_LIBRARIES is used so we can isolate just to td_to_tf conversion + function from dp-bits.c. */ +#define FINE_GRAINED_LIBRARIES 1 +#define L_td_to_kf 1 +#define WIDTH 128 + +#if !defined(__LONG_DOUBLE_128__) || !defined(__LONG_DOUBLE_IEEE128__) +#error "Long double is not IEEE 128-bit" +#endif + +/* Use dfp-bit.c to do the real work. */ +#include "dfp-bit.c" diff --git a/libgcc/config/rs6000/quad-float128.h b/libgcc/config/rs6000/quad-float128.h index 0eb1d34691f..5beb1531d2b 100644 --- a/libgcc/config/rs6000/quad-float128.h +++ b/libgcc/config/rs6000/quad-float128.h @@ -49,6 +49,7 @@ typedef __complex float TCtype __attribute__ ((mode (TC))); #pragma GCC target ("vsx,float128") #endif +#include <stddef.h> #include <quad.h> #define IBM128_TYPE __ibm128 @@ -171,6 +172,13 @@ extern TFtype __trunctfkf2 (IBM128_TYPE); extern TCtype __mulkc3 (TFtype, TFtype, TFtype, TFtype); extern TCtype __divkc3 (TFtype, TFtype, TFtype, TFtype); +/* Convert IEEE 128-bit floating point to/from string. We explicitly use + _Float128 instead of TFmode because _strtokf and _strfromkf must be compiled + with long double being IBM 128. */ +extern _Float128 __strtokf (const char *, char **); +extern int __strfromkf (char *restrict, size_t, const char *restrict, + _Float128); + /* Implementation of conversions between __ibm128 and __float128, to allow the same code to be used on systems with IEEE 128-bit emulation and with IEEE 128-bit hardware support. */ diff --git a/libgcc/config/rs6000/t-float128 b/libgcc/config/rs6000/t-float128 index d5413445189..6fb1a3d871b 100644 --- a/libgcc/config/rs6000/t-float128 +++ b/libgcc/config/rs6000/t-float128 @@ -22,10 +22,23 @@ fp128_softfp_static_obj = $(addsuffix -sw$(objext),$(fp128_softfp_funcs)) fp128_softfp_shared_obj = $(addsuffix -sw_s$(objext),$(fp128_softfp_funcs)) fp128_softfp_obj = $(fp128_softfp_static_obj) $(fp128_softfp_shared_obj) +# Decimal <-> _Float128 conversions +fp128_dec_funcs = _kf_to_sd _kf_to_dd _kf_to_td \ + _sd_to_kf _dd_to_kf _td_to_kf + +# _Float128 to/from string conversions that must be compiled with IBM 128-bit +# long double. +fp128_decstr_funcs = _strtokf _sprintfkf + +# Decimal <-> __ibm128 conversions +ibm128_dec_funcs = _tf_to_sd _tf_to_dd _tf_to_td \ + _sd_to_tf _dd_to_tf _td_to_tf + # New functions for software emulation fp128_ppc_funcs = floattikf floatuntikf fixkfti fixunskfti \ extendkftf2-sw trunctfkf2-sw \ - sfp-exceptions _mulkc3 _divkc3 _powikf2 + sfp-exceptions _mulkc3 _divkc3 _powikf2 \ + $(fp128_dec_funcs) $(fp128_decstr_funcs) fp128_ppc_src = $(addprefix $(srcdir)/config/rs6000/,$(addsuffix \ .c,$(fp128_ppc_funcs))) @@ -69,6 +82,28 @@ $(fp128_ppc_obj) : INTERNAL_CFLAGS += $(FP128_CFLAGS_SW) $(fp128_obj) : $(fp128_includes) $(fp128_obj) : $(srcdir)/config/rs6000/quad-float128.h +# Force the TF mode to/from decimal functions to be compiled with IBM long +# double. Add building the KF mode to/from decimal conversions with explict +# IEEE long double. +fp128_dec_objs = $(addsuffix $(objext),$(fp128_dec_funcs)) \ + $(addsuffix _s$(objext),$(fp128_dec_funcs)) + +fp128_decstr_objs = $(addsuffix $(objext),$(fp128_decstr_funcs)) \ + $(addsuffix _s$(objext),$(fp128_decstr_funcs)) + +ibm128_dec_objs = $(addsuffix $(objext),$(ibm128_dec_funcs)) \ + $(addsuffix _s$(objext),$(ibm128_dec_funcs)) + +FP128_CFLAGS_DECIMAL = -mno-gnu-attribute -Wno-psabi -mabi=ieeelongdouble +IBM128_CFLAGS_DECIMAL = -mno-gnu-attribute -Wno-psabi -mabi=ibmlongdouble + +$(fp128_dec_objs) : INTERNAL_CFLAGS += $(FP128_CFLAGS_DECIMAL) +$(fp128_decstr_objs) : INTERNAL_CFLAGS += $(IBM128_CFLAGS_DECIMAL) +$(ibm128_dec_objs) : INTERNAL_CFLAGS += $(IBM128_CFLAGS_DECIMAL) + +$(fp128_decstr_objs) : $(srcdir)/config/rs6000/_strtokf.h \ + $(srcdir)/config/rs6000/_sprintfkf.h \ + $(fp128_softfp_src) : $(srcdir)/soft-fp/$(subst -sw,,$(subst kf,tf,$@)) $(fp128_dep) @src="$(srcdir)/soft-fp/$(subst -sw,,$(subst kf,tf,$@))"; \ echo "Create $@"; \ diff --git a/libgcc/dfp-bit.c b/libgcc/dfp-bit.c index 17bca9cf203..0b0f9ace1fa 100644 --- a/libgcc/dfp-bit.c +++ b/libgcc/dfp-bit.c @@ -606,6 +606,7 @@ INT_TO_DFP (INT_TYPE i) #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \ + || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \ || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \ && LONG_DOUBLE_HAS_XF_MODE) \ || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \ @@ -626,6 +627,7 @@ DFP_TO_BFP (DFP_C_TYPE f) #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \ || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \ + || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) \ || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \ && LONG_DOUBLE_HAS_XF_MODE) \ || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \ @@ -641,8 +643,14 @@ BFP_TO_DFP (BFP_TYPE x) decContextDefault (&context, CONTEXT_INIT); DFP_INIT_ROUNDMODE (context.round); - /* Use a C library function to write the floating point value to a string. */ - sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x); + /* Use the sprintf library function to write the floating point value to a string. + + If we are handling the IEEE 128-bit floating point on PowerPC, use the + special function __sprintfkf instead of sprintf. This function allows us + to use __sprintfieee128 if we have a new enough GLIBC, and it can fall back + to using the traditional sprintf via conversion to IBM 128-bit if the glibc + is older. */ + BFP_SPRINTF (buf, BFP_FMT, (BFP_VIA_TYPE) x); /* Convert from the floating point string to a decimal* type. */ FROM_STRING (&s, buf, &context); diff --git a/libgcc/dfp-bit.h b/libgcc/dfp-bit.h index 1fa42ee621f..5e3bfa65ab8 100644 --- a/libgcc/dfp-bit.h +++ b/libgcc/dfp-bit.h @@ -241,6 +241,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #elif defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf) \ || defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td) #define BFP_KIND 4 +#elif defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \ + || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) +#define BFP_KIND 5 #endif /* If BFP_KIND is defined, define additional macros: @@ -291,6 +294,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define BFP_VIA_TYPE long double #endif /* LONG_DOUBLE_HAS_TF_MODE */ +#elif BFP_KIND == 5 +#define BFP_TYPE _Float128 +#define BFP_FMT "%.36Le" +#define BFP_VIA_TYPE _Float128 +#define STR_TO_BFP __strtokf +#include <_strtokf.h> + #endif /* BFP_KIND */ #if WIDTH == 128 || WIDTH_TO == 128 @@ -490,6 +500,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #elif BFP_KIND == 4 #define BFP_TO_DFP DPD_BID_NAME(__dpd_trunctfsd,__bid_trunctfsd) #define DFP_TO_BFP DPD_BID_NAME(__dpd_extendsdtf,__bid_extendsdtf) +#elif BFP_KIND == 5 +#define BFP_TO_DFP DPD_BID_NAME(__dpd_trunckfsd,__bid_trunckfsd) +#define DFP_TO_BFP DPD_BID_NAME(__dpd_extendsdkf,__bid_extendsdkf) #endif /* BFP_KIND */ #elif WIDTH == 64 @@ -505,6 +518,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #elif BFP_KIND == 4 #define BFP_TO_DFP DPD_BID_NAME(__dpd_trunctfdd,__bid_trunctfdd) #define DFP_TO_BFP DPD_BID_NAME(__dpd_extendddtf,__bid_extendddtf) +#elif BFP_KIND == 5 +#define BFP_TO_DFP DPD_BID_NAME(__dpd_trunckfdd,__bid_trunckfdd) +#define DFP_TO_BFP DPD_BID_NAME(__dpd_extendddkf,__bid_extendddkf) #endif /* BFP_KIND */ #elif WIDTH == 128 @@ -520,6 +536,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #elif BFP_KIND == 4 #define BFP_TO_DFP DPD_BID_NAME(__dpd_extendtftd,__bid_extendtftd) #define DFP_TO_BFP DPD_BID_NAME(__dpd_trunctdtf,__bid_trunctdtf) +#elif BFP_KIND == 5 +#define BFP_TO_DFP DPD_BID_NAME(__dpd_extendkftd,__bid_extendkftd) +#define DFP_TO_BFP DPD_BID_NAME(__dpd_trunctdkf,__bid_trunctdkf) #endif /* BFP_KIND */ #endif /* WIDTH */ @@ -609,6 +628,7 @@ extern DFP_C_TYPE INT_TO_DFP (INT_TYPE); #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \ + || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \ || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \ && LONG_DOUBLE_HAS_XF_MODE) \ || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \ @@ -623,6 +643,12 @@ extern BFP_TYPE DFP_TO_BFP (DFP_C_TYPE); || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \ && LONG_DOUBLE_HAS_TF_MODE) extern DFP_C_TYPE BFP_TO_DFP (BFP_TYPE); +#define BFP_SPRINTF sprintf + +#elif defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) +extern DFP_C_TYPE BFP_TO_DFP (BFP_TYPE); +#include <_sprintfkf.h> +#define BFP_SPRINTF __sprintfkf #endif #endif /* _DFPBIT_H */ -- 2.22.0