diff mbox series

PowerPC: Add __float128 conversions to/from Decimal

Message ID 20201022220603.GA11658@ibm-toto.the-meissners.org
State New
Headers show
Series PowerPC: Add __float128 conversions to/from Decimal | expand

Commit Message

Michael Meissner Oct. 22, 2020, 10:06 p.m. UTC
PowerPC: Add __float128 conversions to/from Decimal.

I have split all of these patches into separate patches to hopefully get them
into the tree.

This patch adds the various decimal to/from IEEE 128-bit conversions.  I
had to make some changes to the infrastructure, since that infrastructure
assumed that there is a sprintf/scanf format modifier to convert floating
point.  Instead, I used to str* conversion functions.

I have tested this patch with bootstrap builds on a little endian power9 system
running Linux.  With the other patches, I have built two full bootstrap builds
using this patch and the patches after this patch.  One build used the current
default for long double (IBM extended double) and the other build switched the
default to IEEE 128-bit.  I used the Advance Toolchain AT 14.0 compiler as the
library used by this compiler.  There are no regressions between the tests.
There are 3 fortran benchmarks (ieee/large_2.f90, default_format_2.f90, and
default_format_denormal_2.f90) that now pass.

Can I install this into the trunk?

We have gotten some requests to back port these changes to GCC 10.x.  At the
moment, I am not planning to do the back port, but I may need to in the future.

libgcc/
2020-10-22  Michael Meissner  <meissner@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/_td_to_kf.c: New file.
	* config/rs6000/t-float128: Build __float128 conversions to and
	from Decimal support functions.
	* dfp-bit.c: Add support for building the PowerPC _Float128
	to/from Decimal conversion functions.
	* dfp-bit.h: Likewise.
---
 libgcc/config/rs6000/_dd_to_kf.c | 30 ++++++++++++++++++++++++++
 libgcc/config/rs6000/_kf_to_dd.c | 30 ++++++++++++++++++++++++++
 libgcc/config/rs6000/_kf_to_sd.c | 30 ++++++++++++++++++++++++++
 libgcc/config/rs6000/_kf_to_td.c | 30 ++++++++++++++++++++++++++
 libgcc/config/rs6000/_sd_to_kf.c | 30 ++++++++++++++++++++++++++
 libgcc/config/rs6000/_td_to_kf.c | 30 ++++++++++++++++++++++++++
 libgcc/config/rs6000/t-float128  | 20 ++++++++++++++++-
 libgcc/dfp-bit.c                 | 10 +++++++--
 libgcc/dfp-bit.h                 | 37 +++++++++++++++++++++++++++++---
 9 files changed, 241 insertions(+), 6 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/_td_to_kf.c

Comments

will schmidt Oct. 27, 2020, 2:53 p.m. UTC | #1
On Thu, 2020-10-22 at 18:06 -0400, Michael Meissner via Gcc-patches wrote:
> PowerPC: Add __float128 conversions to/from Decimal.
> 
> I have split all of these patches into separate patches to hopefully get them
> into the tree.
> 
> This patch adds the various decimal to/from IEEE 128-bit conversions.  I
> had to make some changes to the infrastructure, since that infrastructure
> assumed that there is a sprintf/scanf format modifier to convert floating
> point.  Instead, I used to str* conversion functions.
> 
> I have tested this patch with bootstrap builds on a little endian power9 system
> running Linux.  With the other patches, I have built two full bootstrap builds
> using this patch and the patches after this patch.  One build used the current
> default for long double (IBM extended double) and the other build switched the
> default to IEEE 128-bit.  I used the Advance Toolchain AT 14.0 compiler as the
> library used by this compiler.  There are no regressions between the tests.
> There are 3 fortran benchmarks (ieee/large_2.f90, default_format_2.f90, and
> default_format_denormal_2.f90) that now pass.
> 
> Can I install this into the trunk?
> 
> We have gotten some requests to back port these changes to GCC 10.x.  At the
> moment, I am not planning to do the back port, but I may need to in the future.
> 
> libgcc/
> 2020-10-22  Michael Meissner  <meissner@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/_td_to_kf.c: New file.
> 	* config/rs6000/t-float128: Build __float128 conversions to and
> 	from Decimal support functions.
ok

> 	* dfp-bit.c: Add support for building the PowerPC _Float128
> 	to/from Decimal conversion functions.
> 	* dfp-bit.h: Likewise.

These are non-arch, so attention to anyone who also needs to bless this
generically.  :-)


> ---
>  libgcc/config/rs6000/_dd_to_kf.c | 30 ++++++++++++++++++++++++++
>  libgcc/config/rs6000/_kf_to_dd.c | 30 ++++++++++++++++++++++++++
>  libgcc/config/rs6000/_kf_to_sd.c | 30 ++++++++++++++++++++++++++
>  libgcc/config/rs6000/_kf_to_td.c | 30 ++++++++++++++++++++++++++
>  libgcc/config/rs6000/_sd_to_kf.c | 30 ++++++++++++++++++++++++++
>  libgcc/config/rs6000/_td_to_kf.c | 30 ++++++++++++++++++++++++++
>  libgcc/config/rs6000/t-float128  | 20 ++++++++++++++++-
>  libgcc/dfp-bit.c                 | 10 +++++++--
>  libgcc/dfp-bit.h                 | 37 +++++++++++++++++++++++++++++---
>  9 files changed, 241 insertions(+), 6 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/_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..081415fd393
> --- /dev/null
> +++ b/libgcc/config/rs6000/_dd_to_kf.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 1989-2020 Free Software Foundation, Inc.

