There are 3 patches left in the basic IEEE 128-bit floating point support for
the compiler. I will submit these at the same time. They are split to make the
review process similar.  Patch #5 and #6 are indpendent of each other and can
be applied in either order. Patch #7 assumes that patches 1-6 have been
applied.

Patch #5 adds the following:
 * Support for the reload handlers that will be enabled in patch #7.
 * Adds IFmode/KFmode to other iterators as appropriate.
 * Adds the basic negate, absolute value, and negative absolute value support.
 * Adds the insns for the 128-bit pack/unpack routines.

Patch #6 adds the following:
 * Adds support for comparisons.
 * Updates the cannot change mode support.

Patch #7 finishes up the initial basic support.
 * It defines macros for IEEE 128-bit floating point users.
 * It defines the basic move support.
 * It sets up the calling sequence.
 * It registers the __float128 and __ibm128 keywords.
 * It sets up the various handler functions.
 * It adds 'q' and 'Q' as the suffix for IEEE 128-bit floating point.
 * It adds target attribute/pragma support for the IEEE 128-bit options.
 * It treats IEEE 128-bit in VSX register modes as vector.
 * It uses a unique mangling for IEEE 128-bit in VSX registers.
 * It moves vector modes tieable above scalar floating point.
 * It adds a simple minded test to make sure IEEE args are passed as vectors.

Things to be done:
 * Work with GDB to add debug support.
 * Work with GLIBC to add basic software emulation support.
 * Work with GLIBC on other IEEE 128-bit support.
 * Look into Complex support.
 * Look into libquadmath support.
 * Enable -mfloat128-software if -mvsx.
 * Add more tests.
 * Fix bugs that show up if -mabi=ieeelongdouble is used.

Each patch bootstraps without error and has no regressions. Are they ok to
install in the trunk?

This is patch #7:

[gcc]
2015-08-13  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define user
        macros for IEEE 128-bit floating point in VSX registers.

        * config/rs6000/rs6000.c (TARGET_C_MODE_FOR_SUFFIX): Add 'q' or
        'Q' as the suffix for IEEE 128-bit floating point in VSX
        registers.
        (rs6000_c_mode_for_suffix): Likewise.
        (rs6000_init_hard_regno_mode_ok): Set up IEEE 128-bit floating
        point in VSX register mode support.
        (rs6000_gen_le_vsx_permute): Use ROTATE instead of VEC_SELECT for
        IEEE 128-bit floating point in VSX registers.
        (init_cumulative_args): When calling the library support
        functions, suppress passing values to IEEE 128-bit floating point
        in VSX registers in both the GPRs and VSX registers.
        (rs6000_function_arg): Likewise.
        (rs6000_arg_partial_bytes): Likewise.
        (rs6000_init_builtins): Likewise.
        (init_float128_ibm): Split 128-bit floating point support into two
        functions, and add support for IEEE 128-bit floating point in VSX
        registers.
        (init_float128_ieee): Likewise.
        (rs6000_init_libfuncs): Likewise.
        (rs6000_mangle_type): Use U10__float128 as the mangled type for
        IEEE 128-bit floating point in VSX registers.
        (struct rs6000_opt_var): Fix typo.
        (struct rs6000_float128_var): Add target attribute and pragma
        support for the IEEE 128-bit floating point in VSX registers.
        (rs6000_float128_vars): Likewise.
        (rs6000_inner_target_options): Likewise.

        * config/rs6000/rs6000.h (ALTIVEC_VECTOR_MODE): Treat IEEE 128-bit
        floating point in vector registers as a vector type.
        (MODES_TIEABLE_P): Move vector tests above floating point scalar
        tests, so that IEEE 128-bit floating point in VSX registers ties
        like a vector operand and not a scalar floating point operand.
        (struct rs6000_args): Add libcall field to support IEEE 128-bit
        floating point in VSX registers.

        * doc/extend.texi (additional floating types): Document PowerPC
        use of __float128 and __ibm128 types.

        * doc/invoke.texi (RS/6000 and PowerPC Options): Document
        -mfloat128-software and -mfloat128-none.

[gcc/testsuite]
2015-08-13  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        * gcc.target/powerpc/float128-call.c: New function, test whether
        IEEE 128-bit floating point in VSX registers is passed correctly.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-c.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c        (revision 226838)
