Make __ibm128 a distinct type, patch 1 of 2 (PR 85657)

Message ID 20180518222231.GA15644@ibm-toto.the-meissners.org
State New
Headers show
Series
  • Make __ibm128 a distinct type, patch 1 of 2 (PR 85657)
Related show

Commit Message

Michael Meissner May 18, 2018, 10:22 p.m.
This patch is the first of two patches to make the __ibm128 type a distict
type.  Previously, when I impemented __ibm128, I had defined it to be long
double on systems where long double used the IBM extended double format.
Segher asked that I always create the type as a distinct type.  For C++, I have
chosen to use u8__ibm128 as the mangling for __ibm128.

I discovered in writing this patch, I needed to tweak the table of the
conversion functions, and I had to converting types that have different modes,
but have the same representation.

The second patch will add new unpack/pack builtin functions for __ibm128.  That
patch will also give an error if the long double default is changed, and the
user uses the pack/unpack long double functions.

I have done bootstrap tests on a little endian power8 system, and verified that
there were no regressions.  I also verified that the new tests run correctly.
I also have looked at the code for -mabi=ieeelongdouble, to verify that it is
still working when the default for long double is changed.

Can I install this in the GCC 9 trunk?  This will need to be back ported to GCC
8.2.

[gcc]
2018-05-18  Michael Meissner  <meissner@linux.ibm.com>

	PR target/85657
	* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Do not
	define __ibm128 as long double.
	* config/rs6000/rs6000.c (rs6000_init_builtins): Always create
	__ibm128 as a distinct type.
	(init_float128_ieee): Fix up conversions between IFmode and IEEE
	128-bit types to use the correct functions.
	(rs6000_expand_float128_convert): Use explicit FLOAT_EXTEND to
	convert between 128-bit floating point types that have different
	modes but the same representation, instead of using gen_lowpart to
	makean alias.
	* config/rs6000/rs6000.md (IFKF): New iterator for IFmode and
	KFmode.
	(IFKF_reg): New attributes to give the register constraints for
	IFmode and KFmode.
	(extend<mode>tf2_internal): New insns to mark an explicit
	conversion between 128-bit floating point types that have a
	different mode but share the same representation.

[gcc/testsuite]
2018-05-18  Michael Meissner  <meissner@linux.ibm.com>

	PR target/85657
	* gcc.target/powerpc/pr85657-1.c: New test for converting between
	__float128, __ibm128, and long double.
	* gcc.target/powerpc/pr85657-2.c: Likewise.
	* gcc.target/powerpc/pr85657-3.c: Likewise.
	* g++.dg/pr85667.C: New test to make sure __ibm128 is
	implementated as a separate type internally, and is not just an
	alias for long double.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meissner@linux.ibm.com, phone: +1 (978) 899-4797

Comments

Michael Meissner May 18, 2018, 11:27 p.m. | #1
Here is patch 2 of 2 to make __ibm128 a distinct type.  This patch makes the
long double pack and unpack builtins only work if the long double type is IBM
extended double.  It adds two new builtins to pack and unpack __ibm128 types.

This has been tested on a little endian power8 system with bootstrap and
regression test (with the previous patch also applied).  Can I check this into
the trunk and the GCC 8 branch?

[gcc]
2018-05-18  Michael Meissner  <meissner@linux.ibm.com>

	PR target/85657
	* config/rs6000/rs6000-builtin.def (BU_IBM128_2): New helper macro
	for __builtin_{,un}pack_ibm128.
	(PACK_IF): Declare __builtin_{,un}pack_ibm128.
	(UNPACK_IF): Likewise.
	* config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): The mask
	for long double builtins (RS6000_BTM_LDBL128) requires that long
	double is IBM extended double.
	(rs6000_invalid_builtin): Add a new error message if the long
	double {,un}pack builtins are used when long double is IEEE
	128-bit floating point.
	* config/rs6000/rs6000.h (RS6000_BTM_LDBL128): Update comment.
	* doc/extend.texi (PowerPC builtins): Update documention for
	__builtin_{,un}pack_longdouble.  Add documentation for
	__builtin_{,un}pack_ibm128.

[gcc/testsuite]
2018-05-18  Michael Meissner  <meissner@linux.ibm.com>

	PR target/85657
	* gcc.target/powerpc/pr85657-4.c: New tests for pack/unpack
	__ibm128 builtin functions, and whether an appropriate error
	message is generate if the long double pack/unpack are used when
	long double is IEEE 128.
	* gcc.target/powerpc/pr85657-5.c: Likewise.
	* gcc.target/powerpc/pr85657-6.c: Likewise.