Should that (new file) have the 1989 start date (since it is presumably
based on an existing file), or start with 2020?
Same with the others here.

> +
> +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.  */
> +#define FINE_GRAINED_LIBRARIES	1
> +#define L_dd_to_kf		1
> +#define WIDTH			64
> +
> +/* 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..09a62cbe629
> --- /dev/null
> +++ b/libgcc/config/rs6000/_kf_to_dd.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 1989-2020 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.  */
> +#define FINE_GRAINED_LIBRARIES	1
> +#define L_kf_to_dd		1
> +#define WIDTH			64
> +
> +/* 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..f35b68eb4d9
> --- /dev/null
> +++ b/libgcc/config/rs6000/_kf_to_sd.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 1989-2020 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.  */
> +#define FINE_GRAINED_LIBRARIES	1
> +#define L_kf_to_sd		1
> +#define WIDTH			32
> +
> +/* 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..d35d09ed848
> --- /dev/null
> +++ b/libgcc/config/rs6000/_kf_to_td.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 1989-2020 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.  */
> +#define FINE_GRAINED_LIBRARIES	1
> +#define L_kf_to_td		1
> +#define WIDTH			128
> +
> +/* 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..9396b71f162
> --- /dev/null
> +++ b/libgcc/config/rs6000/_sd_to_kf.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 1989-2020 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.  */
> +#define FINE_GRAINED_LIBRARIES	1
> +#define L_sd_to_kf		1
> +#define WIDTH			32
> +
> +/* Use dfp-bit.c to do the real work.  */
> +#include "dfp-bit.c"
> diff --git a/libgcc/config/rs6000/_td_to_kf.c b/libgcc/config/rs6000/_td_to_kf.c
> new file mode 100644
> index 00000000000..fade2a28859
> --- /dev/null
> +++ b/libgcc/config/rs6000/_td_to_kf.c
> @@ -0,0 +1,30 @@
> +/* Copyright (C) 1989-2020 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.  */
> +#define FINE_GRAINED_LIBRARIES	1
> +#define L_td_to_kf		1
> +#define WIDTH			128
> +
> +/* Use dfp-bit.c to do the real work.  */
> +#include "dfp-bit.c"
> diff --git a/libgcc/config/rs6000/t-float128 b/libgcc/config/rs6000/t-float128
> index c2cb3e2b705..14a4df1bbf3 100644
> --- a/libgcc/config/rs6000/t-float128
> +++ b/libgcc/config/rs6000/t-float128
> @@ -22,10 +22,15 @@ 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
> +
>  # 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_ppc_src		= $(addprefix $(srcdir)/config/rs6000/,$(addsuffix \
>  				.c,$(fp128_ppc_funcs)))
> @@ -74,6 +79,19 @@ $(fp128_obj)		 : $(srcdir)/config/rs6000/quad-float128.h
>  # __ibm128 if long double uses the IEEE 128-bit representation.
>  ibm-ldouble$(objext)	: INTERNAL_CFLAGS += -mno-gnu-attribute
> 
> +# 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.
> +TF_DECIMAL_OBJS		= _dd_to_tf$(objext) _sd_to_tf$(objext) \
> +		          _td_to_tf$(objext) _tf_to_dd$(objext) \
> +			  _tf_to_sd$(objext) _tf_to_td$(objext)
> +
> +CFLAGS_TF_DECIMAL	= -mno-gnu-attribute -Wno-psabi -mabi=ibmlongdouble
> +CFLAGS_KF_DECIMAL	= -mno-gnu-attribute -Wno-psabi -mabi=ieeelongdouble
> +CFLAGS_KF_DECIMAL_SW	= $(CFLAGS_KF_DECIMAL) -mno-float128-hardware
> +
> +$(TF_DECIMAL_OBJS) : INTERNAL_CFLAGS += $(CFLAGS_TF_DECIMAL)
> +
>  $(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 935a1e340db..67212daa0bd 100644
> --- a/libgcc/dfp-bit.c
> +++ b/libgcc/dfp-bit.c
> @@ -609,7 +609,8 @@ INT_TO_DFP (INT_TYPE i)
>   || ((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)) \
> -     && LONG_DOUBLE_HAS_TF_MODE)
> +     && LONG_DOUBLE_HAS_TF_MODE) \
> +  || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf)
>  BFP_TYPE
>  DFP_TO_BFP (DFP_C_TYPE f)
>  {
> @@ -629,7 +630,8 @@ DFP_TO_BFP (DFP_C_TYPE f)
>   || ((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)) \
> -     && LONG_DOUBLE_HAS_TF_MODE)
> +     && LONG_DOUBLE_HAS_TF_MODE) \
> + || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td)
>  DFP_C_TYPE
>  BFP_TO_DFP (BFP_TYPE x)
>  {
> @@ -642,7 +644,11 @@ BFP_TO_DFP (BFP_TYPE x)
>    DFP_INIT_ROUNDMODE (context.round);
> 
>    /* Use a C library function to write the floating point value to a string.  */
> +#if HAVE_KF_MODE
> +  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
> +#else
>    sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
> +#endif
> 
>    /* 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 4215241da18..91fcdcdc7eb 100644
> --- a/libgcc/dfp-bit.h
> +++ b/libgcc/dfp-bit.h
> @@ -226,6 +226,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #define STR_TO_INT strtoull
>  #endif
> 
> +/* Support PowerPC KF mode, which is __float128 when long double is
> +   IBM extended double.  */
> +#if 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 HAVE_KF_MODE 1
> +#endif
> +
>  /* Conversions between decimal float types and binary float types use
>     BFP_KIND to determine the data type and C functions to use.  */
> 
> @@ -239,7 +246,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>   ||   defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)
>  #define BFP_KIND 3
>  #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)
> + ||   defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td) \
> + ||   defined (HAVE_KF_MODE)
>  #define BFP_KIND 4
>  #endif
> 
> @@ -277,6 +285,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #define STR_TO_BFP strtold
>  #endif /* LONG_DOUBLE_HAS_XF_MODE */
> 
> +#elif BFP_KIND == 4 && HAVE_KF_MODE
> +#define BFP_TYPE _Float128
> +#define BFP_FMT "%.36e"
> +#define STR_TO_BFP strtof128
> +#define BFP_VIA_TYPE _Float128
> +extern _Float128 strtof128 (const char *__restrict __nptr,
> +			    char **__restrict __endptr)
> +  __THROW __nonnull ((1));
> +extern int strfromf128 (char *__dest, size_t __size, const char * __format,
> +			_Float128 __f)
> +  __THROW __nonnull ((3));
> +
>  #elif BFP_KIND == 4
>  #if LONG_DOUBLE_HAS_TF_MODE
>  #define BFP_TYPE TFtype
> @@ -487,6 +507,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #elif BFP_KIND == 3
>  #define BFP_TO_DFP	DPD_BID_NAME(__dpd_truncxfsd,__bid_truncxfsd)
>  #define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendsdxf,__bid_extendsdxf)
> +#elif BFP_KIND == 4 && HAVE_KF_MODE
> +#define BFP_TO_DFP	DPD_BID_NAME(__dpd_trunckfsd,__bid_trunckfsd)
> +#define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendsdkf,__bid_extendsdkf)
>  #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)
> @@ -502,6 +525,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #elif BFP_KIND == 3
>  #define BFP_TO_DFP	DPD_BID_NAME(__dpd_truncxfdd,__bid_truncxfdd)
>  #define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendddxf,__bid_extendddxf)
> +#elif BFP_KIND == 4 && HAVE_KF_MODE
> +#define BFP_TO_DFP	DPD_BID_NAME(__dpd_trunckfdd,__bid_trunckfdd)
> +#define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendddkf,__bid_extendddkf)
>  #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)
> @@ -517,6 +543,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>  #elif BFP_KIND == 3
>  #define BFP_TO_DFP	DPD_BID_NAME(__dpd_extendxftd,__bid_extendxftd)
>  #define DFP_TO_BFP	DPD_BID_NAME(__dpd_trunctdxf,__bid_trunctdxf)
> +#elif BFP_KIND == 4 && HAVE_KF_MODE
> +#define BFP_TO_DFP	DPD_BID_NAME(__dpd_extendkftd,__bid_extendkftd)
> +#define DFP_TO_BFP	DPD_BID_NAME(__dpd_trunctdkf,__bid_trunctdkf)
>  #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)
> @@ -612,7 +641,8 @@ extern DFP_C_TYPE INT_TO_DFP (INT_TYPE);
>   || ((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)) \
> -     && LONG_DOUBLE_HAS_TF_MODE)
> +     && LONG_DOUBLE_HAS_TF_MODE) \
> + || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf)
>  extern BFP_TYPE DFP_TO_BFP (DFP_C_TYPE);
>  #endif
> 
> @@ -621,7 +651,8 @@ extern BFP_TYPE DFP_TO_BFP (DFP_C_TYPE);
>   || ((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)) \
> -     && LONG_DOUBLE_HAS_TF_MODE)
> +     && LONG_DOUBLE_HAS_TF_MODE) \
> + || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td)
>  extern DFP_C_TYPE BFP_TO_DFP (BFP_TYPE);
>  #endif
> 