+++ gcc/config/rs6000/rs6000-c.c        (working copy)
@@ -410,6 +410,10 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi
     builtin_define ("__RSQRTE__");
   if (TARGET_FRSQRTES)
     builtin_define ("__RSQRTEF__");
+  if (TARGET_FLOAT128)
+    builtin_define ("__FLOAT128__");
+  if (TARGET_FLOAT128 == FLOAT128_SW)
+    builtin_define ("__FLOAT128_SOFTWARE__");
 
   if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM)
     {
@@ -483,6 +487,11 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi
     {
       builtin_define ("__LONG_DOUBLE_128__");
       builtin_define ("__LONGDOUBLE128");
+
+      if (TARGET_IEEEQUAD)
+       builtin_define ("__LONG_DOUBLE_IEEE128__");
+      else
+       builtin_define ("__LONG_DOUBLE_IBM128__");
     }
 
   switch (TARGET_CMODEL)
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 226872)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -1688,6 +1688,9 @@ static const struct attribute_spec rs600
 #define TARGET_LIBGCC_SHIFT_COUNT_MODE rs6000_abi_word_mode
 #undef TARGET_UNWIND_WORD_MODE
 #define TARGET_UNWIND_WORD_MODE rs6000_abi_word_mode
+
+#undef TARGET_C_MODE_FOR_SUFFIX
+#define TARGET_C_MODE_FOR_SUFFIX rs6000_c_mode_for_suffix
 
 
 /* Processor table.  */
@@ -2671,6 +2674,20 @@ rs6000_init_hard_regno_mode_ok (bool glo
       align32 = 128;
     }
 
