diff mbox

, PowerPC IEEE 128-bit fp, patch #10 (comparison, documentation, conversion, debug)

Message ID 20151229154333.GA16764@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner Dec. 29, 2015, 3:43 p.m. UTC
This is a clean-up patch for IEEE 128-bit floating point support on the
PowerPC.

The main change is to change the way comparisons are done when IEEE 128-bit
floating is emulated.  Previously, I had added special __cmpkf2 and __cmpukf2
functions that were modeled on the CR bits that the XSCMPUQP instruction sets.
I have changed this to use the standard EQ, GE, LE, and UNORD functions
provided by glibc/libgcc's software floating point emulation functions.

I've done some debugging on issues with _Complex __float128, and I think at the
moment it is just not feasible to support _Complex __float128 in GCC 6.x.  The
main problem is the way the IFmode/KFmode types are added as fractional floating
point types which prevents them from being default types for conversion.  I
think in order to support this, the machine independent type system is going to
have to be tinkered with.  However, since we are now coming to the end of
stage3 it is not the time to be making these changes.

I added documentation to state that right now -mfloat128 is only enabled on
64-bit PowerPC Linux systems.  There is some desire for this to be eventually
supported on other systems like FreeBSD, but I wanted to set expectations for
users interested in the this.  I also documented that complex __float128
currently does not work.

I added an undocumented debug switch (-mfloat128-convert) that enables default
conversions between IBM extended double and IEEE 128-bit floating point, to
enable further debugging of the complex __float128 support in the future.

Finally, I noticed if you use -mabi=ieeelongdouble, that it generated calls to
convert between long double and explicit __float128, even though they are the
same representation, and fixed that.

Going forward, patch #11 will enable the software emulation library.  At the
moment, there is no support for converting between decimal types and
__float128, nor for the complex __float128 support.  These are being worked on,
and should be done in the GCC 7.x time frame.  However, it is important to add
the software emulation support in GCC 6.x so that most users that want to use
IEEE 128-bit floating point can use it, and that we can work on the glibc
issues to fully support __float128 in the GCC 7.x time frame.