ok
lgtm,
Thanks,
-Will

> -- 
> 2.22.0
> 
>
Segher Boessenkool Oct. 29, 2020, 12:04 a.m. UTC | #2
On Thu, Oct 22, 2020 at 06:06:03PM -0400, Michael Meissner wrote:
> This patch adds the various decimal to/from IEEE 128-bit conversions.  I
> had to make some changes to the infrastructure, since that infrastructure
> assumed that there is a sprintf/scanf format modifier to convert floating
> point.  Instead, I used to str* conversion functions.

> --- /dev/null
> +++ b/libgcc/config/rs6000/_dd_to_kf.c

> +/* Decimal64 -> _Float128 conversion.  */
> +#define FINE_GRAINED_LIBRARIES	1

This isn't defined in any other source file (instead, it is put in the
Makefile).  Why should it be different here?

> +# 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

(typo, "explicit")

> +#if HAVE_KF_MODE
> +  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
> +#else
>    sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
> +#endif

Does strfromf128 exist everywhere we build this?  It isn't a standard
function.

> +/* Support PowerPC KF mode, which is __float128 when long double is
> +   IBM extended double.  */
> +#if 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 HAVE_KF_MODE 1
> +#endif

This might want a better name, other targets can have a KFmode as well,
for some completely different purpose, since it is not a standard mode.