-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meissner@linux.ibm.com, phone: +1 (978) 899-4797
Segher Boessenkool May 21, 2018, 5:59 p.m. | #2
Hi!

On Fri, May 18, 2018 at 06:22:31PM -0400, Michael Meissner wrote:
> 	* config/rs6000/rs6000.c (rs6000_init_builtins): Always create

> 	__ibm128 as a distinct type.


This is not what it does though?  It only does that if TARGET_FLOAT128_TYPE?
And it does not make long double a separate type in all cases.

So please fix the changelog.

I think the patch is a step in the right direction, please apply to trunk.
Okay for 8 too (after the usual shakedown).


Segher
Segher Boessenkool May 22, 2018, 1:08 a.m. | #3
On Fri, May 18, 2018 at 07:27:15PM -0400, Michael Meissner wrote:
> Here is patch 2 of 2 to make __ibm128 a distinct type.  This patch makes the

> long double pack and unpack builtins only work if the long double type is IBM

> extended double.  It adds two new builtins to pack and unpack __ibm128 types.

> 

> This has been tested on a little endian power8 system with bootstrap and

> regression test (with the previous patch also applied).  Can I check this into

> the trunk and the GCC 8 branch?

> 

> [gcc]

> 2018-05-18  Michael Meissner  <meissner@linux.ibm.com>

> 

> 	PR target/85657

> 	* config/rs6000/rs6000-builtin.def (BU_IBM128_2): New helper macro

> 	for __builtin_{,un}pack_ibm128.

> 	(PACK_IF): Declare __builtin_{,un}pack_ibm128.

> 	(UNPACK_IF): Likewise.

> 	* config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): The mask

> 	for long double builtins (RS6000_BTM_LDBL128) requires that long

> 	double is IBM extended double.

> 	(rs6000_invalid_builtin): Add a new error message if the long

> 	double {,un}pack builtins are used when long double is IEEE

> 	128-bit floating point.

> 	* config/rs6000/rs6000.h (RS6000_BTM_LDBL128): Update comment.

> 	* doc/extend.texi (PowerPC builtins): Update documention for

> 	__builtin_{,un}pack_longdouble.  Add documentation for

> 	__builtin_{,un}pack_ibm128.

> 

> [gcc/testsuite]

> 2018-05-18  Michael Meissner  <meissner@linux.ibm.com>

> 

> 	PR target/85657

> 	* gcc.target/powerpc/pr85657-4.c: New tests for pack/unpack

> 	__ibm128 builtin functions, and whether an appropriate error

> 	message is generate if the long double pack/unpack are used when

> 	long double is IEEE 128.

> 	* gcc.target/powerpc/pr85657-5.c: Likewise.

> 	* gcc.target/powerpc/pr85657-6.c: Likewise.


-ENOPATCH?


Segher
Michael Meissner May 22, 2018, 6 p.m. | #4
Evidently I forgot the patch.

[gcc]
2018-05-21  Michael Meissner  <meissner@linux.ibm.com>

	PR target/85657
	* config/rs6000/rs6000-builtin.def (BU_IBM128_2): New helper macro
	for __builtin_{,un}pack_ibm128.
	(PACK_IF): Declare __builtin_{,un}pack_ibm128.
	(UNPACK_IF): Likewise.
	* config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): The mask
	for long double builtins (RS6000_BTM_LDBL128) requires that long
	double is IBM extended double.
	(rs6000_invalid_builtin): Add a new error message if the long
	double {,un}pack builtins are used when long double is IEEE
	128-bit floating point.
	* config/rs6000/rs6000.h (RS6000_BTM_LDBL128): Update comment.
	* doc/extend.texi (PowerPC builtins): Update documention for
	__builtin_{,un}pack_longdouble.  Add documentation for
	__builtin_{,un}pack_ibm128.

[gcc/testsuite]
2018-05-21  Michael Meissner  <meissner@linux.ibm.com>

	PR target/85657
	* gcc.target/powerpc/pr85657-4.c: New tests for pack/unpack
	__ibm128 builtin functions, and whether an appropriate error
	message is generate if the long double pack/unpack are used when
	long double is IEEE 128.
	* gcc.target/powerpc/pr85657-5.c: Likewise.
	* gcc.target/powerpc/pr85657-6.c: Likewise.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meissner@linux.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-builtin.def