+  /* KF mode (ieee 128-bit) where we can pass it as a vector.  We do not have
+     arithmetic, so only set the memory modes.  */
+  if (TARGET_FLOAT128)
+    {
+      rs6000_vector_mem[KFmode] = VECTOR_VSX;
+      rs6000_vector_align[KFmode] = 128;
+
+      if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
+       {
+         rs6000_vector_mem[TFmode] = VECTOR_VSX;
+         rs6000_vector_align[TFmode] = 128;
+       }
+    }
+
   /* V2DF mode, VSX only.  */
   if (TARGET_VSX)
     {
@@ -2887,6 +2904,8 @@ rs6000_init_hard_regno_mode_ok (bool glo
          reg_addr[V4SFmode].reload_load   = CODE_FOR_reload_v4sf_di_load;
          reg_addr[V2DFmode].reload_store  = CODE_FOR_reload_v2df_di_store;
          reg_addr[V2DFmode].reload_load   = CODE_FOR_reload_v2df_di_load;
+         reg_addr[KFmode].reload_store    = CODE_FOR_reload_kf_di_store;
+         reg_addr[KFmode].reload_load     = CODE_FOR_reload_kf_di_load;
          reg_addr[DFmode].reload_store    = CODE_FOR_reload_df_di_store;
          reg_addr[DFmode].reload_load     = CODE_FOR_reload_df_di_load;
          reg_addr[DDmode].reload_store    = CODE_FOR_reload_dd_di_store;
@@ -2894,6 +2913,12 @@ rs6000_init_hard_regno_mode_ok (bool glo
          reg_addr[SFmode].reload_store    = CODE_FOR_reload_sf_di_store;
          reg_addr[SFmode].reload_load     = CODE_FOR_reload_sf_di_load;
 
+         if (TARGET_IEEEQUAD && TARGET_FLOAT128)
+           {
+             reg_addr[TFmode].reload_store = CODE_FOR_reload_tf_di_store;
+             reg_addr[TFmode].reload_load  = CODE_FOR_reload_tf_di_load;
+           }
+
          /* Only provide a reload handler for SDmode if lfiwzx/stfiwx are
             available.  */
          if (TARGET_NO_SDMODE_STACK)
@@ -2947,6 +2972,8 @@ rs6000_init_hard_regno_mode_ok (bool glo
          reg_addr[V4SFmode].reload_load   = CODE_FOR_reload_v4sf_si_load;
          reg_addr[V2DFmode].reload_store  = CODE_FOR_reload_v2df_si_store;
          reg_addr[V2DFmode].reload_load   = CODE_FOR_reload_v2df_si_load;
+         reg_addr[KFmode].reload_store    = CODE_FOR_reload_kf_si_store;
+         reg_addr[KFmode].reload_load     = CODE_FOR_reload_kf_si_load;
          reg_addr[DFmode].reload_store    = CODE_FOR_reload_df_si_store;
          reg_addr[DFmode].reload_load     = CODE_FOR_reload_df_si_load;
          reg_addr[DDmode].reload_store    = CODE_FOR_reload_dd_si_store;
@@ -2954,6 +2981,12 @@ rs6000_init_hard_regno_mode_ok (bool glo
          reg_addr[SFmode].reload_store    = CODE_FOR_reload_sf_si_store;
          reg_addr[SFmode].reload_load     = CODE_FOR_reload_sf_si_load;
 
+         if (TARGET_IEEEQUAD && TARGET_FLOAT128)
+           {
+             reg_addr[TFmode].reload_store = CODE_FOR_reload_tf_si_store;
+             reg_addr[TFmode].reload_load  = CODE_FOR_reload_tf_si_load;
+           }
+
          /* Only provide a reload handler for SDmode if lfiwzx/stfiwx are
             available.  */
          if (TARGET_NO_SDMODE_STACK)
@@ -8421,8 +8454,14 @@ rs6000_const_vec (machine_mode mode)
 rtx
 rs6000_gen_le_vsx_permute (rtx source, machine_mode mode)
 {
-  rtx par = gen_rtx_PARALLEL (VOIDmode, rs6000_const_vec (mode));
-  return gen_rtx_VEC_SELECT (mode, source, par);
+  /* Use ROTATE instead of VEC_SELECT on IEEE 128-bit floating point.  */
+  if (FLOAT128_VECTOR_P (mode))
+    return gen_rtx_ROTATE (mode, source, GEN_INT (64));
+  else
+    {
+      rtx par = gen_rtx_PARALLEL (VOIDmode, rs6000_const_vec (mode));
+      return gen_rtx_VEC_SELECT (mode, source, par);
+    }
 }
 
 /* Emit a little-endian load from vector memory location SOURCE to VSX
@@ -9401,6 +9440,7 @@ init_cumulative_args (CUMULATIVE_ARGS *c
                      ? CALL_LIBCALL : CALL_NORMAL);
   cum->sysv_gregno = GP_ARG_MIN_REG;
   cum->stdarg = stdarg_p (fntype);
+  cum->libcall = libcall;
 
   cum->nargs_prototype = 0;
   if (incoming || cum->prototype)
@@ -10563,9 +10603,11 @@ rs6000_function_arg (cumulative_args_t c
       rtx r, off;
       int i, k = 0;
 
-      /* Do we also need to pass this argument in the parameter
-        save area?  */
-      if (TARGET_64BIT && ! cum->prototype)
+      /* Do we also need to pass this argument in the parameter save area?
+        Library support functions for IEEE 128-bit are assumed to not need the
+        value passed both in GPRs and in vector registers.  */
+      if (TARGET_64BIT && !cum->prototype
+         && (!cum->libcall || !FLOAT128_VECTOR_P (elt_mode)))
        {
          int align_words = (cum->words + 1) & ~1;
          k = rs6000_psave_function_arg (mode, type, align_words, rvec);
@@ -10796,11 +10838,14 @@ rs6000_arg_partial_bytes (cumulative_arg
 
   if (USE_ALTIVEC_FOR_ARG_P (cum, elt_mode, named))
     {
-      /* If we are passing this arg in the fixed parameter save area
-         (gprs or memory) as well as VRs, we do not use the partial
-        bytes mechanism; instead, rs6000_function_arg will return a
-        PARALLEL including a memory element as necessary.  */
-      if (TARGET_64BIT && ! cum->prototype)
+      /* If we are passing this arg in the fixed parameter save area (gprs or
+         memory) as well as VRs, we do not use the partial bytes mechanism;
+         instead, rs6000_function_arg will return a PARALLEL including a memory
+         element as necessary.  Library support functions for IEEE 128-bit are
+         assumed to not need the value passed both in GPRs and in vector
+         registers.  */
+      if (TARGET_64BIT && !cum->prototype
+         && (!cum->libcall || !FLOAT128_VECTOR_P (elt_mode)))
        return 0;
 
       /* Otherwise, we pass in VRs only.  Check for partial copies.  */
@@ -14480,6 +14525,14 @@ rs6000_init_builtins (void)
   layout_type (ibm128_float_type_node);
   SET_TYPE_MODE (ibm128_float_type_node, ibm128_mode);
 
+  if (TARGET_FLOAT128)
+    {
+      lang_hooks.types.register_builtin_type (ieee128_float_type_node,
+                                             "__float128");
+      lang_hooks.types.register_builtin_type (ibm128_float_type_node,
+                                             "__ibm128");
+    }
+
   /* Initialize the modes for builtin_function_type, mapping a machine mode to
      tree type node.  */
   builtin_mode_to_type[QImode][0] = integer_type_node;
@@ -15984,78 +16037,150 @@ rs6000_common_init_builtins (void)
     }
 }
 
+/* Set up AIX/Darwin/64-bit Linux quad floating point routines.  */
 static void
-rs6000_init_libfuncs (void)
+init_float128_ibm (machine_mode mode)
 {
-  if (!TARGET_IEEEQUAD)
-      /* AIX/Darwin/64-bit Linux quad floating point routines.  */
-    if (!TARGET_XL_COMPAT)
-      {
-       set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
-       set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
-       set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
-       set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
+  if (!TARGET_XL_COMPAT)
+    {
+      set_optab_libfunc (add_optab, mode, "__gcc_qadd");
+      set_optab_libfunc (sub_optab, mode, "__gcc_qsub");
+      set_optab_libfunc (smul_optab, mode, "__gcc_qmul");
+      set_optab_libfunc (sdiv_optab, mode, "__gcc_qdiv");
 
-       if (!(TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)))
-         {
-           set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg");
-           set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq");
-           set_optab_libfunc (ne_optab, TFmode, "__gcc_qne");
-           set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt");
-           set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
-           set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
-           set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
-
-           set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
-           set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
-           set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos");
-           set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod");
-           set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi");
-           set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou");
-           set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
-           set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
-         }
+      if (!(TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)))
+       {
+         set_optab_libfunc (neg_optab, mode, "__gcc_qneg");
+         set_optab_libfunc (eq_optab, mode, "__gcc_qeq");
+         set_optab_libfunc (ne_optab, mode, "__gcc_qne");
+         set_optab_libfunc (gt_optab, mode, "__gcc_qgt");
+         set_optab_libfunc (ge_optab, mode, "__gcc_qge");
+         set_optab_libfunc (lt_optab, mode, "__gcc_qlt");
+         set_optab_libfunc (le_optab, mode, "__gcc_qle");
 
-       if (!(TARGET_HARD_FLOAT && TARGET_FPRS))
-         set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
-      }
-    else
-      {
-       set_optab_libfunc (add_optab, TFmode, "_xlqadd");
-       set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
-       set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
-       set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
-      }
+         set_conv_libfunc (sext_optab, mode, SFmode, "__gcc_stoq");
+         set_conv_libfunc (sext_optab, mode, DFmode, "__gcc_dtoq");
+         set_conv_libfunc (trunc_optab, SFmode, mode, "__gcc_qtos");
+         set_conv_libfunc (trunc_optab, DFmode, mode, "__gcc_qtod");
+         set_conv_libfunc (sfix_optab, SImode, mode, "__gcc_qtoi");
+         set_conv_libfunc (ufix_optab, SImode, mode, "__gcc_qtou");
+         set_conv_libfunc (sfloat_optab, mode, SImode, "__gcc_itoq");
+         set_conv_libfunc (ufloat_optab, mode, SImode, "__gcc_utoq");
+       }
+
+      if (!(TARGET_HARD_FLOAT && TARGET_FPRS))
+       set_optab_libfunc (unord_optab, mode, "__gcc_qunord");
+    }
   else
     {
-      /* 32-bit SVR4 quad floating point routines.  */
+      set_optab_libfunc (add_optab, mode, "_xlqadd");
+      set_optab_libfunc (sub_optab, mode, "_xlqsub");
+      set_optab_libfunc (smul_optab, mode, "_xlqmul");
+      set_optab_libfunc (sdiv_optab, mode, "_xlqdiv");
+    }
+}
+
+/* Set up IEEE 128-bit floating point routines.  Use different names if the
+   arguments can be passed in a vector register.  The historical PowerPC
+   implementation of IEEE 128-bit floating point used _q_<op> for the names, so
+   continue to use that if we can't pass IEEE 128-bit in a VSX vector register.
 
-      set_optab_libfunc (add_optab, TFmode, "_q_add");
-      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
-      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
-      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
-      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
+   Add _vector to clarify that this function is called with the argument in a
+   vector register, and _fpr when we are not passing IEEE 128-bit in a vector
+   register.  */
+
+static void
+init_float128_ieee (machine_mode mode)
+{
+  if (FLOAT128_VECTOR_P (mode))
+    {
+      set_optab_libfunc (add_optab, mode, "__addkf3");
+      set_optab_libfunc (sub_optab, mode, "__subkf3");
+      set_optab_libfunc (neg_optab, mode, "__negkf2");
+      set_optab_libfunc (smul_optab, mode, "__mulkf3");
+      set_optab_libfunc (sdiv_optab, mode, "__divkf3");
+      set_optab_libfunc (sqrt_optab, mode, "__sqrtkf2");
+      set_optab_libfunc (abs_optab, mode, "__abstkf2");
+
+      set_optab_libfunc (eq_optab, mode, "__eqkf2");
+      set_optab_libfunc (ne_optab, mode, "__nekf2");
+      set_optab_libfunc (gt_optab, mode, "__gtkf2");
+      set_optab_libfunc (ge_optab, mode, "__gekf2");
+      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, "__cmpkf2");
+
+      set_conv_libfunc (sext_optab, mode, SFmode, "__extendsfkf2");
+      set_conv_libfunc (sext_optab, mode, DFmode, "__extenddfkf2");
+      set_conv_libfunc (trunc_optab, SFmode, mode, "__trunckfsf2");
+      set_conv_libfunc (trunc_optab, DFmode, mode, "__trunckfdf2");
+
+      set_conv_libfunc (sfix_optab, SImode, mode, "__fixkfsi");
+      set_conv_libfunc (ufix_optab, SImode, mode, "__fixunskfsi");
+      set_conv_libfunc (sfix_optab, DImode, mode, "__fixkfdi");
+      set_conv_libfunc (ufix_optab, DImode, mode, "__fixunskfdi");
+
+      set_conv_libfunc (sfloat_optab, mode, SImode, "__floatsikf");
+      set_conv_libfunc (ufloat_optab, mode, SImode, "__floatunsikf");
+      set_conv_libfunc (sfloat_optab, mode, DImode, "__floatdikf");
+      set_conv_libfunc (ufloat_optab, mode, DImode, "__floatundikf");
+
+      if (mode == KFmode)
+       {
+         set_conv_libfunc (sext_optab, IFmode, KFmode, "__extendkftf2");
+         set_conv_libfunc (trunc_optab, KFmode, IFmode, "__trunctfkf2");
+
+         if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
+           {
+             set_conv_libfunc (sext_optab, TFmode, KFmode, "__extendkftf2");
+             set_conv_libfunc (trunc_optab, mode, KFmode, "__trunctfkf2");
+           }
+       }
+    }
+
+  else
+    {
+      set_optab_libfunc (add_optab, mode, "_q_add");
+      set_optab_libfunc (sub_optab, mode, "_q_sub");
+      set_optab_libfunc (neg_optab, mode, "_q_neg");
+      set_optab_libfunc (smul_optab, mode, "_q_mul");
+      set_optab_libfunc (sdiv_optab, mode, "_q_div");
       if (TARGET_PPC_GPOPT)
-       set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
+       set_optab_libfunc (sqrt_optab, mode, "_q_sqrt");
 
-      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
-      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
-      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
-      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
-      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
-      set_optab_libfunc (le_optab, TFmode, "_q_fle");
-
-      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
-      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
-      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
-      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
-      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
-      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
-      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
-      set_conv_libfunc (ufloat_optab, TFmode, SImode, "_q_utoq");
+      set_optab_libfunc (eq_optab, mode, "_q_feq");
+      set_optab_libfunc (ne_optab, mode, "_q_fne");
+      set_optab_libfunc (gt_optab, mode, "_q_fgt");
+      set_optab_libfunc (ge_optab, mode, "_q_fge");
+      set_optab_libfunc (lt_optab, mode, "_q_flt");
+      set_optab_libfunc (le_optab, mode, "_q_fle");
+
+      set_conv_libfunc (sext_optab, mode, SFmode, "_q_stoq");
+      set_conv_libfunc (sext_optab, mode, DFmode, "_q_dtoq");
+      set_conv_libfunc (trunc_optab, SFmode, mode, "_q_qtos");
+      set_conv_libfunc (trunc_optab, DFmode, mode, "_q_qtod");
+      set_conv_libfunc (sfix_optab, SImode, mode, "_q_qtoi");
+      set_conv_libfunc (ufix_optab, SImode, mode, "_q_qtou");
+      set_conv_libfunc (sfloat_optab, mode, SImode, "_q_itoq");
+      set_conv_libfunc (ufloat_optab, mode, SImode, "_q_utoq");
     }
 }
 
+static void
+rs6000_init_libfuncs (void)
+{
+  /* AIX/Darwin/64-bit Linux quad floating point routines.  */
+  init_float128_ibm (IFmode);
+  if (!TARGET_IEEEQUAD)
+    init_float128_ibm (TFmode);
+
+  /* IEEE 128-bit including 32-bit SVR4 quad floating point routines.  */
+  init_float128_ieee (KFmode);
+  if (TARGET_IEEEQUAD)
+    init_float128_ieee (TFmode);
+}
+
 
 /* Expand a block clear operation, and return 1 if successful.  Return 0
    if we should let the compiler generate normal code.
@@ -29763,9 +29888,13 @@ rs6000_mangle_type (const_tree type)
   if (type == bool_int_type_node) return "U6__booli";
   if (type == bool_long_type_node) return "U6__booll";
 
+  /* Use a unique name for __float128 rather than trying to use "e" or "g".  */
+  if (type == ieee128_float_type_node && TARGET_FLOAT128)
+    return "U10__float128";
+
   /* Mangle IBM extended float long double as `g' (__float128) on
      powerpc*-linux where long-double-64 previously was the default.  */
-  if (TYPE_MAIN_VARIANT (type) == long_double_type_node
+  if (type == long_double_type_node
       && TARGET_ELF
       && TARGET_LONG_DOUBLE_128
       && !TARGET_IEEEQUAD)
@@ -33014,6 +33143,26 @@ rs6000_vector_mode_supported_p (machine_
     return false;
 }
 
+/* Target hook for c_mode_for_suffix.  */
+static machine_mode
+rs6000_c_mode_for_suffix (char suffix)
+{
+  if (TARGET_FLOAT128 && TARGET_LONG_DOUBLE_128)
+    {
+      if (suffix == 'q' || suffix == 'Q')
+       return (TARGET_IEEEQUAD) ? TFmode : KFmode;
+
+      /* At the moment, we are not defining a suffix for IBM extended double.
+        If/when the default for -mabi=ieeelongdouble is changed, and we want
+        to support __ibm128 constants in legacy library code, we may need to
+        re-evalaute this decision.  Currently, c-lex.c only supports 'w' and
+        'q' as machine dependent suffixes.  The x86_64 port uses 'w' for
+        __float80 constants.  */
+    }
+
+  return VOIDmode;
+}
+
 /* Target hook for invalid_arg_for_unprototyped_fn. */
 static const char *
 invalid_arg_for_unprototyped_fn (const_tree typelist, const_tree funcdecl, 
const_tree val)
@@ -33175,7 +33324,7 @@ static struct rs6000_opt_mask const rs60
 struct rs6000_opt_var {
   const char *name;            /* option name */
   size_t global_offset;                /* offset of the option in 
global_options.  */
-  size_t target_offset;                /* offset of the option in target 
optiosn.  */
+  size_t target_offset;                /* offset of the option in target 
options.  */
 };
 
 static struct rs6000_opt_var const rs6000_opt_vars[] =
@@ -33230,6 +33379,21 @@ static struct rs6000_opt_var const rs600
     offsetof (struct cl_target_option, x_rs6000_warn_cell_microcode), },
 };
 
+/* Float128 options we want to support inside attribute((target)) and #pragma
+   GCC target operations.  */
+
+struct rs6000_float128_var {
+  const char *name;            /* option name.  */
+  enum float128_type_t type;   /* float128 type.  */
+};
+
+static struct rs6000_float128_var const rs6000_float128_vars[] =
+{
+  { "float128-none",           FLOAT128_NONE },
+  { "float128-software",       FLOAT128_SW },
+  { "float128-sw",             FLOAT128_SW },
+};
+
 /* Inner function to handle attribute((target("..."))) and #pragma GCC target
    parsing.  Return true if there were no errors.  */
 
@@ -33322,6 +33486,18 @@ rs6000_inner_target_options (tree args, 
                    break;
                  }
 
+             if (error_p && !not_valid_p && !invert)
+               {
+                 for (i = 0; i < ARRAY_SIZE (rs6000_float128_vars); i++)
+                   if (strcmp (r, rs6000_float128_vars[i].name) == 0)
+                     {
+                       TARGET_FLOAT128 = rs6000_float128_vars[i].type;
+                       error_p = false;
+                       not_valid_p = false;
+                       break;
+                     }
+               }
+
              if (error_p && !not_valid_p)
                {
                  for (i = 0; i < ARRAY_SIZE (rs6000_opt_vars); i++)
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h  (revision 226838)
+++ gcc/config/rs6000/rs6000.h  (working copy)
@@ -1217,11 +1217,16 @@ enum data_align { align_abi, align_opt, 
         ((MODE) == V4SFmode            \
          || (MODE) == V2DFmode)        \
 
-#define ALTIVEC_VECTOR_MODE(MODE)      \
-        ((MODE) == V16QImode           \
-         || (MODE) == V8HImode         \
-         || (MODE) == V4SFmode         \
-         || (MODE) == V4SImode)
+/* Note KFmode and possibly TFmode (i.e. IEEE 128-bit floating point) are not
+   really a vector, but we want to treat it as a vector for moves, and
+   such.  */
+
+#define ALTIVEC_VECTOR_MODE(MODE)                                      \
+  ((MODE) == V16QImode                                                 \
+   || (MODE) == V8HImode                                               \
+   || (MODE) == V4SFmode                                               \
+   || (MODE) == V4SImode                                               \
+   || FLOAT128_VECTOR_P (MODE))
 
 #define ALTIVEC_OR_VSX_VECTOR_MODE(MODE)                               \
   (ALTIVEC_VECTOR_MODE (MODE) || VSX_VECTOR_MODE (MODE)                        
\
@@ -1248,12 +1253,19 @@ enum data_align { align_abi, align_opt, 
 
    PTImode cannot tie with other modes because PTImode is restricted to even
    GPR registers, and TImode can go in any GPR as well as VSX registers (PR
-   57744).  */
+   57744).
+
+   Altivec/VSX vector tests were moved ahead of scalar float mode, so that IEEE
+   128-bit floating point on VSX systems ties with other vectors.  */
 #define MODES_TIEABLE_P(MODE1, MODE2)          \
   ((MODE1) == PTImode                          \
    ? (MODE2) == PTImode                                \
    : (MODE2) == PTImode                                \
    ? 0                                         \
+   : ALTIVEC_OR_VSX_VECTOR_MODE (MODE1)                \
+   ? ALTIVEC_OR_VSX_VECTOR_MODE (MODE2)                \
+   : ALTIVEC_OR_VSX_VECTOR_MODE (MODE2)                \
+   ? 0                                         \
    : SCALAR_FLOAT_MODE_P (MODE1)               \
    ? SCALAR_FLOAT_MODE_P (MODE2)               \
    : SCALAR_FLOAT_MODE_P (MODE2)               \
@@ -1266,10 +1278,6 @@ enum data_align { align_abi, align_opt, 
    ? SPE_VECTOR_MODE (MODE2)                   \
    : SPE_VECTOR_MODE (MODE2)                   \
    ? 0                                         \
-   : ALTIVEC_OR_VSX_VECTOR_MODE (MODE1)                \
-   ? ALTIVEC_OR_VSX_VECTOR_MODE (MODE2)                \
-   : ALTIVEC_OR_VSX_VECTOR_MODE (MODE2)                \
-   ? 0                                         \
    : 1)
 
 /* Post-reload, we can't use any new AltiVec registers, as we already
@@ -1801,6 +1809,7 @@ typedef struct rs6000_args
                                   GPR space (darwin64) */
   int named;                   /* false for varargs params */
   int escapes;                 /* if function visible outside tu */
+  int libcall;                 /* If this is a compiler generated call.  */
 } CUMULATIVE_ARGS;
 
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 226838)
+++ gcc/doc/extend.texi (working copy)
@@ -929,6 +929,7 @@ examine and set these two fictitious var
 @cindex additional floating types
 @cindex @code{__float80} data type
 @cindex @code{__float128} data type
+@cindex @code{__ibm128} data type
 @cindex @code{w} floating point suffix
 @cindex @code{q} floating point suffix
 @cindex @code{W} floating point suffix
@@ -941,19 +942,39 @@ Support for additional types includes th
 add, subtract, multiply, divide; unary arithmetic operators;
 relational operators; equality operators; and conversions to and from
 integer and other floating types.  Use a suffix @samp{w} or @samp{W}
-in a literal constant of type @code{__float80} and @samp{q} or @samp{Q}
-for @code{_float128}.  You can declare complex types using the
-corresponding internal complex type, @code{XCmode} for @code{__float80}
-type and @code{TCmode} for @code{__float128} type:
+in a literal constant of type @code{__float80} or type
+@code{__ibm128}.  Use a suffix @samp{q} or @samp{Q} for @code{_float128}.
+
+On the i386, x86_64, IA-64, and HP-UX targets, you can declare complex
+types using the corresponding internal complex type, @code{XCmode} for
+@code{__float80} type and @code{TCmode} for @code{__float128} type:
 
 @smallexample
 typedef _Complex float __attribute__((mode(TC))) _Complex128;
 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}:
+
+@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 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.
+
+On the PowerPC, @code{__ibm128} provides access to the IBM extended
+double format, and it is intended to be used by the library functions
+that handle conversions if/when long double is changed to be IEEE
+128-bit floating point.
 
 @node Half-Precision
 @section Half-Precision Floating Point
@@ -13318,6 +13339,8 @@ uint64_t __builtin_ppc_get_timebase ();
 unsigned long __builtin_ppc_mftb ();
 double __builtin_unpack_longdouble (long double, int);
 long double __builtin_pack_longdouble (double, double);
+double __builtin_unpack_ibm128 (long double, int);
+__ibm128 __builtin_pack_ibm128 (double, double);
 @end smallexample
 
 The @code{vec_rsqrt}, @code{__builtin_rsqrt}, and
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi (revision 226838)
+++ gcc/doc/invoke.texi (working copy)
@@ -940,7 +940,8 @@ See RS/6000 and PowerPC Options.
 -mquad-memory-atomic -mno-quad-memory-atomic @gol
 -mcompat-align-parm -mno-compat-align-parm @gol
 -mupper-regs-df -mno-upper-regs-df -mupper-regs-sf -mno-upper-regs-sf @gol
--mupper-regs -mno-upper-regs}
+-mupper-regs -mno-upper-regs @gol
+-mfloat128-software -mfloat128-none}
 
 @emph{RX Options}
 @gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
@@ -19410,6 +19411,20 @@ floating point register set, depending o
 If the @option{-mno-upper-regs} option is used, it turns off both
 @option{-mupper-regs-sf} and @option{-mupper-regs-df} options.
 
+@item -mfloat128-software
+@opindex mfloat128-software
+Enable the @var{__float128} keyword for IEEE 128-bit floating point
+and use software emulation for IEEE 128-bit floating point.
+@option{-mfloat128-software} option is enabled by default with either
+of the the @option{-mcpu=power7} or @option{-mcpu=power8} options.
+
+The VSX instruction set must be enabled to use the
+@option{-mfloat128-software} option.
+
+@item -mfloat128-none
+@opindex mfloat128-none
+Disable the use of the @var{__float128} keyword.
+
 @item -mfloat-gprs=@var{yes/single/double/no}
 @itemx -mfloat-gprs
 @opindex mfloat-gprs
Index: gcc/testsuite/gcc.target/powerpc/float128-call.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-call.c    (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/float128-call.c    (revision 0)
@@ -0,0 +1,27 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { 
"-mcpu=power7" } } */
+/* { dg-options "-O2 -mcpu=power7 -mfloat128-software -mno-regnames" } */
+
+#ifndef __FLOAT128_SOFTWARE__
+#error "-mfloat128-software is not supported."
+#endif
+
+#ifdef __LONG_DOUBLE_IEEE128__
+#define TYPE long double
+#define ONE  1.0L
+
+#else
+#define TYPE __float128
+#define ONE  1.0Q
+#endif
+
+/* Test to make sure vector registers are used for passing IEEE 128-bit
+   floating point values and returning them. Also make sure the 'q' suffix is
+   handled.  */
+TYPE one (void) { return ONE; }
+void store (TYPE a, TYPE *p) { *p = a; }
+
+/* { dg-final { scan-assembler "lxvd2x 34"  } } */
+/* { dg-final { scan-assembler "stxvd2x 34" } } */

Reply via email to