(Some libgcc maintainer needs to approve the generic parts, not all of
it can obviously only trigger for us.)


Segher
Michael Meissner Oct. 29, 2020, 4:45 p.m. UTC | #3
On Wed, Oct 28, 2020 at 07:04:31PM -0500, Segher Boessenkool wrote:
> On Thu, Oct 22, 2020 at 06:06:03PM -0400, Michael Meissner wrote:
> > This patch adds the various decimal to/from IEEE 128-bit conversions.  I
> > had to make some changes to the infrastructure, since that infrastructure
> > assumed that there is a sprintf/scanf format modifier to convert floating
> > point.  Instead, I used to str* conversion functions.
> 
> > --- /dev/null
> > +++ b/libgcc/config/rs6000/_dd_to_kf.c
> 
> > +/* Decimal64 -> _Float128 conversion.  */
> > +#define FINE_GRAINED_LIBRARIES	1
> 
> This isn't defined in any other source file (instead, it is put in the
> Makefile).  Why should it be different here?

I'll check it out.

> > +# 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
> 
> (typo, "explicit")
> 
> > +#if HAVE_KF_MODE
> > +  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
> > +#else
> >    sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
> > +#endif
> 
> Does strfromf128 exist everywhere we build this?  It isn't a standard
> function.

Yes, it is in ISO/IEC TS 18661-3, which is the document that describes most of
the *f128 functions.

We have to use str* instead of sprintf or scanf, because I don't believe their
is a float128 format specifier.

> > +/* Support PowerPC KF mode, which is __float128 when long double is
> > +   IBM extended double.  */
> > +#if 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 HAVE_KF_MODE 1
> > +#endif
> 
> This might want a better name, other targets can have a KFmode as well,
> for some completely different purpose, since it is not a standard mode.

Given everything else uses *F, including XF on the x86, I figured it was easier
than creating a new name.

> (Some libgcc maintainer needs to approve the generic parts, not all of
> it can obviously only trigger for us.)
> 
> 
> Segher
Segher Boessenkool Oct. 29, 2020, 6:10 p.m. UTC | #4
Hi!

On Thu, Oct 29, 2020 at 12:45:15PM -0400, Michael Meissner wrote:
> On Wed, Oct 28, 2020 at 07:04:31PM -0500, Segher Boessenkool wrote:
> > > +#if HAVE_KF_MODE
> > > +  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
> > > +#else
> > >    sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
> > > +#endif
> > 
> > Does strfromf128 exist everywhere we build this?  It isn't a standard
> > function.
> 
> Yes, it is in ISO/IEC TS 18661-3, which is the document that describes most of
> the *f128 functions.

But this means it does *not* exist most places we build this?  Not the
whole world is Linux (and even then, it is probably a too recent
addition).

Does it need something in libibiberty maybe?  At least _doprnt handles
long double (whatever type it uses for that, but that can be fixed :-) )
(_doprint is used by all the libiberty versions of the printf family,
and it handles %lf etc. for long double.)

> We have to use str* instead of sprintf or scanf, because I don't believe their
> is a float128 format specifier.

No standard one at least, yes.

> > > +/* Support PowerPC KF mode, which is __float128 when long double is
> > > +   IBM extended double.  */
> > > +#if 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 HAVE_KF_MODE 1
> > > +#endif
> > 
> > This might want a better name, other targets can have a KFmode as well,
> > for some completely different purpose, since it is not a standard mode.
> 
> Given everything else uses *F, including XF on the x86, I figured it was easier
> than creating a new name.

I mean the name for the macro.  "HAVE_KF_MODE" is not great.

Anyway, some libgcc maintainer needs to review this, you may be lucky
with this ;-)


Segher
Joseph Myers Oct. 29, 2020, 6:31 p.m. UTC | #5
On Thu, 29 Oct 2020, Segher Boessenkool wrote:

> Hi!
> 
> On Thu, Oct 29, 2020 at 12:45:15PM -0400, Michael Meissner wrote:
> > On Wed, Oct 28, 2020 at 07:04:31PM -0500, Segher Boessenkool wrote:
> > > > +#if HAVE_KF_MODE
> > > > +  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
> > > > +#else
> > > >    sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
> > > > +#endif
> > > 
> > > Does strfromf128 exist everywhere we build this?  It isn't a standard
> > > function.
> > 
> > Yes, it is in ISO/IEC TS 18661-3, which is the document that describes most of
> > the *f128 functions.
> 
> But this means it does *not* exist most places we build this?  Not the
> whole world is Linux (and even then, it is probably a too recent
> addition).

strfromf128 and strtof128 were added for powerpc64le-linux-gnu in glibc 
2.26.  (The variants that are namespace-clean in the absence of 18661-3, 
which may be relevant when being used for long double, __strfromieee128 
and __strtoieee128, were added in 2.32.)