===================================================================
--- gcc/config/rs6000/rs6000-builtin.def	(.../trunk)	(revision 260267)
+++ gcc/config/rs6000/rs6000-builtin.def	(.../branches/ibm/ieee)	(revision 260381)
@@ -628,6 +628,17 @@
 		     | RS6000_BTC_BINARY),				\
 		    CODE_FOR_ ## ICODE)			/* ICODE */
 
+/* 128-bit __ibm128 floating point builtins (use -mfloat128 to indicate that
+   __ibm128 is available).  */
+#define BU_IBM128_2(ENUM, NAME, ATTR, ICODE)				\
+  RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM,		/* ENUM */	\
+		    "__builtin_" NAME,			/* NAME */	\
+		    (RS6000_BTM_HARD_FLOAT		/* MASK */	\
+		     | RS6000_BTM_FLOAT128),				\
+		    (RS6000_BTC_ ## ATTR		/* ATTR */	\
+		     | RS6000_BTC_BINARY),				\
+		    CODE_FOR_ ## ICODE)			/* ICODE */
+
 /* Miscellaneous builtins for instructions added in ISA 3.0.  These
    instructions don't require either the DFP or VSX options, just the basic
    ISA 3.0 enablement since they operate on general purpose registers.  */
@@ -2315,6 +2326,9 @@ BU_P9_64BIT_MISC_0 (DARN,	"darn",			MISC
 BU_LDBL128_2 (PACK_TF,		"pack_longdouble",	CONST,	packtf)
 BU_LDBL128_2 (UNPACK_TF,	"unpack_longdouble",	CONST,	unpacktf)
 
+BU_IBM128_2 (PACK_IF,		"pack_ibm128",		CONST,	packif)
+BU_IBM128_2 (UNPACK_IF,		"unpack_ibm128",	CONST,	unpackif)
+
 BU_P7_MISC_2 (PACK_V1TI,	"pack_vector_int128",	CONST,	packv1ti)
 BU_P7_MISC_2 (UNPACK_V1TI,	"unpack_vector_int128",	CONST,	unpackv1ti)
 
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(.../trunk)	(revision 260267)
+++ gcc/config/rs6000/rs6000.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -3891,7 +3891,8 @@ rs6000_builtin_mask_calculate (void)
 	  | ((TARGET_HTM)		    ? RS6000_BTM_HTM	   : 0)
 	  | ((TARGET_DFP)		    ? RS6000_BTM_DFP	   : 0)
 	  | ((TARGET_HARD_FLOAT)	    ? RS6000_BTM_HARD_FLOAT : 0)
-	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128   : 0)
+	  | ((TARGET_LONG_DOUBLE_128
+	      && !TARGET_IEEEQUAD)	    ? RS6000_BTM_LDBL128   : 0)
 	  | ((TARGET_FLOAT128_TYPE)	    ? RS6000_BTM_FLOAT128  : 0)
 	  | ((TARGET_FLOAT128_HW)	    ? RS6000_BTM_FLOAT128_HW : 0));
 }
