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

Reply via email to