Doing these conversions accurately is nontrivial.  Converting via strings 
is the simple approach (i.e. the one that moves the complexity somewhere 
else).  There are more complicated but more efficient approaches that can 
achieve correct conversions with smaller bounds on resource usage (and 
there are various papers published in this area), but those involve a lot 
more code (and precomputed data, with a speed/space trade-off in how much 
you precompute; the BID code in libgcc has several MB of precomputed data 
for that purpose).
Segher Boessenkool Oct. 29, 2020, 7:40 p.m. UTC | #6
On Thu, Oct 29, 2020 at 06:31:54PM +0000, Joseph Myers wrote:
> On Thu, 29 Oct 2020, Segher Boessenkool wrote:
> > On Thu, Oct 29, 2020 at 12:45:15PM -0400, Michael Meissner wrote:
> > > On Wed, Oct 28, 2020 at 07:04:31PM -0500, Segher Boessenkool wrote:
> > > > > +#if HAVE_KF_MODE
> > > > > +  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
> > > > > +#else
> > > > >    sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
> > > > > +#endif
> > > > 
> > > > Does strfromf128 exist everywhere we build this?  It isn't a standard
> > > > function.
> > > 
> > > Yes, it is in ISO/IEC TS 18661-3, which is the document that describes most of
> > > the *f128 functions.
> > 
> > But this means it does *not* exist most places we build this?  Not the
> > whole world is Linux (and even then, it is probably a too recent
> > addition).
> 
> strfromf128 and strtof128 were added for powerpc64le-linux-gnu in glibc 
> 2.26.  (The variants that are namespace-clean in the absence of 18661-3, 
> which may be relevant when being used for long double, __strfromieee128 
> and __strtoieee128, were added in 2.32.)

And we otherwise support at least glibc 2.17 still (that is what RHEL 7
has).

> Doing these conversions accurately is nontrivial.  Converting via strings 
> is the simple approach (i.e. the one that moves the complexity somewhere 
> else).  There are more complicated but more efficient approaches that can 
> achieve correct conversions with smaller bounds on resource usage (and 
> there are various papers published in this area), but those involve a lot 
> more code (and precomputed data, with a speed/space trade-off in how much 
> you precompute; the BID code in libgcc has several MB of precomputed data 
> for that purpose).

Does the printf code in libgcc handle things correctly for IEEE QP float
as long double, do you know?


Segher
Joseph Myers Oct. 29, 2020, 10:05 p.m. UTC | #7
On Thu, 29 Oct 2020, Segher Boessenkool wrote:

> > Doing these conversions accurately is nontrivial.  Converting via strings 
> > is the simple approach (i.e. the one that moves the complexity somewhere 
> > else).  There are more complicated but more efficient approaches that can 
> > achieve correct conversions with smaller bounds on resource usage (and 
> > there are various papers published in this area), but those involve a lot 
> > more code (and precomputed data, with a speed/space trade-off in how much 
> > you precompute; the BID code in libgcc has several MB of precomputed data 
> > for that purpose).
> 
> Does the printf code in libgcc handle things correctly for IEEE QP float
> as long double, do you know?

As far as I know, the code in libgcc for conversions *from* decimal *to* 
binary (so the direction that uses strtof128 as opposed to the one using 
strfrom128, in the binary128 case) works correctly, if the underlying libc 
has accurate string/numeric conversion operations.

Binary to decimal is another matter, even for cases such as float to 
_Decimal64.  I've just filed bug 97635 for that.

Also note that if you want to use printf as opposed to strfromf128 for 
IEEE binary128 you'll need to use __printfieee128 (the version that 
expects long double to be IEEE binary128) which was introduced in glibc 
2.32, so that doesn't help with the glibc version dependencies.