@@ -15311,6 +15312,10 @@ rs6000_invalid_builtin (enum rs6000_buil
   else if ((fnmask & RS6000_BTM_P9_MISC) == RS6000_BTM_P9_MISC)
     error ("builtin function %qs requires the %qs option", name,
 	   "-mcpu=power9");
+  else if ((fnmask & RS6000_BTM_LDBL128)
+	   && (!TARGET_LONG_DOUBLE_128 || TARGET_IEEEQUAD))
+    error ("builtin function %qs requires the %qs and %qs options",
+	   name, "-mabi=ibmlongdouble", "-mlong-double-128");
   else if ((fnmask & (RS6000_BTM_HARD_FLOAT | RS6000_BTM_LDBL128))
 	   == (RS6000_BTM_HARD_FLOAT | RS6000_BTM_LDBL128))
     error ("builtin function %qs requires the %qs and %qs options",
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(.../trunk)	(revision 260267)
+++ gcc/config/rs6000/rs6000.h	(.../branches/ibm/ieee)	(revision 260381)
@@ -2452,7 +2452,7 @@ extern int frame_pointer_needed;
 #define RS6000_BTM_CELL		MASK_FPRND	/* Target is cell powerpc.  */
 #define RS6000_BTM_DFP		MASK_DFP	/* Decimal floating point.  */
 #define RS6000_BTM_HARD_FLOAT	MASK_SOFT_FLOAT	/* Hardware floating point.  */
-#define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit long double.  */
+#define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit IBM long double.  */
 #define RS6000_BTM_64BIT	MASK_64BIT	/* 64-bit addressing.  */
 #define RS6000_BTM_POWERPC64	MASK_POWERPC64	/* 64-bit registers.  */
 #define RS6000_BTM_FLOAT128	MASK_FLOAT128_KEYWORD /* IEEE 128-bit float.  */
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(.../trunk)	(revision 260267)
+++ gcc/doc/extend.texi	(.../branches/ibm/ieee)	(revision 260381)
@@ -15745,6 +15745,8 @@ processors:
 @smallexample
 uint64_t __builtin_ppc_get_timebase ();
 unsigned long __builtin_ppc_mftb ();
+__ibm128 __builtin_unpack_ibm128 (__ibm128, int);
+__ibm128 __builtin_pack_ibm128 (double, double);
 @end smallexample
 
 The @code{__builtin_ppc_get_timebase} and @code{__builtin_ppc_mftb}
@@ -15827,10 +15829,32 @@ the reciprocal estimate instructions.
 The following functions require @option{-mhard-float} and
 @option{-mmultiple} options.
 
-@smallexample
-long double __builtin_pack_longdouble (double, double);
-double __builtin_unpack_longdouble (long double, int);
-@end smallexample
+The @code{__builtin_unpack_longdouble} function takes a
+@code{long double} argument and a compile time constant of 0 or 1.  If
+the constant is 0, the first @code{double} within the
+@code{long double} is returned, otherwise the second @code{double}
+is returned.  The @code{__builtin_unpack_longdouble} function is only
+availble if @code{long double} uses the IBM extended double
+representation.
+
+The @code{__builtin_pack_longdouble} function takes two @code{double}
+arguments and returns a @code{long double} value that combines the two
+arguments.  The @code{__builtin_pack_longdouble} function is only
+availble if @code{long double} uses the IBM extended double
+representation.
+
+The @code{__builtin_unpack_ibm128} function takes a @code{__ibm128}
+argument and a compile time constant of 0 or 1.  If the constant is 0,
+the first @code{double} within the @code{__ibm128} is returned,
+otherwise the second @code{double} is returned.
+
+The @code{__builtin_pack_ibm128} function takes two @code{double}
+arguments and returns a @code{__ibm128} value that combines the two
+arguments.
+
+Additional built-in functions are available for the 64-bit PowerPC
+family of processors, for efficient use of 128-bit floating point
+(@code{__float128}) values.
 
 @node Basic PowerPC Built-in Functions Available on ISA 2.06
 @subsubsection Basic PowerPC Built-in Functions Available on ISA 2.06
Index: gcc/testsuite/gcc.target/powerpc/pr85657-4.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85657-4.c	(.../trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85657-4.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2" } */
+
+/* PR 85657 -- test __builtin_pack_ibm128.  */
+
+__ibm128
+pack (double dummy, double a, double b)
+{
+  /* Should just generate some moves.  */
+  return __builtin_pack_ibm128 (a, b);
+}
+
+/* { dg-final { scan-assembler     {\m(fmr|xxlor)\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
+/* { dg-final { scan-assembler-not {\m(stfd|stxsd)x?\M} } } */
+/* { dg-final { scan-assembler-not {\m(lfd|lxsd)x?\M} } } */
+/* { dg-final { scan-assembler-not {\m(mtvsrd|mfvsrd)\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/pr85657-5.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85657-5.c	(.../trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85657-5.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,25 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2" } */
+
+/* PR 85657 -- test __builtin_unpack_ibm128.  Each call should generate just 1
+   move.  */
+
+double
+unpack0 (double dummy, __ibm128 x)
+{
+  return __builtin_unpack_ibm128 (x, 0);
+}
+
+double
+unpack1 (double dummy, __ibm128 x)
+{
+  /* Should just generate some moves.  */
+  return __builtin_unpack_ibm128 (x, 1);
+}
+
+/* { dg-final { scan-assembler     {\m(fmr|xxlor)\M} } } */
+/* { dg-final { scan-assembler-not {\mbl\M} } } */
+/* { dg-final { scan-assembler-not {\m(stfd|stxsd)x?\M} } } */
+/* { dg-final { scan-assembler-not {\m(lfd|lxsd)x?\M} } } */
+/* { dg-final { scan-assembler-not {\m(mtvsrd|mfvsrd)\M} } } */
Index: gcc/testsuite/gcc.target/powerpc/pr85657-6.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85657-6.c	(.../trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85657-6.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+/* PR 85657 -- test that __builtin_pack_longdouble and
+   __builtin_unpack_longdouble get the appropriate error messages.  */
+
+long double
+pack (double a, double b)
+{
+  /* Should just generate some moves.  */
+  return __builtin_pack_longdouble (a, b); /* { dg-error builtin function '__builtin_pack_longdouble' } */
+}
+
+double
+unpack0 (long double x)
+{
+  return __builtin_unpack_longdouble (x, 0); /* { dg-error builtin function '__builtin_unpack_longdouble' } */
+}

Patch

Index: gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c	(.../trunk)	(revision 260267)
+++ gcc/config/rs6000/rs6000-c.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -608,8 +608,6 @@  rs6000_cpu_cpp_builtins (cpp_reader *pfi
     builtin_define ("__RSQRTEF__");
   if (TARGET_FLOAT128_TYPE)
     builtin_define ("__FLOAT128_TYPE__");
-  if (TARGET_LONG_DOUBLE_128 && FLOAT128_IBM_P (TFmode))
-    builtin_define ("__ibm128=long double");
 #ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
   builtin_define ("__BUILTIN_CPU_SUPPORTS__");
 #endif
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(.../trunk)	(revision 260267)
+++ gcc/config/rs6000/rs6000.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -16345,35 +16350,28 @@  rs6000_init_builtins (void)
      floating point, we need make sure the type is non-zero or else self-test
      fails during bootstrap.
 
-     We don't register a built-in type for __ibm128 if the type is the same as
-     long double.  Instead we add a #define for __ibm128 in
-     rs6000_cpu_cpp_builtins to long double.
+     Always create __ibm128 as a separate type, even if the current long double
+     format is IBM extended double.
 
      For IEEE 128-bit floating point, always create the type __ieee128.  If the
      user used -mfloat128, rs6000-c.c will create a define from __float128 to
      __ieee128.  */
-  if (TARGET_LONG_DOUBLE_128 && FLOAT128_IEEE_P (TFmode))
+  if (TARGET_FLOAT128_TYPE)
     {
       ibm128_float_type_node = make_node (REAL_TYPE);
       TYPE_PRECISION (ibm128_float_type_node) = 128;
       SET_TYPE_MODE (ibm128_float_type_node, IFmode);
       layout_type (ibm128_float_type_node);
-
       lang_hooks.types.register_builtin_type (ibm128_float_type_node,
 					      "__ibm128");
-    }
-  else
-    ibm128_float_type_node = long_double_type_node;
 
-  if (TARGET_FLOAT128_TYPE)
-    {
       ieee128_float_type_node = float128_type_node;
       lang_hooks.types.register_builtin_type (ieee128_float_type_node,
 					      "__ieee128");
     }
 
   else
-    ieee128_float_type_node = long_double_type_node;
+    ieee128_float_type_node = ibm128_float_type_node = long_double_type_node;
 
   /* Initialize the modes for builtin_function_type, mapping a machine mode to
      tree type node.  */
@@ -17863,13 +17861,13 @@  init_float128_ieee (machine_mode mode)
       set_conv_libfunc (trunc_optab, SFmode, mode, "__trunckfsf2");
       set_conv_libfunc (trunc_optab, DFmode, mode, "__trunckfdf2");
 
-      set_conv_libfunc (sext_optab, mode, IFmode, "__extendtfkf2");
+      set_conv_libfunc (sext_optab, mode, IFmode, "__trunctfkf2");
       if (mode != TFmode && FLOAT128_IBM_P (TFmode))
-	set_conv_libfunc (sext_optab, mode, TFmode, "__extendtfkf2");
+	set_conv_libfunc (sext_optab, mode, TFmode, "__trunctfkf2");
 
-      set_conv_libfunc (trunc_optab, IFmode, mode, "__trunckftf2");
+      set_conv_libfunc (trunc_optab, IFmode, mode, "__extendkftf2");
       if (mode != TFmode && FLOAT128_IBM_P (TFmode))
-	set_conv_libfunc (trunc_optab, TFmode, mode, "__trunckftf2");
+	set_conv_libfunc (trunc_optab, TFmode, mode, "__extendkftf2");
 
       set_conv_libfunc (sext_optab, mode, SDmode, "__dpd_extendsdkf2");
       set_conv_libfunc (sext_optab, mode, DDmode, "__dpd_extendddkf2");
@@ -21698,9 +21696,9 @@  rs6000_expand_float128_convert (rtx dest
   else
     gcc_unreachable ();
 
-  /* Handle conversion between TFmode/KFmode.  */
+  /* Handle conversion between TFmode/KFmode/IFmode.  */
   if (do_move)
-    emit_move_insn (dest, gen_lowpart (dest_mode, src));
+    emit_insn (gen_rtx_SET (dest, gen_rtx_FLOAT_EXTEND (dest_mode, src)));
 
   /* Handle conversion if we have hardware support.  */
   else if (TARGET_FLOAT128_HW && hw_convert)
@@ -32126,14 +32124,11 @@  rs6000_mangle_type (const_tree type)
       if (type == ieee128_float_type_node)
 	return "U10__float128";
 
-      if (TARGET_LONG_DOUBLE_128)
-	{
-	  if (type == long_double_type_node)
-	    return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
+      if (type == ibm128_float_type_node)
+	return "u8__ibm128";
 
-	  if (type == ibm128_float_type_node)
-	    return "g";
-	}
+      if (TARGET_LONG_DOUBLE_128 && type == long_double_type_node)
+	return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
     }
 
   /* Mangle IBM extended float long double as `g' (__float128) on
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(.../trunk)	(revision 260267)
+++ gcc/config/rs6000/rs6000.md	(.../branches/ibm/ieee)	(revision 260381)
@@ -422,6 +422,12 @@  (define_mode_iterator FMOVE128_GPR [TI
 ; Iterator for 128-bit VSX types for pack/unpack
 (define_mode_iterator FMOVE128_VSX [V1TI KF])
 
+; Iterators for converting to/from TFmode
+(define_mode_iterator IFKF [IF KF])
+
+; Constraints for moving IF/KFmode.
+(define_mode_attr IFKF_reg [(IF "d") (KF "wa")])
+
 ; Whether a floating point move is ok, don't allow SD without hardware FP
 (define_mode_attr fmove_ok [(SF "")
 			    (DF "")
@@ -8188,6 +8194,32 @@  (define_expand "trunctfif2"
   DONE;
 })
 
+(define_insn_and_split "*extend<mode>tf2_internal"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=<IFKF_reg>")
+	(float_extend:TF
+	 (match_operand:IFKF 1 "gpc_reg_operand" "<IFKF_reg>")))]
+   "TARGET_FLOAT128_TYPE
+    && FLOAT128_IBM_P (TFmode) == FLOAT128_IBM_P (<MODE>mode)"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (match_dup 2))]
+{
+  operands[2] = gen_rtx_REG (TFmode, REGNO (operands[1]));
+})
+
+(define_insn_and_split "*extendtf<mode>2_internal"
+  [(set (match_operand:IFKF 0 "gpc_reg_operand" "=<IFKF_reg>")
+	(float_extend:IFKF
+	 (match_operand:TF 1 "gpc_reg_operand" "<IFKF_reg>")))]
+   "TARGET_FLOAT128_TYPE
+    && FLOAT128_IBM_P (TFmode) == FLOAT128_IBM_P (<MODE>mode)"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (match_dup 2))]
+{
+  operands[2] = gen_rtx_REG (<MODE>mode, REGNO (operands[1]));
+})
+
 
 ;; Reload helper functions used by rs6000_secondary_reload.  The patterns all
 ;; must have 3 arguments, and scratch register constraint must be a single
Index: gcc/testsuite/gcc.target/powerpc/pr85657-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85657-1.c	(.../trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85657-1.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,74 @@ 
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" } */
+
+// PR 85657 -- make sure conversions work between each of the 128-bit floating
+// point types.
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+  return (long double)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+  return (long double)a;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+volatile __float128 f128 = 1.2Q;
+volatile __ibm128 i128 = (__ibm128)3.4L;
+volatile long double ld = 5.6L;
+
+int
+main (void)
+{
+  printf ("f128 (1.2) = %g (ld), %g (ibm128)\n",
+	  (double) float128_to_ldouble (f128),
+	  (double) float128_to_ibm128 (f128));
+
+  printf ("i128 (3.4) = %g (ld), %g (float128)\n",
+	  (double) ibm128_to_ldouble (i128),
+	  (double) ibm128_to_float128 (i128));
+
+  printf ("long double (5.6) = %g (ibm128), %g (float128)\n",
+	  (double) ldouble_to_ibm128 (ld),
+	  (double) ldouble_to_float128 (ld));
+
+  return 0;
+}
+#endif
Index: gcc/testsuite/gcc.target/powerpc/pr85657-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85657-2.c	(.../trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85657-2.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,74 @@ 
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+// PR 85657 -- make sure conversions work between each of the 128-bit floating
+// point types.
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+  return (long double)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+  return (long double)a;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+volatile __float128 f128 = 1.2Q;
+volatile __ibm128 i128 = (__ibm128)3.4L;
+volatile long double ld = 5.6L;
+
+int
+main (void)
+{
+  printf ("f128 (1.2) = %g (ld), %g (ibm128)\n",
+	  (double) float128_to_ldouble (f128),
+	  (double) float128_to_ibm128 (f128));
+
+  printf ("i128 (3.4) = %g (ld), %g (float128)\n",
+	  (double) ibm128_to_ldouble (i128),
+	  (double) ibm128_to_float128 (i128));
+
+  printf ("long double (5.6) = %g (ibm128), %g (float128)\n",
+	  (double) ldouble_to_ibm128 (ld),
+	  (double) ldouble_to_float128 (ld));
+
+  return 0;
+}
+#endif
Index: gcc/testsuite/gcc.target/powerpc/pr85657-3.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/pr85657-3.c	(.../trunk)	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/pr85657-3.c	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,82 @@ 
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-require-effective-target vsx_hw } */
+/* { dg-options "-mvsx -O2" } */
+
+/* PR 85657 -- make __ibm128 a full type.  */
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+  return (__float128)a + 1.0q;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+  return (__float128)a + 1.0q;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+  return (__ibm128)a + (__ibm128)1.0;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+  return (__ibm128)a + (__ibm128)1.0;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+  return (long double)a + 1.0L;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+  return (long double)a + 1.0L;
+}
+
+volatile __float128  f128 = 1.25Q;
+volatile __ibm128    i128 = (__ibm128)3.5L;
+volatile long double ld   = 4.75L;
+
+volatile double f128_p1 = 2.25;
+volatile double i128_p1 = 4.5;
+volatile double ld_p1   = 5.75;
+
+extern void abort (void);
+
+int
+main (void)
+{
+  if (((double) float128_to_ldouble (f128)) != f128_p1)
+    abort ();
+
+  if (((double) float128_to_ibm128 (f128)) != f128_p1)
+    abort ();
+
+  if (((double) ibm128_to_ldouble (i128)) != i128_p1)
+    abort ();
+
+  if (((double) ibm128_to_float128 (i128)) != i128_p1)
+    abort ();
+
+  if (((double) ldouble_to_ibm128 (ld)) != ld_p1)
+    abort ();
+
+  if (((double) ldouble_to_float128 (ld)) != ld_p1)
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/g++.dg/pr85657.C
===================================================================
--- gcc/testsuite/g++.dg/pr85657.C	(.../trunk)	(revision 0)
+++ gcc/testsuite/g++.dg/pr85657.C	(.../branches/ibm/ieee)	(revision 260381)
@@ -0,0 +1,47 @@ 
+// { dg-do compile { target { powerpc*-*-linux* } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" }
+
+// PR 85657
+// Check that __ibm128 and long double are represented as different types, even
+// if long double is currently using the same representation as __ibm128.
+
+template <class __T> inline bool
+iszero (__T __val)
+{
+  return __val == 0;
+}
+
+int
+use_template (void)
+{
+  long double ld = 0.0;
+  __ibm128 ibm = 0.0;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+d" (ld), "+d" (ibm));
+#endif
+
+  return iszero (ld) + iszero (ibm);
+}
+
+class foo {
+public:
+  foo () {}
+  ~foo () {}
+  inline bool iszero (long double ld) { return ld == 0.0; }
+  inline bool iszero (__ibm128 i128) { return i128 == 0.0; }
+} st;
+
+int
+use_class (void)
+{
+  long double ld = 0.0;
+  __ibm128 ibm = 0.0;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+d" (ld), "+d" (ibm));
+#endif
+
+  return st.iszero (ld) + st.iszero (ibm);
+}