2015-12-29  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit
	comparison functions in cmp_optab and ucmp_optab.
	(rs6000_generate_compare): Rewrite IEEE 128-bit floating point
	software emulation comparisons to only use __eqkf2, __gekf2,
	__lekf2, and __unordkf2 functions.
	(rs6000_invalid_binary_op): Add support for -mfloat128-convert.

	* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
	__FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is
	available.

	* config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch
	to allow IBM extended double and IEEE 128-bit floating point to be
	converted with default conversions.

	* config/rs6000/rs6000.md (extendkftf2): Add converters between
	KFmode and TFmode if -mabi=ieeelongdouble.
	(trunctfkf2): Likewise.
	(ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and
	64-bit insns.
	(ieee128_mfvsrd_64bit): Likewise.
	(ieee128_mfvsrd_32bit): Likewise.
	(ieee128_mtvsrd): Likewise.
	(ieee128_mtvsrd_64bit): Likewise.
	(ieee128_mtvsrd_32bit): Likewise.

	* doc/extend.texi (Floating Types): Document that complex
	__float128 does not work currently.

	* doc/invoke.texi (RS/6000 and PowerPC Options): Document that
	-mfloat128 is only supported on PowerPC 64-bit Linux systems.

Comments

David Edelsohn Dec. 29, 2015, 4:37 p.m. UTC | #1
On Tue, Dec 29, 2015 at 10:43 AM, Michael Meissner
<meissner@linux.vnet.ibm.com> wrote:
> This is a clean-up patch for IEEE 128-bit floating point support on the
> PowerPC.
>
> The main change is to change the way comparisons are done when IEEE 128-bit
> floating is emulated.  Previously, I had added special __cmpkf2 and __cmpukf2
> functions that were modeled on the CR bits that the XSCMPUQP instruction sets.
> I have changed this to use the standard EQ, GE, LE, and UNORD functions
> provided by glibc/libgcc's software floating point emulation functions.
>
> I've done some debugging on issues with _Complex __float128, and I think at the
> moment it is just not feasible to support _Complex __float128 in GCC 6.x.  The
> main problem is the way the IFmode/KFmode types are added as fractional floating
> point types which prevents them from being default types for conversion.  I
> think in order to support this, the machine independent type system is going to
> have to be tinkered with.  However, since we are now coming to the end of
> stage3 it is not the time to be making these changes.
>
> I added documentation to state that right now -mfloat128 is only enabled on
> 64-bit PowerPC Linux systems.  There is some desire for this to be eventually
> supported on other systems like FreeBSD, but I wanted to set expectations for
> users interested in the this.  I also documented that complex __float128
> currently does not work.
>
> I added an undocumented debug switch (-mfloat128-convert) that enables default
> conversions between IBM extended double and IEEE 128-bit floating point, to
> enable further debugging of the complex __float128 support in the future.
>
> Finally, I noticed if you use -mabi=ieeelongdouble, that it generated calls to
> convert between long double and explicit __float128, even though they are the
> same representation, and fixed that.
>
> Going forward, patch #11 will enable the software emulation library.  At the
> moment, there is no support for converting between decimal types and
> __float128, nor for the complex __float128 support.  These are being worked on,
> and should be done in the GCC 7.x time frame.  However, it is important to add
> the software emulation support in GCC 6.x so that most users that want to use
> IEEE 128-bit floating point can use it, and that we can work on the glibc
> issues to fully support __float128 in the GCC 7.x time frame.
>
> 2015-12-29  Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>         * config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit
>         comparison functions in cmp_optab and ucmp_optab.
>         (rs6000_generate_compare): Rewrite IEEE 128-bit floating point
>         software emulation comparisons to only use __eqkf2, __gekf2,
>         __lekf2, and __unordkf2 functions.
>         (rs6000_invalid_binary_op): Add support for -mfloat128-convert.
>
>         * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
>         __FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is
>         available.
>
>         * config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch
>         to allow IBM extended double and IEEE 128-bit floating point to be
>         converted with default conversions.
>
>         * config/rs6000/rs6000.md (extendkftf2): Add converters between
>         KFmode and TFmode if -mabi=ieeelongdouble.
>         (trunctfkf2): Likewise.
>         (ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and
>         64-bit insns.
>         (ieee128_mfvsrd_64bit): Likewise.
>         (ieee128_mfvsrd_32bit): Likewise.
>         (ieee128_mtvsrd): Likewise.
>         (ieee128_mtvsrd_64bit): Likewise.
>         (ieee128_mtvsrd_32bit): Likewise.
>
>         * doc/extend.texi (Floating Types): Document that complex
>         __float128 does not work currently.
>
>         * doc/invoke.texi (RS/6000 and PowerPC Options): Document that
>         -mfloat128 is only supported on PowerPC 64-bit Linux systems.

Okay.

Thanks, David
Joseph Myers Dec. 31, 2015, 12:16 a.m. UTC | #2
On Tue, 29 Dec 2015, Michael Meissner wrote:

> Going forward, patch #11 will enable the software emulation library.  At the
> moment, there is no support for converting between decimal types and
> __float128, nor for the complex __float128 support.  These are being worked on,
> and should be done in the GCC 7.x time frame.  However, it is important to add
> the software emulation support in GCC 6.x so that most users that want to use
> IEEE 128-bit floating point can use it, and that we can work on the glibc
> issues to fully support __float128 in the GCC 7.x time frame.

While of course glibc issues can be worked on in the GCC 7.x time frame 
even in the absence of a GCC release with the required support (and 
functions could be added to glibc e.g. for x86_64 where the GCC support 
already exists), to be clear, as the glibc ABI can't depend on the GCC 
version used to build glibc, it won't be possible to add any __float128 
functions to glibc for powerpc until there is glibc community consensus 
that we can require GCC 7.x (or whatever version has all the required 
features, which certainly include complex __float128 support) as the 
minimum version for building glibc for powerpc64 (and the symbol version 
for any new functions will be that of the first glibc release including 
them, as usual).  That may not be for a few years.

(I exclude the idea of adding real functions to glibc before complex 
functions as unlikely to get consensus, although there's certainly a lot 
of careful design and consensus-building work to determine the precise set 
of functions that makes logical sense, especially as regards float128 
equivalents of glibc functions outside ISO C, or ISO C functions where TS 
18661-3 nevertheless doesn't include *f128 functions - and to resolve a 
great many other tricky design issues.)
diff mbox

Patch

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)	(revision 231978)
+++ gcc/config/rs6000/rs6000.c	(.../gcc/config/rs6000)	(working copy)
@@ -16501,8 +16501,6 @@  init_float128_ieee (machine_mode mode)
       set_optab_libfunc (lt_optab, mode, "__ltkf2");
       set_optab_libfunc (le_optab, mode, "__lekf2");
       set_optab_libfunc (unord_optab, mode, "__unordkf2");
-      set_optab_libfunc (cmp_optab, mode, "__cmpokf2");		/* fcmpo */
-      set_optab_libfunc (ucmp_optab, mode, "__cmpukf2");	/* fcmpu */
 
       set_conv_libfunc (sext_optab, mode, SFmode, "__extendsfkf2");
       set_conv_libfunc (sext_optab, mode, DFmode, "__extenddfkf2");
@@ -20297,7 +20295,9 @@  rs6000_generate_compare (rtx cmp, machin
   rtx op0 = XEXP (cmp, 0);
   rtx op1 = XEXP (cmp, 1);
 
-  if (FLOAT_MODE_P (mode))
+  if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
+    comp_mode = CCmode;
+  else if (FLOAT_MODE_P (mode))
     comp_mode = CCFPmode;
   else if (code == GTU || code == LTU
 	   || code == GEU || code == LEU)
@@ -20503,106 +20503,77 @@  rs6000_generate_compare (rtx cmp, machin
       emit_insn (cmp);
     }
 
-  /* IEEE 128-bit support in VSX registers.  If we do not have IEEE 128-bit
-     hardware, the comparison functions (__cmpokf2 and __cmpukf2) returns 0..15
-     that is laid out the same way as the PowerPC CR register would for a
-     normal floating point comparison from the fcmpo and fcmpu
-     instructions.  */
-  else if (!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (mode))
+  /* IEEE 128-bit support in VSX registers when we do not have hardware
+     support.  */
+  else if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
     {
-      rtx and_reg = gen_reg_rtx (SImode);
+      rtx libfunc = NULL_RTX;
+      bool uneq_or_ltgt = false;
       rtx dest = gen_reg_rtx (SImode);
-      rtx libfunc = optab_libfunc (ucmp_optab, mode);
-      HOST_WIDE_INT mask_value = 0;
-
-      /* Values that __cmpokf2/__cmpukf2 returns.  */
-#define PPC_CMP_UNORDERED	0x1		/* isnan (a) || isnan (b).  */
-#define PPC_CMP_EQUAL		0x2		/* a == b.  */
-#define PPC_CMP_GREATER_THEN	0x4		/* a > b.  */
-#define PPC_CMP_LESS_THEN	0x8		/* a < b.  */
 
       switch (code)
 	{
 	case EQ:
-	  mask_value = PPC_CMP_EQUAL;
-	  code = NE;
-	  break;
-
 	case NE:
-	  mask_value = PPC_CMP_EQUAL;
-	  code = EQ;
+	  libfunc = optab_libfunc (eq_optab, mode);
 	  break;
 
 	case GT:
-	  mask_value = PPC_CMP_GREATER_THEN;
-	  code = NE;
-	  break;
-
 	case GE:
-	  mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
-	  code = NE;
+	  libfunc = optab_libfunc (ge_optab, mode);
 	  break;
 
 	case LT:
-	  mask_value = PPC_CMP_LESS_THEN;
-	  code = NE;
-	  break;
-
 	case LE:
-	  mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
-	  code = NE;
-	  break;
-
-	case UNLE:
-	  mask_value = PPC_CMP_GREATER_THEN;
-	  code = EQ;
+	  libfunc = optab_libfunc (le_optab, mode);
 	  break;
 
-	case UNLT:
-	  mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
-	  code = EQ;
+	case UNORDERED:
+	case ORDERED:
+	  libfunc = optab_libfunc (unord_optab, mode);
+	  code = (code == UNORDERED) ? NE : EQ;
 	  break;
 
 	case UNGE:
-	  mask_value = PPC_CMP_LESS_THEN;
-	  code = EQ;
+	case UNGT:
+	  libfunc = optab_libfunc (le_optab, mode);
+	  code = (code == UNGE) ? GE : GT;
 	  break;
 
-	case UNGT:
-	  mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
-	  code = EQ;
+	case UNLE:
+	case UNLT:
+	  libfunc = optab_libfunc (ge_optab, mode);
+	  code = (code == UNLE) ? LE : LT;
 	  break;
 
 	case UNEQ:
-	  mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
-	  code = NE;
-
 	case LTGT:
-	  mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
-	  code = EQ;
-	  break;
-
-	case UNORDERED:
-	  mask_value = PPC_CMP_UNORDERED;
-	  code = NE;
-	  break;
-
-	case ORDERED:
-	  mask_value = PPC_CMP_UNORDERED;
-	  code = EQ;
+	  libfunc = optab_libfunc (le_optab, mode);
+	  uneq_or_ltgt = true;
+	  code = (code = UNEQ) ? NE : EQ;
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
 
-      gcc_assert (mask_value != 0);
-      and_reg = emit_library_call_value (libfunc, and_reg, LCT_CONST, SImode, 2,
-					 op0, mode, op1, mode);
-
-      emit_insn (gen_andsi3 (dest, and_reg, GEN_INT (mask_value)));
-      compare_result = gen_reg_rtx (CCmode);
-      comp_mode = CCmode;
+      gcc_assert (libfunc);
+      dest = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+				      SImode, 2, op0, mode, op1, mode);
+
+      /* If this is UNEQ or LTGT, we call __lekf2, which returns -1 for less
+	 than, 0 for equal, +1 for greater, and +2 for nan.  We add 1, to give
+	 a value of 0..3, and then do and AND immediate of 1 to isolate whether
+	 it is 0/Nan (i.e. bottom bit is 0), or less than/greater than
+	 (i.e. bottom bit is 1).  */
+      if (uneq_or_ltgt)
+	{
+	  rtx add_result = gen_reg_rtx (SImode);
+	  rtx and_result = gen_reg_rtx (SImode);
+	  emit_insn (gen_addsi3 (add_result, dest, GEN_INT (1)));
+	  emit_insn (gen_andsi3 (and_result, add_result, GEN_INT (1)));
+	  dest = and_result;
+	}
 
       emit_insn (gen_rtx_SET (compare_result,
 			      gen_rtx_COMPARE (comp_mode, dest, const0_rtx)));
@@ -20706,24 +20677,29 @@  rs6000_invalid_binary_op (int op ATTRIBU
     mode2 = GET_MODE_INNER (mode2);
 
   /* Don't allow IEEE 754R 128-bit binary floating point and IBM extended
-     double to intermix.  */
+     double to intermix unless -mfloat128-convert.  */
   if (mode1 == mode2)
     return NULL;
 
-  if ((mode1 == KFmode && mode2 == IFmode)
-      || (mode1 == IFmode && mode2 == KFmode))
-    return N_("__float128 and __ibm128 cannot be used in the same expression");
-
-  if (TARGET_IEEEQUAD
-      && ((mode1 == IFmode && mode2 == TFmode)
-	  || (mode1 == TFmode && mode2 == IFmode)))
-    return N_("__ibm128 and long double cannot be used in the same expression");
-
-  if (!TARGET_IEEEQUAD
-      && ((mode1 == KFmode && mode2 == TFmode)
-	  || (mode1 == TFmode && mode2 == KFmode)))
-    return N_("__float128 and long double cannot be used in the same "
-	      "expression");
+  if (!TARGET_FLOAT128_CVT)
+    {
+      if ((mode1 == KFmode && mode2 == IFmode)
+	  || (mode1 == IFmode && mode2 == KFmode))
+	return N_("__float128 and __ibm128 cannot be used in the same "
+		  "expression");
+
+      if (TARGET_IEEEQUAD
+	  && ((mode1 == IFmode && mode2 == TFmode)
+	      || (mode1 == TFmode && mode2 == IFmode)))
+	return N_("__ibm128 and long double cannot be used in the same "
+		  "expression");
+
+      if (!TARGET_IEEEQUAD
+	  && ((mode1 == KFmode && mode2 == TFmode)
+	      || (mode1 == TFmode && mode2 == KFmode)))
+	return N_("__float128 and long double cannot be used in the same "
+		  "expression");
+    }
 
   return NULL;
 }
Index: gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)	(revision 231978)
+++ gcc/config/rs6000/rs6000-c.c	(.../gcc/config/rs6000)	(working copy)
@@ -412,6 +412,8 @@  rs6000_cpu_cpp_builtins (cpp_reader *pfi
     builtin_define ("__RSQRTEF__");
   if (TARGET_FLOAT128)
     builtin_define ("__FLOAT128__");
+  if (TARGET_FLOAT128_HW)
+    builtin_define ("__FLOAT128_HARDWARE__");
 
   if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM)
     {
Index: gcc/config/rs6000/rs6000.opt
===================================================================
--- gcc/config/rs6000/rs6000.opt	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)	(revision 231978)
+++ gcc/config/rs6000/rs6000.opt	(.../gcc/config/rs6000)	(working copy)
@@ -632,3 +632,7 @@  Enable/disable IEEE 128-bit floating poi
 mfloat128-hardware
 Target Report Mask(FLOAT128_HW) Var(rs6000_isa_flags)
 Enable/disable using IEEE 128-bit floating point instructions.
+
+mfloat128-convert
+Target Undocumented Mask(FLOAT128_CVT) Var(rs6000_isa_flags)
+Enable/disable default conversions between __float128 & long double.
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/config/rs6000)	(revision 231978)
+++ gcc/config/rs6000/rs6000.md	(.../gcc/config/rs6000)	(working copy)
@@ -13352,6 +13352,40 @@  (define_insn "extend<SFDF:mode><IEEE128:
   "xscvdpqp %0,%1"
   [(set_attr "type" "vecfloat")])
 
+;; Conversion between KFmode and TFmode if TFmode is ieee 128-bit floating
+;; point is a simple copy.
+(define_insn_and_split "extendkftf2"
+  [(set (match_operand:TF 0 "vsx_register_operand" "=wa,?wa")
+	(float_extend:TF (match_operand:KF 1 "vsx_register_operand" "0,wa")))]
+  "TARGET_FLOAT128 && TARGET_IEEEQUAD"
+  "@
+   #
+   xxlor %x0,%x1,%x1"
+  "&& reload_completed  && REGNO (operands[0]) == REGNO (operands[1])"
+  [(const_int 0)]
+{
+  emit_note (NOTE_INSN_DELETED);
+  DONE;
+}
+  [(set_attr "type" "*,vecsimple")
+   (set_attr "length" "0,4")])
+
+(define_insn_and_split "trunctfkf2"
+  [(set (match_operand:KF 0 "vsx_register_operand" "=wa,?wa")
+	(float_extend:KF (match_operand:TF 1 "vsx_register_operand" "0,wa")))]
+  "TARGET_FLOAT128 && TARGET_IEEEQUAD"
+  "@
+   #
+   xxlor %x0,%x1,%x1"
+  "&& reload_completed  && REGNO (operands[0]) == REGNO (operands[1])"
+  [(const_int 0)]
+{
+  emit_note (NOTE_INSN_DELETED);
+  DONE;
+}
+  [(set_attr "type" "*,vecsimple")
+   (set_attr "length" "0,4")])
+
 (define_insn "trunc<mode>df2_hw"
   [(set (match_operand:DF 0 "altivec_register_operand" "=v")
 	(float_truncate:DF
@@ -13476,7 +13510,7 @@  (define_insn "*xscv<su>dqp_<mode>"
   "xscv<su>dqp %0,%1"
   [(set_attr "type" "vecfloat")])
 
-(define_insn "*ieee128_mfvsrd"
+(define_insn "*ieee128_mfvsrd_64bit"
   [(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi")
 	(unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")]
 		   UNSPEC_IEEE128_MOVE))]
@@ -13487,6 +13521,17 @@  (define_insn "*ieee128_mfvsrd"
    xxlor %x0,%x1,%x1"
   [(set_attr "type" "mftgpr,vecsimple,fpstore")])
 
+
+(define_insn "*ieee128_mfvsrd_32bit"
+  [(set (match_operand:DI 0 "reg_or_indexed_operand" "=Z,wi")
+	(unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
+		   UNSPEC_IEEE128_MOVE))]
+  "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
+  "@
+   stxsdx %x1,%y0
+   xxlor %x0,%x1,%x1"
+  [(set_attr "type" "vecsimple,fpstore")])
+
 (define_insn "*ieee128_mfvsrwz"
   [(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z")
 	(unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
@@ -13512,17 +13557,27 @@  (define_insn "*ieee128_mtvsrw"
   [(set_attr "type" "mffgpr,fpload,mffgpr,fpload")])
 
 
-(define_insn "*ieee128_mtvsrd"
+(define_insn "*ieee128_mtvsrd_64bit"
   [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v")
 	(unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")]
 		     UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW"
+  "TARGET_FLOAT128_HW && TARGET_POWERPC64"
   "@
    mtvsrd %x0,%1
    lxsdx %x0,%y1
    xxlor %x0,%x1,%x1"
   [(set_attr "type" "mffgpr,fpload,vecsimple")])
 
+(define_insn "*ieee128_mtvsrd_32bit"
+  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v")
+	(unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "Z,wi")]
+		     UNSPEC_IEEE128_MOVE))]
+  "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
+  "@
+   lxsdx %x0,%y1
+   xxlor %x0,%x1,%x1"
+  [(set_attr "type" "fpload,vecsimple")])
+
 ;; IEEE 128-bit instructions with round to odd semantics
 (define_insn "*trunc<mode>df2_odd"
   [(set (match_operand:DF 0 "vsx_register_operand" "=v")
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/doc)	(revision 231978)
+++ gcc/doc/extend.texi	(.../gcc/doc)	(working copy)
@@ -954,22 +954,20 @@  typedef _Complex float __attribute__((mo
 typedef _Complex float __attribute__((mode(XC))) _Complex80;
 @end smallexample
 
-On PowerPC Linux, Freebsd and Darwin systems, the default for
-@code{long double} is to use the IBM extended floating point format
-that uses a pair of @code{double} values to extend the precision.
-This means that the mode @code{TCmode} was already used by the
-traditional IBM long double format, and you would need to use the mode
-@code{KCmode}:
+On PowerPC 64-bit Linux systems there are currently problems in using
+the complex @code{__float128} type.  When these problems are fixed,
+you would use:
 
 @smallexample
 typedef _Complex float __attribute__((mode(KC))) _Complex128;
 @end smallexample
 
-Not all targets support additional floating-point types.  @code{__float80}
-and @code{__float128} types are supported on x86 and IA-64 targets.
-The @code{__float128} type is supported on hppa HP-UX.
-The @code{__float128} type is supported on PowerPC systems by default
-if the vector scalar instruction set (VSX) is enabled.
+Not all targets support additional floating-point types.
+@code{__float80} and @code{__float128} types are supported on x86 and
+IA-64 targets.  The @code{__float128} type is supported on hppa HP-UX.
+The @code{__float128} type is supported on PowerPC 64-bit Linux
+systems by default if the vector scalar instruction set (VSX) is
+enabled.
 
 On the PowerPC, @code{__ibm128} provides access to the IBM extended
 double format, and it is intended to be used by the library functions
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(.../svn+ssh://meissner@gcc.gnu.org/svn/gcc/trunk/gcc/doc)	(revision 231978)
+++ gcc/doc/invoke.texi	(.../gcc/doc)	(working copy)
@@ -19690,7 +19690,8 @@  hardware instructions.
 
 The VSX instruction set (@option{-mvsx}, @option{-mcpu=power7}, or
 @option{-mcpu=power8}) must be enabled to use the @option{-mfloat128}
-option.
+option.  The @code{-mfloat128} option only works on PowerPC 64-bit
+Linux systems.
 
 @item -mfloat128-hardware
 @itemx -mno-float128-hardware