When I investigated and reported several bugs in the conversion operations 
in libdfp, I noted (e.g. https://github.com/libdfp/libdfp/issues/29 ) that 
the libgcc versions were working correctly for those tests (and filed and 
subsequently fixed one glibc strtod bug, missing inexact exceptions, that 
I'd noticed while looking at such issues in libdfp).  But the specific 
case I tested for badly rounded conversions was the case of conversions 
from decimal to binary, not the case of conversions from binary to 
decimal, which, as noted above, turn out to be buggy in libgcc.

Lots of bugs have been fixed in the glibc conversion code over the years 
(more on the strtod side than in the code shared by printf and strfrom 
functions).  That code uses multiple-precision operations from GMP, which 
avoids some complications but introduces others (it also needs to e.g. 
deal with locale issues, which are irrelevant for libgcc conversions).
Segher Boessenkool Nov. 2, 2020, 11:42 p.m. UTC | #8
Hi Joseph,

On Thu, Oct 29, 2020 at 10:05:38PM +0000, Joseph Myers wrote:
> On Thu, 29 Oct 2020, Segher Boessenkool wrote:
> > > Doing these conversions accurately is nontrivial.  Converting via strings 
> > > is the simple approach (i.e. the one that moves the complexity somewhere 
> > > else).  There are more complicated but more efficient approaches that can 
> > > achieve correct conversions with smaller bounds on resource usage (and 
> > > there are various papers published in this area), but those involve a lot 
> > > more code (and precomputed data, with a speed/space trade-off in how much 
> > > you precompute; the BID code in libgcc has several MB of precomputed data 
> > > for that purpose).
> > 
> > Does the printf code in libgcc handle things correctly for IEEE QP float
> > as long double, do you know?
> 
> As far as I know, the code in libgcc for conversions *from* decimal *to* 
> binary (so the direction that uses strtof128 as opposed to the one using 
> strfrom128, in the binary128 case) works correctly, if the underlying libc 
> has accurate string/numeric conversion operations.
> 
> Binary to decimal is another matter, even for cases such as float to 
> _Decimal64.  I've just filed bug 97635 for that.
> 
> Also note that if you want to use printf as opposed to strfromf128 for 
> IEEE binary128 you'll need to use __printfieee128 (the version that 
> expects long double to be IEEE binary128) which was introduced in glibc 
> 2.32, so that doesn't help with the glibc version dependencies.

libiberty has printf functions of its own, I was wondering if those work
fine; if they do, that would solve all problems here.

> When I investigated and reported several bugs in the conversion operations 
> in libdfp, I noted (e.g. https://github.com/libdfp/libdfp/issues/29 ) that 
> the libgcc versions were working correctly for those tests (and filed and 
> subsequently fixed one glibc strtod bug, missing inexact exceptions, that 
> I'd noticed while looking at such issues in libdfp).  But the specific 
> case I tested for badly rounded conversions was the case of conversions 
> from decimal to binary, not the case of conversions from binary to 
> decimal, which, as noted above, turn out to be buggy in libgcc.

Yeah :-(

> Lots of bugs have been fixed in the glibc conversion code over the years 
> (more on the strtod side than in the code shared by printf and strfrom 
> functions).  That code uses multiple-precision operations from GMP, which 
> avoids some complications but introduces others (it also needs to e.g. 
> deal with locale issues, which are irrelevant for libgcc conversions).

Thanks for the info,


Segher
Joseph Myers Nov. 3, 2020, 1:12 a.m. UTC | #9
On Mon, 2 Nov 2020, Segher Boessenkool wrote:

> > Also note that if you want to use printf as opposed to strfromf128 for 
> > IEEE binary128 you'll need to use __printfieee128 (the version that 
> > expects long double to be IEEE binary128) which was introduced in glibc 
> > 2.32, so that doesn't help with the glibc version dependencies.
> 
> libiberty has printf functions of its own, I was wondering if those work
> fine; if they do, that would solve all problems here.

I don't see any meaningful kind of printf implementation in libiberty.  
There are implementations of various printf functions in terms of other 
printf functions (including vprintf in terms of vfprintf in terms of 
_doprnt in terms of fprintf), but nothing that actually does the main work 
of converting a floating-point value to a string without calling out to 
some libc printf function.
Segher Boessenkool Nov. 3, 2020, 2:33 p.m. UTC | #10
On Tue, Nov 03, 2020 at 01:12:29AM +0000, Joseph Myers wrote:
> On Mon, 2 Nov 2020, Segher Boessenkool wrote:
> 
> > > Also note that if you want to use printf as opposed to strfromf128 for 
> > > IEEE binary128 you'll need to use __printfieee128 (the version that 
> > > expects long double to be IEEE binary128) which was introduced in glibc 
> > > 2.32, so that doesn't help with the glibc version dependencies.
> > 
> > libiberty has printf functions of its own, I was wondering if those work
> > fine; if they do, that would solve all problems here.
> 
> I don't see any meaningful kind of printf implementation in libiberty.  
> There are implementations of various printf functions in terms of other 
> printf functions (including vprintf in terms of vfprintf in terms of 
> _doprnt in terms of fprintf), but nothing that actually does the main work 
> of converting a floating-point value to a string without calling out to 
> some libc printf function.

I missed that "in terms of fprintf" step :-(

Well, rats.  Thanks for telling me about my stupidity!  :-)


Segher
Michael Meissner Nov. 12, 2020, 9:42 p.m. UTC | #11
On Thu, Oct 29, 2020 at 10:05:38PM +0000, Joseph Myers wrote:
> On Thu, 29 Oct 2020, Segher Boessenkool wrote:
> 
> > > Doing these conversions accurately is nontrivial.  Converting via strings 
> > > is the simple approach (i.e. the one that moves the complexity somewhere 
> > > else).  There are more complicated but more efficient approaches that can 
> > > achieve correct conversions with smaller bounds on resource usage (and 
> > > there are various papers published in this area), but those involve a lot 
> > > more code (and precomputed data, with a speed/space trade-off in how much 
> > > you precompute; the BID code in libgcc has several MB of precomputed data 
> > > for that purpose).
> > 
> > Does the printf code in libgcc handle things correctly for IEEE QP float
> > as long double, do you know?
> 
> As far as I know, the code in libgcc for conversions *from* decimal *to* 
> binary (so the direction that uses strtof128 as opposed to the one using 
> strfrom128, in the binary128 case) works correctly, if the underlying libc 
> has accurate string/numeric conversion operations.
> 
> Binary to decimal is another matter, even for cases such as float to 
> _Decimal64.  I've just filed bug 97635 for that.
> 
> Also note that if you want to use printf as opposed to strfromf128 for 
> IEEE binary128 you'll need to use __printfieee128 (the version that 
> expects long double to be IEEE binary128) which was introduced in glibc 
> 2.32, so that doesn't help with the glibc version dependencies.

My latest patches now switches to using the GLIBC 2.32 and __sprintfieee128.
If we don't have glibc 2.32, it just calls abort, so we don't get linker
errors.  I hope to submit it tonight or tomorrow night.

> When I investigated and reported several bugs in the conversion operations 
> in libdfp, I noted (e.g. https://github.com/libdfp/libdfp/issues/29 ) that 
> the libgcc versions were working correctly for those tests (and filed and 
> subsequently fixed one glibc strtod bug, missing inexact exceptions, that 
> I'd noticed while looking at such issues in libdfp).  But the specific 
> case I tested for badly rounded conversions was the case of conversions 
> from decimal to binary, not the case of conversions from binary to 
> decimal, which, as noted above, turn out to be buggy in libgcc.
> 
> Lots of bugs have been fixed in the glibc conversion code over the years 
> (more on the strtod side than in the code shared by printf and strfrom 
> functions).  That code uses multiple-precision operations from GMP, which 
> avoids some complications but introduces others (it also needs to e.g. 
> deal with locale issues, which are irrelevant for libgcc conversions).

Using the sprintf method, I see an error in

c-c++-common/dfp/convert-bfp-11.c

that I didn't see with the method used in the patches with strtof128 and
strfromf128 directly.  I need to track down exactly what the error is.

All of the other dfp conversion tests work fine.
diff mbox series

Patch

diff --git a/libgcc/config/rs6000/_dd_to_kf.c b/libgcc/config/rs6000/_dd_to_kf.c
new file mode 100644
index 00000000000..081415fd393
--- /dev/null
+++ b/libgcc/config/rs6000/_dd_to_kf.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 1989-2020 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.  */
+#define FINE_GRAINED_LIBRARIES	1
+#define L_dd_to_kf		1
+#define WIDTH			64
+
+/* 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..09a62cbe629
--- /dev/null
+++ b/libgcc/config/rs6000/_kf_to_dd.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 1989-2020 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.  */
+#define FINE_GRAINED_LIBRARIES	1
+#define L_kf_to_dd		1
+#define WIDTH			64
+
+/* 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..f35b68eb4d9
--- /dev/null
+++ b/libgcc/config/rs6000/_kf_to_sd.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 1989-2020 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.  */
+#define FINE_GRAINED_LIBRARIES	1
+#define L_kf_to_sd		1
+#define WIDTH			32
+
+/* 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..d35d09ed848
--- /dev/null
+++ b/libgcc/config/rs6000/_kf_to_td.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 1989-2020 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.  */
+#define FINE_GRAINED_LIBRARIES	1
+#define L_kf_to_td		1
+#define WIDTH			128
+
+/* 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..9396b71f162
--- /dev/null
+++ b/libgcc/config/rs6000/_sd_to_kf.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 1989-2020 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.  */
+#define FINE_GRAINED_LIBRARIES	1
+#define L_sd_to_kf		1
+#define WIDTH			32
+
+/* Use dfp-bit.c to do the real work.  */
+#include "dfp-bit.c"
diff --git a/libgcc/config/rs6000/_td_to_kf.c b/libgcc/config/rs6000/_td_to_kf.c
new file mode 100644
index 00000000000..fade2a28859
--- /dev/null
+++ b/libgcc/config/rs6000/_td_to_kf.c
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 1989-2020 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.  */
+#define FINE_GRAINED_LIBRARIES	1
+#define L_td_to_kf		1
+#define WIDTH			128
+
+/* Use dfp-bit.c to do the real work.  */
+#include "dfp-bit.c"
diff --git a/libgcc/config/rs6000/t-float128 b/libgcc/config/rs6000/t-float128
index c2cb3e2b705..14a4df1bbf3 100644
--- a/libgcc/config/rs6000/t-float128
+++ b/libgcc/config/rs6000/t-float128
@@ -22,10 +22,15 @@  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
+
 # 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_ppc_src		= $(addprefix $(srcdir)/config/rs6000/,$(addsuffix \
 				.c,$(fp128_ppc_funcs)))
@@ -74,6 +79,19 @@  $(fp128_obj)		 : $(srcdir)/config/rs6000/quad-float128.h
 # __ibm128 if long double uses the IEEE 128-bit representation.
 ibm-ldouble$(objext)	: INTERNAL_CFLAGS += -mno-gnu-attribute
 
+# 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.
+TF_DECIMAL_OBJS		= _dd_to_tf$(objext) _sd_to_tf$(objext) \
+		          _td_to_tf$(objext) _tf_to_dd$(objext) \
+			  _tf_to_sd$(objext) _tf_to_td$(objext)
+
+CFLAGS_TF_DECIMAL	= -mno-gnu-attribute -Wno-psabi -mabi=ibmlongdouble
+CFLAGS_KF_DECIMAL	= -mno-gnu-attribute -Wno-psabi -mabi=ieeelongdouble
+CFLAGS_KF_DECIMAL_SW	= $(CFLAGS_KF_DECIMAL) -mno-float128-hardware
+
+$(TF_DECIMAL_OBJS) : INTERNAL_CFLAGS += $(CFLAGS_TF_DECIMAL)
+
 $(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 935a1e340db..67212daa0bd 100644
--- a/libgcc/dfp-bit.c
+++ b/libgcc/dfp-bit.c
@@ -609,7 +609,8 @@  INT_TO_DFP (INT_TYPE i)
  || ((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)) \
-     && LONG_DOUBLE_HAS_TF_MODE)
+     && LONG_DOUBLE_HAS_TF_MODE) \
+  || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf)
 BFP_TYPE
 DFP_TO_BFP (DFP_C_TYPE f)
 {
@@ -629,7 +630,8 @@  DFP_TO_BFP (DFP_C_TYPE f)
  || ((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)) \
-     && LONG_DOUBLE_HAS_TF_MODE)
+     && LONG_DOUBLE_HAS_TF_MODE) \
+ || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td)
 DFP_C_TYPE
 BFP_TO_DFP (BFP_TYPE x)
 {
@@ -642,7 +644,11 @@  BFP_TO_DFP (BFP_TYPE x)
   DFP_INIT_ROUNDMODE (context.round);
 
   /* Use a C library function to write the floating point value to a string.  */
+#if HAVE_KF_MODE
+  strfromf128 (buf, BUFMAX, BFP_FMT, (BFP_VIA_TYPE) x);
+#else
   sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
+#endif
 
   /* 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 4215241da18..91fcdcdc7eb 100644
--- a/libgcc/dfp-bit.h
+++ b/libgcc/dfp-bit.h
@@ -226,6 +226,13 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define STR_TO_INT strtoull
 #endif
 
+/* Support PowerPC KF mode, which is __float128 when long double is
+   IBM extended double.  */
+#if 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 HAVE_KF_MODE 1
+#endif
+
 /* Conversions between decimal float types and binary float types use
    BFP_KIND to determine the data type and C functions to use.  */
 
@@ -239,7 +246,8 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
  ||   defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)
 #define BFP_KIND 3
 #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)
+ ||   defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td) \
+ ||   defined (HAVE_KF_MODE)
 #define BFP_KIND 4
 #endif
 
@@ -277,6 +285,18 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define STR_TO_BFP strtold
 #endif /* LONG_DOUBLE_HAS_XF_MODE */
 
+#elif BFP_KIND == 4 && HAVE_KF_MODE
+#define BFP_TYPE _Float128
+#define BFP_FMT "%.36e"
+#define STR_TO_BFP strtof128
+#define BFP_VIA_TYPE _Float128
+extern _Float128 strtof128 (const char *__restrict __nptr,
+			    char **__restrict __endptr)
+  __THROW __nonnull ((1));
+extern int strfromf128 (char *__dest, size_t __size, const char * __format,
+			_Float128 __f)
+  __THROW __nonnull ((3));
+
 #elif BFP_KIND == 4
 #if LONG_DOUBLE_HAS_TF_MODE
 #define BFP_TYPE TFtype
@@ -487,6 +507,9 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #elif BFP_KIND == 3
 #define BFP_TO_DFP	DPD_BID_NAME(__dpd_truncxfsd,__bid_truncxfsd)
 #define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendsdxf,__bid_extendsdxf)
+#elif BFP_KIND == 4 && HAVE_KF_MODE
+#define BFP_TO_DFP	DPD_BID_NAME(__dpd_trunckfsd,__bid_trunckfsd)
+#define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendsdkf,__bid_extendsdkf)
 #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)
@@ -502,6 +525,9 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #elif BFP_KIND == 3
 #define BFP_TO_DFP	DPD_BID_NAME(__dpd_truncxfdd,__bid_truncxfdd)
 #define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendddxf,__bid_extendddxf)
+#elif BFP_KIND == 4 && HAVE_KF_MODE
+#define BFP_TO_DFP	DPD_BID_NAME(__dpd_trunckfdd,__bid_trunckfdd)
+#define DFP_TO_BFP	DPD_BID_NAME(__dpd_extendddkf,__bid_extendddkf)
 #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)
@@ -517,6 +543,9 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #elif BFP_KIND == 3
 #define BFP_TO_DFP	DPD_BID_NAME(__dpd_extendxftd,__bid_extendxftd)
 #define DFP_TO_BFP	DPD_BID_NAME(__dpd_trunctdxf,__bid_trunctdxf)
+#elif BFP_KIND == 4 && HAVE_KF_MODE
+#define BFP_TO_DFP	DPD_BID_NAME(__dpd_extendkftd,__bid_extendkftd)
+#define DFP_TO_BFP	DPD_BID_NAME(__dpd_trunctdkf,__bid_trunctdkf)
 #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)
@@ -612,7 +641,8 @@  extern DFP_C_TYPE INT_TO_DFP (INT_TYPE);
  || ((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)) \
-     && LONG_DOUBLE_HAS_TF_MODE)
+     && LONG_DOUBLE_HAS_TF_MODE) \
+ || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf)
 extern BFP_TYPE DFP_TO_BFP (DFP_C_TYPE);
 #endif
 
@@ -621,7 +651,8 @@  extern BFP_TYPE DFP_TO_BFP (DFP_C_TYPE);
  || ((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)) \
-     && LONG_DOUBLE_HAS_TF_MODE)
+     && LONG_DOUBLE_HAS_TF_MODE) \
+ || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td)
 extern DFP_C_TYPE BFP_TO_DFP (BFP_TYPE);
 #endif