diff mbox

Backport PowerPC complex __float128 compiler support to GCC 6.x

Message ID 20160603133335.GA28522@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner June 3, 2016, 1:33 p.m. UTC
These patches were installed on the trunk on May 2nd, with a fix from Alan
Modra on May 11th.  Unless I here objections in the next few days, I will
commit these changes to the GCC 6.x branch.  These changes will allow people to
use complex __float128 types (via an attribute) on the PowerPC.

Note, we will need patches to libgcc to fully enable complex __float128 support
on the PowerPC.  These patches enable the compiler support, so that the libgcc
changes can be coded.

In addition to bootstrapping and regtesting on the PowerPC (little endian
power8), I also bootstrapped and regested the changes on x86_64 running RHEL
6.2.  There were no regressions in either case.

[gcc]
2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>

	Back port from trunk
	2016-05-11  Alan Modra  <amodra@gmail.com>

	* config/rs6000/rs6000.c (is_complex_IBM_long_double,
	abi_v4_pass_in_fpr): New functions.
	(rs6000_function_arg_boundary): Exclude complex IBM long double
	from 64-bit alignment when ABI_V4.
	(rs6000_function_arg, rs6000_function_arg_advance_1,
	rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.

	Back port from trunk
	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* machmode.h (mode_complex): Add support to give the complex mode
	for a given mode.
	(GET_MODE_COMPLEX_MODE): Likewise.
	* stor-layout.c (layout_type): For COMPLEX_TYPE, use the mode
	stored by build_complex_type and gfc_build_complex_type instead of
	trying to figure out the appropriate mode based on the size. Raise
	an assertion error, if the type was not set.
	* genmodes.c (struct mode_data): Add field for the complex type of
	the given type.
	(blank_mode): Likewise.
	(make_complex_modes): Remember the complex mode created in the
	base type.
	(emit_mode_complex): Write out the mode_complex array to map a
	type mode to the complex version.
	(emit_insn_modes_c): Likewise.
	* tree.c (build_complex_type): Set the complex type to use before
	calling layout_type.
	* config/rs6000/rs6000.c (rs6000_hard_regno_nregs_internal): Add
	support for __float128 complex datatypes.
	(rs6000_hard_regno_mode_ok): Likewise.
	(rs6000_setup_reg_addr_masks): Likewise.
	(rs6000_complex_function_value): Likewise.
	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Likewise.
	__float128 and __ibm128 complex.
	(FLOAT128_IBM_P): Likewise.
	(ALTIVEC_ARG_MAX_RETURN): Likewise.
	* doc/extend.texi (Additional Floating Types): Document that
	-mfloat128 must be used to enable __float128.  Document complex
	__float128 and __ibm128 support.

[gcc/fortran]
2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>

	Back port from trunk
	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* trans-types.c (gfc_build_complex_type):

[gcc/testsuite]
2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>

	Back port from trunk
	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* gcc.target/powerpc/float128-complex-1.c: New tests for complex
	__float128.
	* gcc.target/powerpc/float128-complex-2.c: Likewise.

Comments

Michael Meissner June 9, 2016, 8:06 p.m. UTC | #1
I'm including the global reviewers on the list.  I just want to be sure that
there is no problem installing these patches on the GCC 6.2 branch.  While it
is technically an enchancement, it is needed to be able to install the glibc
support that is needed to complete the work to add IEEE 128-bit floating point.

The issue being fixed is that when we are creating the complex type, we used to
do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
floating point types (__ibm128 and __float128, with long double currently
defaulting to __ibm128).

On Fri, Jun 03, 2016 at 09:33:35AM -0400, Michael Meissner wrote:
> These patches were installed on the trunk on May 2nd, with a fix from Alan
> Modra on May 11th.  Unless I here objections in the next few days, I will
> commit these changes to the GCC 6.x branch.  These changes will allow people to
> use complex __float128 types (via an attribute) on the PowerPC.
> 
> Note, we will need patches to libgcc to fully enable complex __float128 support
> on the PowerPC.  These patches enable the compiler support, so that the libgcc
> changes can be coded.
> 
> In addition to bootstrapping and regtesting on the PowerPC (little endian
> power8), I also bootstrapped and regested the changes on x86_64 running RHEL
> 6.2.  There were no regressions in either case.
> 
> [gcc]
> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	Back port from trunk
> 	2016-05-11  Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/rs6000.c (is_complex_IBM_long_double,
> 	abi_v4_pass_in_fpr): New functions.
> 	(rs6000_function_arg_boundary): Exclude complex IBM long double
> 	from 64-bit alignment when ABI_V4.
> 	(rs6000_function_arg, rs6000_function_arg_advance_1,
> 	rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.
> 
> 	Back port from trunk
> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	* machmode.h (mode_complex): Add support to give the complex mode
> 	for a given mode.
> 	(GET_MODE_COMPLEX_MODE): Likewise.
> 	* stor-layout.c (layout_type): For COMPLEX_TYPE, use the mode
> 	stored by build_complex_type and gfc_build_complex_type instead of
> 	trying to figure out the appropriate mode based on the size. Raise
> 	an assertion error, if the type was not set.
> 	* genmodes.c (struct mode_data): Add field for the complex type of
> 	the given type.
> 	(blank_mode): Likewise.
> 	(make_complex_modes): Remember the complex mode created in the
> 	base type.
> 	(emit_mode_complex): Write out the mode_complex array to map a
> 	type mode to the complex version.
> 	(emit_insn_modes_c): Likewise.
> 	* tree.c (build_complex_type): Set the complex type to use before
> 	calling layout_type.
> 	* config/rs6000/rs6000.c (rs6000_hard_regno_nregs_internal): Add
> 	support for __float128 complex datatypes.
> 	(rs6000_hard_regno_mode_ok): Likewise.
> 	(rs6000_setup_reg_addr_masks): Likewise.
> 	(rs6000_complex_function_value): Likewise.
> 	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Likewise.
> 	__float128 and __ibm128 complex.
> 	(FLOAT128_IBM_P): Likewise.
> 	(ALTIVEC_ARG_MAX_RETURN): Likewise.
> 	* doc/extend.texi (Additional Floating Types): Document that
> 	-mfloat128 must be used to enable __float128.  Document complex
> 	__float128 and __ibm128 support.
> 
> [gcc/fortran]
> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	Back port from trunk
> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	* trans-types.c (gfc_build_complex_type):
> 
> [gcc/testsuite]
> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	Back port from trunk
> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	* gcc.target/powerpc/float128-complex-1.c: New tests for complex
> 	__float128.
> 	* gcc.target/powerpc/float128-complex-2.c: Likewise.
> 
> -- 
> Michael Meissner, IBM
> IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
> email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797

> Index: gcc/machmode.h
> ===================================================================
> --- gcc/machmode.h	(revision 237045)
> +++ gcc/machmode.h	(working copy)
> @@ -269,6 +269,10 @@ extern const unsigned char mode_wider[NU
>  extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
>  #define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
> 
> +/* Get the complex mode from the component mode.  */
> +extern const unsigned char mode_complex[NUM_MACHINE_MODES];
> +#define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE])
> +
>  /* Return the mode for data of a given size SIZE and mode class CLASS.
>     If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
>     The value is BLKmode if no other mode is found.  */
> Index: gcc/stor-layout.c
> ===================================================================
> --- gcc/stor-layout.c	(revision 237045)
> +++ gcc/stor-layout.c	(working copy)
> @@ -2146,11 +2146,13 @@ layout_type (tree type)
> 
>      case COMPLEX_TYPE:
>        TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
> -      SET_TYPE_MODE (type,
> -		     mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)),
> -				    (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
> -				     ? MODE_COMPLEX_FLOAT : MODE_COMPLEX_INT),
> -				     0));
> +
> +      /* build_complex_type and fortran's gfc_build_complex_type have set the
> +	 expected mode to allow having multiple complex types for multiple
> +	 floating point types that have the same size such as the PowerPC with
> +	 __ibm128 and __float128.  */
> +      gcc_assert (TYPE_MODE (type) != VOIDmode);
> +
>        TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
>        TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
>        break;
> Index: gcc/genmodes.c
> ===================================================================
> --- gcc/genmodes.c	(revision 237045)
> +++ gcc/genmodes.c	(working copy)
> @@ -66,6 +66,7 @@ struct mode_data
>  				   this mode as a component.  */
>    struct mode_data *next_cont;  /* Next mode in that list.  */
> 
> +  struct mode_data *complex;	/* complex type with mode as component.  */
>    const char *file;		/* file and line of definition, */
>    unsigned int line;		/* for error reporting */
>    unsigned int counter;		/* Rank ordering of modes */
> @@ -83,7 +84,7 @@ static struct mode_data *void_mode;
>  static const struct mode_data blank_mode = {
>    0, "<unknown>", MAX_MODE_CLASS,
>    -1U, -1U, -1U, -1U,
> -  0, 0, 0, 0, 0,
> +  0, 0, 0, 0, 0, 0,
>    "<unknown>", 0, 0, 0, 0, false, 0
>  };
> 
> @@ -472,6 +473,7 @@ make_complex_modes (enum mode_class cl,
> 
>        c = new_mode (cclass, buf, file, line);
>        c->component = m;
> +      m->complex = c;
>      }
>  }
> 
> @@ -1381,6 +1383,22 @@ emit_mode_wider (void)
>  }
> 
>  static void
> +emit_mode_complex (void)
> +{
> +  int c;
> +  struct mode_data *m;
> +
> +  print_decl ("unsigned char", "mode_complex", "NUM_MACHINE_MODES");
> +
> +  for_all_modes (c, m)
> +    tagged_printf ("%smode",
> +		   m->complex ? m->complex->name : void_mode->name,
> +		   m->name);
> +
> +  print_closer ();
> +}
> +
> +static void
>  emit_mode_mask (void)
>  {
>    int c;
> @@ -1745,6 +1763,7 @@ emit_insn_modes_c (void)
>    emit_mode_size ();
>    emit_mode_nunits ();
>    emit_mode_wider ();
> +  emit_mode_complex ();
>    emit_mode_mask ();
>    emit_mode_inner ();
>    emit_mode_unit_size ();
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c	(revision 237045)
> +++ gcc/tree.c	(working copy)
> @@ -8675,6 +8675,7 @@ build_complex_type (tree component_type)
>    t = make_node (COMPLEX_TYPE);
> 
>    TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
> +  SET_TYPE_MODE (t, GET_MODE_COMPLEX_MODE (TYPE_MODE (component_type)));
> 
>    /* If we already have such a type, use the old one.  */
>    hstate.add_object (TYPE_HASH (component_type));
> Index: gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc/config/rs6000/rs6000.c	(revision 237045)
> +++ gcc/config/rs6000/rs6000.c	(working copy)
> @@ -1882,7 +1882,7 @@ rs6000_hard_regno_nregs_internal (int re
>       128-bit floating point that can go in vector registers, which has VSX
>       memory addressing.  */
>    if (FP_REGNO_P (regno))
> -    reg_size = (VECTOR_MEM_VSX_P (mode)
> +    reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode)
>  		? UNITS_PER_VSX_WORD
>  		: UNITS_PER_FP_WORD);
> 
> @@ -1914,6 +1914,9 @@ rs6000_hard_regno_mode_ok (int regno, ma
>  {
>    int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1;
> 
> +  if (COMPLEX_MODE_P (mode))
> +    mode = GET_MODE_INNER (mode);
> +
>    /* PTImode can only go in GPRs.  Quad word memory operations require even/odd
>       register combinations, and use PTImode where we need to deal with quad
>       word memory operations.  Don't allow quad words in the argument or frame
> @@ -2716,8 +2719,17 @@ rs6000_setup_reg_addr_masks (void)
> 
>    for (m = 0; m < NUM_MACHINE_MODES; ++m)
>      {
> -      machine_mode m2 = (machine_mode)m;
> -      unsigned short msize = GET_MODE_SIZE (m2);
> +      machine_mode m2 = (machine_mode) m;
> +      bool complex_p = false;
> +      size_t msize;
> +
> +      if (COMPLEX_MODE_P (m2))
> +	{
> +	  complex_p = true;
> +	  m2 = GET_MODE_INNER (m2);
> +	}
> +
> +      msize = GET_MODE_SIZE (m2);
> 
>        /* SDmode is special in that we want to access it only via REG+REG
>  	 addressing on power7 and above, since we want to use the LFIWZX and
> @@ -2739,7 +2751,7 @@ rs6000_setup_reg_addr_masks (void)
>  	      /* Indicate if the mode takes more than 1 physical register.  If
>  		 it takes a single register, indicate it can do REG+REG
>  		 addressing.  */
> -	      if (nregs > 1 || m == BLKmode)
> +	      if (nregs > 1 || m == BLKmode || complex_p)
>  		addr_mask |= RELOAD_REG_MULTIPLE;
>  	      else
>  		addr_mask |= RELOAD_REG_INDEXED;
> @@ -2755,7 +2767,7 @@ rs6000_setup_reg_addr_masks (void)
>  		  && msize <= 8
>  		  && !VECTOR_MODE_P (m2)
>  		  && !FLOAT128_VECTOR_P (m2)
> -		  && !COMPLEX_MODE_P (m2)
> +		  && !complex_p
>  		  && (m2 != DFmode || !TARGET_UPPER_REGS_DF)
>  		  && (m2 != SFmode || !TARGET_UPPER_REGS_SF)
>  		  && !(TARGET_E500_DOUBLE && msize == 8))
> @@ -10266,6 +10278,35 @@ rs6000_must_pass_in_stack (machine_mode 
>      return must_pass_in_stack_var_size_or_pad (mode, type);
>  }
> 
> +static inline bool
> +is_complex_IBM_long_double (machine_mode mode)
> +{
> +  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
> +}
> +
> +/* Whether ABI_V4 passes MODE args to a function in floating point
> +   registers.  */
> +
> +static bool
> +abi_v4_pass_in_fpr (machine_mode mode)
> +{
> +  if (!TARGET_FPRS || !TARGET_HARD_FLOAT)
> +    return false;
> +  if (TARGET_SINGLE_FLOAT && mode == SFmode)
> +    return true;
> +  if (TARGET_DOUBLE_FLOAT && mode == DFmode)
> +    return true;
> +  /* ABI_V4 passes complex IBM long double in 8 gprs.
> +     Stupid, but we can't change the ABI now.  */
> +  if (is_complex_IBM_long_double (mode))
> +    return false;
> +  if (FLOAT128_2REG_P (mode))
> +    return true;
> +  if (DECIMAL_FLOAT_MODE_P (mode))
> +    return true;
> +  return false;
> +}
> +
>  /* If defined, a C expression which determines whether, and in which
>     direction, to pad out an argument with extra space.  The value
>     should be of type `enum direction': either `upward' to pad above
> @@ -10350,6 +10391,7 @@ rs6000_function_arg_boundary (machine_mo
>        && (GET_MODE_SIZE (mode) == 8
>  	  || (TARGET_HARD_FLOAT
>  	      && TARGET_FPRS
> +	      && !is_complex_IBM_long_double (mode)
>  	      && FLOAT128_2REG_P (mode))))
>      return 64;
>    else if (FLOAT128_VECTOR_P (mode))
> @@ -10729,11 +10771,7 @@ rs6000_function_arg_advance_1 (CUMULATIV
>      }
>    else if (DEFAULT_ABI == ABI_V4)
>      {
> -      if (TARGET_HARD_FLOAT && TARGET_FPRS
> -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
> -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
> -	      || FLOAT128_2REG_P (mode)
> -	      || DECIMAL_FLOAT_MODE_P (mode)))
> +      if (abi_v4_pass_in_fpr (mode))
>  	{
>  	  /* _Decimal128 must use an even/odd register pair.  This assumes
>  	     that the register number is odd when fregno is odd.  */
> @@ -11390,11 +11428,7 @@ rs6000_function_arg (cumulative_args_t c
> 
>    else if (abi == ABI_V4)
>      {
> -      if (TARGET_HARD_FLOAT && TARGET_FPRS
> -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
> -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
> -	      || FLOAT128_2REG_P (mode)
> -	      || DECIMAL_FLOAT_MODE_P (mode)))
> +      if (abi_v4_pass_in_fpr (mode))
>  	{
>  	  /* _Decimal128 must use an even/odd register pair.  This assumes
>  	     that the register number is odd when fregno is odd.  */
> @@ -12315,19 +12349,15 @@ rs6000_gimplify_va_arg (tree valist, tre
>    rsize = (size + 3) / 4;
>    align = 1;
> 
> -  if (TARGET_HARD_FLOAT && TARGET_FPRS
> -      && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode)
> -          || (TARGET_DOUBLE_FLOAT 
> -              && (TYPE_MODE (type) == DFmode 
> -		  || FLOAT128_2REG_P (TYPE_MODE (type))
> -		  || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))))))
> +  machine_mode mode = TYPE_MODE (type);
> +  if (abi_v4_pass_in_fpr (mode))
>      {
>        /* FP args go in FP registers, if present.  */
>        reg = fpr;
>        n_reg = (size + 7) / 8;
>        sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4;
>        sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4);
> -      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
> +      if (mode != SFmode && mode != SDmode)
>  	align = 8;
>      }
>    else
> @@ -12347,7 +12377,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>    addr = create_tmp_var (ptr_type_node, "addr");
> 
>    /*  AltiVec vectors never go in registers when -mabi=altivec.  */
> -  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
> +  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
>      align = 16;
>    else
>      {
> @@ -12368,7 +12398,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>  	}
>        /* _Decimal128 is passed in even/odd fpr pairs; the stored
>  	 reg number is 0 for f1, so we want to make it odd.  */
> -      else if (reg == fpr && TYPE_MODE (type) == TDmode)
> +      else if (reg == fpr && mode == TDmode)
>  	{
>  	  t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg),
>  		      build_int_cst (TREE_TYPE (reg), 1));
> @@ -12395,7 +12425,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>  	 FP register for 32-bit binaries.  */
>        if (TARGET_32BIT
>  	  && TARGET_HARD_FLOAT && TARGET_FPRS
> -	  && TYPE_MODE (type) == SDmode)
> +	  && mode == SDmode)
>  	t = fold_build_pointer_plus_hwi (t, size);
> 
>        gimplify_assign (addr, t, pre_p);
> @@ -18464,25 +18494,33 @@ rs6000_secondary_reload_memory (rtx addr
>      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX]
>  		 & ~RELOAD_REG_AND_M16);
> 
> -  else
> +  /* If the register allocator hasn't made up its mind yet on the register
> +     class to use, settle on defaults to use.  */
> +  else if (rclass == NO_REGS)
>      {
> -      if (TARGET_DEBUG_ADDR)
> -	fprintf (stderr,
> -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> -		 "class is not GPR, FPR, VMX\n",
> -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
> +      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_ANY]
> +		   & ~RELOAD_REG_AND_M16);
> 
> -      return -1;
> +      if ((addr_mask & RELOAD_REG_MULTIPLE) != 0)
> +	addr_mask &= ~(RELOAD_REG_INDEXED
> +		       | RELOAD_REG_PRE_INCDEC
> +		       | RELOAD_REG_PRE_MODIFY);
>      }
> 
> +  else
> +    addr_mask = 0;
> +
>    /* If the register isn't valid in this register class, just return now.  */
>    if ((addr_mask & RELOAD_REG_VALID) == 0)
>      {
>        if (TARGET_DEBUG_ADDR)
> -	fprintf (stderr,
> -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> -		 "not valid in class\n",
> -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
> +	{
> +	  fprintf (stderr,
> +		   "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> +		   "not valid in class\n",
> +		   GET_MODE_NAME (mode), reg_class_names[rclass]);
> +	  debug_rtx (addr);
> +	}
> 
>        return -1;
>      }
> @@ -19143,6 +19181,9 @@ rs6000_secondary_reload (bool in_p,
>  	fprintf (stderr, ", reload func = %s, extra cost = %d",
>  		 insn_data[sri->icode].name, sri->extra_cost);
> 
> +      else if (sri->extra_cost > 0)
> +	fprintf (stderr, ", extra cost = %d", sri->extra_cost);
> +
>        fputs ("\n", stderr);
>        debug_rtx (x);
>      }
> @@ -19553,6 +19594,16 @@ rs6000_preferred_reload_class (rtx x, en
>    machine_mode mode = GET_MODE (x);
>    bool is_constant = CONSTANT_P (x);
> 
> +  /* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred
> +     reload class for it.  */
> +  if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS)
> +      && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0)
> +    return NO_REGS;
> +
> +  if ((rclass == FLOAT_REGS || rclass == VSX_REGS)
> +      && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
> +    return NO_REGS;
> +
>    /* For VSX, see if we should prefer FLOAT_REGS or ALTIVEC_REGS.  Do not allow
>       the reloading of address expressions using PLUS into floating point
>       registers.  */
> @@ -19603,6 +19654,25 @@ rs6000_preferred_reload_class (rtx x, en
>        return NO_REGS;
>      }
> 
> +  /* If we haven't picked a register class, and the type is a vector or
> +     floating point type, prefer to use the VSX, FPR, or Altivec register
> +     classes.  */
> +  if (rclass == NO_REGS)
> +    {
> +      if (TARGET_VSX && VECTOR_MEM_VSX_OR_P8_VECTOR_P (mode))
> +	return VSX_REGS;
> +
> +      if (TARGET_ALTIVEC && VECTOR_MEM_ALTIVEC_P (mode))
> +	return ALTIVEC_REGS;
> +
> +      if (DECIMAL_FLOAT_MODE_P (mode))
> +	return TARGET_DFP ? FLOAT_REGS : NO_REGS;
> +
> +      if (TARGET_FPRS && TARGET_HARD_FLOAT && FLOAT_MODE_P (mode)
> +	  && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
> +	return FLOAT_REGS;
> +    }
> +
>    if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS)
>      return GENERAL_REGS;
> 
> @@ -34549,8 +34619,14 @@ rs6000_complex_function_value (machine_m
>    machine_mode inner = GET_MODE_INNER (mode);
>    unsigned int inner_bytes = GET_MODE_UNIT_SIZE (mode);
> 
> -  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
> +  if (TARGET_FLOAT128
> +      && (mode == KCmode
> +	  || (mode == TCmode && TARGET_IEEEQUAD)))
> +    regno = ALTIVEC_ARG_RETURN;
> +
> +  else if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
>      regno = FP_ARG_RETURN;
> +
>    else
>      {
>        regno = GP_ARG_RETURN;
> Index: gcc/config/rs6000/rs6000.h
> ===================================================================
> --- gcc/config/rs6000/rs6000.h	(revision 237045)
> +++ gcc/config/rs6000/rs6000.h	(working copy)
> @@ -418,12 +418,12 @@ extern const char *host_detect_local_cpu
>     Similarly IFmode is the IBM long double format even if the default is IEEE
>     128-bit.  */
>  #define FLOAT128_IEEE_P(MODE)						\
> -  (((MODE) == TFmode && TARGET_IEEEQUAD)				\
> -   || ((MODE) == KFmode))
> +  ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
> +   || ((MODE) == KFmode) || ((MODE) == KCmode))
> 
>  #define FLOAT128_IBM_P(MODE)						\
> -  (((MODE) == TFmode && !TARGET_IEEEQUAD)				\
> -   || ((MODE) == IFmode))
> +  ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
> +   || ((MODE) == IFmode) || ((MODE) == ICmode))
> 
>  /* Helper macros to say whether a 128-bit floating point type can go in a
>     single vector register, or whether it needs paired scalar values.  */
> @@ -1789,7 +1789,9 @@ extern enum reg_class rs6000_constraints
>  #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
>  #define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN	\
>  			   : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> -#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
> +#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2		\
> +				? (ALTIVEC_ARG_RETURN			\
> +				   + (TARGET_FLOAT128 ? 1 : 0))		\
>  			        : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> 
>  /* Flags for the call/call_value rtl operations set up by function_arg */
> Index: gcc/doc/extend.texi
> ===================================================================
> --- gcc/doc/extend.texi	(revision 237045)
> +++ gcc/doc/extend.texi	(working copy)
> @@ -962,8 +962,13 @@ complex @code{__float128} type.  When th
>  would use the following syntax to declare @code{_Complex128} to be a
>  complex @code{__float128} type:
> 
> +On the PowerPC Linux VSX targets, you can declare complex types using
> +the corresponding internal complex type, @code{KCmode} for
> +@code{__float128} type and @code{ICmode} for @code{__ibm128} type:
> +
>  @smallexample
> -typedef _Complex float __attribute__((mode(KC))) _Complex128;
> +typedef _Complex float __attribute__((mode(KC))) _Complex_float128;
> +typedef _Complex float __attribute__((mode(IC))) _Complex_ibm128;
>  @end smallexample
> 
>  Not all targets support additional floating-point types.
> Index: gcc/fortran/trans-types.c
> ===================================================================
> --- gcc/fortran/trans-types.c	(revision 237045)
> +++ gcc/fortran/trans-types.c	(working copy)
> @@ -828,6 +828,7 @@ gfc_build_complex_type (tree scalar_type
> 
>    new_type = make_node (COMPLEX_TYPE);
>    TREE_TYPE (new_type) = scalar_type;
> +  SET_TYPE_MODE (new_type, GET_MODE_COMPLEX_MODE (TYPE_MODE (scalar_type)));
>    layout_type (new_type);
>    return new_type;
>  }
> Index: gcc/testsuite/gcc.target/powerpc/float128-complex-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
> +++ gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
> @@ -0,0 +1,157 @@
> +/* { dg-do compile { target { powerpc*-*-linux* } } } */
> +/* { dg-require-effective-target powerpc_float128_sw_ok } */
> +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
> +/* { dg-options "-O2 -mcpu=power7 -mfloat128" } */
> +
> +#ifndef NO_FLOAT
> +typedef _Complex float	float_complex;
> +extern float_complex cfloat1 (void);
> +extern float_complex cfloat2 (void);
> +
> +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
> +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
> +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
> +
> +#else
> +#define FLOAT_ARG(NAME, OP)
> +#define FLOAT_PTR(NAME, OP)
> +#define FLOAT_CALL()
> +#endif
> +
> +#ifndef NO_DOUBLE
> +typedef _Complex double	double_complex;
> +extern double_complex cdouble1 (void);
> +extern double_complex cdouble2 (void);
> +
> +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
> +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
> +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
> +
> +#else
> +#define DOUBLE_ARG(NAME, OP)
> +#define DOUBLE_PTR(NAME, OP)
> +#define DOUBLE_CALL()
> +#endif
> +
> +#ifndef NO_FLOAT128
> +#ifdef __VSX__
> +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
> +#else
> +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
> +#endif
> +
> +extern float128_complex cfloat128_1 (void);
> +extern float128_complex cfloat128_2 (void);
> +
> +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
> +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
> +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
> +
> +#else
> +#define FLOAT128_ARG(NAME, OP)
> +#define FLOAT128_PTR(NAME, OP)
> +#define FLOAT128_CALL()
> +#endif
> +
> +#ifndef NO_LDOUBLE
> +typedef _Complex long double ldouble_complex;
> +extern ldouble_complex cldouble1 (void);
> +extern ldouble_complex cldouble2 (void);
> +
> +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
> +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
> +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
> +
> +#else
> +#define LDOUBLE_ARG(NAME, OP)
> +#define LDOUBLE_PTR(NAME, OP)
> +#define LDOUBLE_CALL()
> +#endif
> +
> +
> +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
> +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
> +{									\
> +  return a OP b;							\
> +}
> +
> +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
> +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
> +{									\
> +  *p = *a OP *b;							\
> +}
> +
> +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
> +TYPE call_ ## SUFFIX (void)						\
> +{									\
> +  TYPE value1 = FUNC1 ();						\
> +  TYPE value2 = FUNC2 ();						\
> +  return value1 + value2;						\
> +}
> +
> +#ifndef NO_ARG
> +#ifndef NO_ADD
> +FLOAT_ARG    (add, +)
> +DOUBLE_ARG   (add, +)
> +FLOAT128_ARG (add, +)
> +LDOUBLE_ARG  (add, +)
> +#endif
> +
> +#ifndef NO_SUB
> +FLOAT_ARG    (sub, -)
> +DOUBLE_ARG   (sub, -)
> +FLOAT128_ARG (sub, -)
> +LDOUBLE_ARG  (sub, -)
> +#endif
> +
> +#ifndef NO_MUL
> +FLOAT_ARG    (mul, *)
> +DOUBLE_ARG   (mul, *)
> +FLOAT128_ARG (mul, *)
> +LDOUBLE_ARG  (mul, *)
> +#endif
> +
> +#ifndef NO_DIV
> +FLOAT_ARG    (div, /)
> +DOUBLE_ARG   (div, /)
> +FLOAT128_ARG (div, /)
> +LDOUBLE_ARG  (div, /)
> +#endif
> +#endif
> +
> +#ifndef NO_PTR
> +#ifndef NO_ADD
> +FLOAT_PTR    (add, +)
> +DOUBLE_PTR   (add, +)
> +FLOAT128_PTR (add, +)
> +LDOUBLE_PTR  (add, +)
> +#endif
> +
> +#ifndef NO_SUB
> +FLOAT_PTR    (sub, -)
> +DOUBLE_PTR   (sub, -)
> +FLOAT128_PTR (sub, -)
> +LDOUBLE_PTR  (sub, -)
> +#endif
> +
> +#ifndef NO_MUL
> +FLOAT_PTR    (mul, *)
> +DOUBLE_PTR   (mul, *)
> +FLOAT128_PTR (mul, *)
> +LDOUBLE_PTR  (mul, *)
> +#endif
> +
> +#ifndef NO_DIV
> +FLOAT_PTR    (div, /)
> +DOUBLE_PTR   (div, /)
> +FLOAT128_PTR (div, /)
> +LDOUBLE_PTR  (div, /)
> +#endif
> +#endif
> +
> +#ifndef NO_CALL
> +FLOAT_CALL    ()
> +DOUBLE_CALL   ()
> +FLOAT128_CALL ()
> +LDOUBLE_CALL  ()
> +#endif
> Index: gcc/testsuite/gcc.target/powerpc/float128-complex-2.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
> +++ gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
> @@ -0,0 +1,160 @@
> +/* { dg-do compile { target { powerpc*-*-linux* } } } */
> +/* { dg-require-effective-target powerpc_float128_hw_ok } */
> +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
> +/* { dg-options "-O2 -mcpu=power9 -mfloat128 -mfloat128-hardware" } */
> +
> +#ifndef NO_FLOAT
> +typedef _Complex float	float_complex;
> +extern float_complex cfloat1 (void);
> +extern float_complex cfloat2 (void);
> +
> +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
> +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
> +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
> +
> +#else
> +#define FLOAT_ARG(NAME, OP)
> +#define FLOAT_PTR(NAME, OP)
> +#define FLOAT_CALL()
> +#endif
> +
> +#ifndef NO_DOUBLE
> +typedef _Complex double	double_complex;
> +extern double_complex cdouble1 (void);
> +extern double_complex cdouble2 (void);
> +
> +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
> +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
> +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
> +
> +#else
> +#define DOUBLE_ARG(NAME, OP)
> +#define DOUBLE_PTR(NAME, OP)
> +#define DOUBLE_CALL()
> +#endif
> +
> +#ifndef NO_FLOAT128
> +#ifdef __VSX__
> +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
> +#else
> +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
> +#endif
> +
> +extern float128_complex cfloat128_1 (void);
> +extern float128_complex cfloat128_2 (void);
> +
> +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
> +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
> +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
> +
> +#else
> +#define FLOAT128_ARG(NAME, OP)
> +#define FLOAT128_PTR(NAME, OP)
> +#define FLOAT128_CALL()
> +#endif
> +
> +#ifndef NO_LDOUBLE
> +typedef _Complex long double ldouble_complex;
> +extern ldouble_complex cldouble1 (void);
> +extern ldouble_complex cldouble2 (void);
> +
> +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
> +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
> +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
> +
> +#else
> +#define LDOUBLE_ARG(NAME, OP)
> +#define LDOUBLE_PTR(NAME, OP)
> +#define LDOUBLE_CALL()
> +#endif
> +
> +
> +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
> +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
> +{									\
> +  return a OP b;							\
> +}
> +
> +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
> +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
> +{									\
> +  *p = *a OP *b;							\
> +}
> +
> +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
> +TYPE call_ ## SUFFIX (void)						\
> +{									\
> +  TYPE value1 = FUNC1 ();						\
> +  TYPE value2 = FUNC2 ();						\
> +  return value1 + value2;						\
> +}
> +
> +#ifndef NO_ARG
> +#ifndef NO_ADD
> +FLOAT_ARG    (add, +)
> +DOUBLE_ARG   (add, +)
> +FLOAT128_ARG (add, +)
> +LDOUBLE_ARG  (add, +)
> +#endif
> +
> +#ifndef NO_SUB
> +FLOAT_ARG    (sub, -)
> +DOUBLE_ARG   (sub, -)
> +FLOAT128_ARG (sub, -)
> +LDOUBLE_ARG  (sub, -)
> +#endif
> +
> +#ifndef NO_MUL
> +FLOAT_ARG    (mul, *)
> +DOUBLE_ARG   (mul, *)
> +FLOAT128_ARG (mul, *)
> +LDOUBLE_ARG  (mul, *)
> +#endif
> +
> +#ifndef NO_DIV
> +FLOAT_ARG    (div, /)
> +DOUBLE_ARG   (div, /)
> +FLOAT128_ARG (div, /)
> +LDOUBLE_ARG  (div, /)
> +#endif
> +#endif
> +
> +#ifndef NO_PTR
> +#ifndef NO_ADD
> +FLOAT_PTR    (add, +)
> +DOUBLE_PTR   (add, +)
> +FLOAT128_PTR (add, +)
> +LDOUBLE_PTR  (add, +)
> +#endif
> +
> +#ifndef NO_SUB
> +FLOAT_PTR    (sub, -)
> +DOUBLE_PTR   (sub, -)
> +FLOAT128_PTR (sub, -)
> +LDOUBLE_PTR  (sub, -)
> +#endif
> +
> +#ifndef NO_MUL
> +FLOAT_PTR    (mul, *)
> +DOUBLE_PTR   (mul, *)
> +FLOAT128_PTR (mul, *)
> +LDOUBLE_PTR  (mul, *)
> +#endif
> +
> +#ifndef NO_DIV
> +FLOAT_PTR    (div, /)
> +DOUBLE_PTR   (div, /)
> +FLOAT128_PTR (div, /)
> +LDOUBLE_PTR  (div, /)
> +#endif
> +#endif
> +
> +#ifndef NO_CALL
> +FLOAT_CALL    ()
> +DOUBLE_CALL   ()
> +FLOAT128_CALL ()
> +LDOUBLE_CALL  ()
> +#endif
> +
> +/* { dg-final { scan-assembler "xsaddqp"  } } */
> +/* { dg-final { scan-assembler "xssubqp"  } } */
Segher Boessenkool June 9, 2016, 9:09 p.m. UTC | #2
On Thu, Jun 09, 2016 at 04:06:53PM -0400, Michael Meissner wrote:
> I'm including the global reviewers on the list.  I just want to be sure that
> there is no problem installing these patches on the GCC 6.2 branch.  While it
> is technically an enchancement, it is needed to be able to install the glibc
> support that is needed to complete the work to add IEEE 128-bit floating point.
> 
> The issue being fixed is that when we are creating the complex type, we used to
> do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
> floating point types (__ibm128 and __float128, with long double currently
> defaulting to __ibm128).

The rs6000 parts are okay to backport to 6.

Thanks,


Segher
Richard Biener June 10, 2016, 7:06 a.m. UTC | #3
On Thu, 9 Jun 2016, Michael Meissner wrote:

> I'm including the global reviewers on the list.  I just want to be sure that
> there is no problem installing these patches on the GCC 6.2 branch.  While it
> is technically an enchancement, it is needed to be able to install the glibc
> support that is needed to complete the work to add IEEE 128-bit floating point.
> 
> The issue being fixed is that when we are creating the complex type, we used to
> do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
> floating point types (__ibm128 and __float128, with long double currently
> defaulting to __ibm128).

As this enhancement includes middle-end changes I am hesitant to approve
it for the branch.  Why is it desirable to backport this change?

Thanks,
Richard.

> On Fri, Jun 03, 2016 at 09:33:35AM -0400, Michael Meissner wrote:
> > These patches were installed on the trunk on May 2nd, with a fix from Alan
> > Modra on May 11th.  Unless I here objections in the next few days, I will
> > commit these changes to the GCC 6.x branch.  These changes will allow people to
> > use complex __float128 types (via an attribute) on the PowerPC.
> > 
> > Note, we will need patches to libgcc to fully enable complex __float128 support
> > on the PowerPC.  These patches enable the compiler support, so that the libgcc
> > changes can be coded.
> > 
> > In addition to bootstrapping and regtesting on the PowerPC (little endian
> > power8), I also bootstrapped and regested the changes on x86_64 running RHEL
> > 6.2.  There were no regressions in either case.
> > 
> > [gcc]
> > 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> > 
> > 	Back port from trunk
> > 	2016-05-11  Alan Modra  <amodra@gmail.com>
> > 
> > 	* config/rs6000/rs6000.c (is_complex_IBM_long_double,
> > 	abi_v4_pass_in_fpr): New functions.
> > 	(rs6000_function_arg_boundary): Exclude complex IBM long double
> > 	from 64-bit alignment when ABI_V4.
> > 	(rs6000_function_arg, rs6000_function_arg_advance_1,
> > 	rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.
> > 
> > 	Back port from trunk
> > 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> > 
> > 	* machmode.h (mode_complex): Add support to give the complex mode
> > 	for a given mode.
> > 	(GET_MODE_COMPLEX_MODE): Likewise.
> > 	* stor-layout.c (layout_type): For COMPLEX_TYPE, use the mode
> > 	stored by build_complex_type and gfc_build_complex_type instead of
> > 	trying to figure out the appropriate mode based on the size. Raise
> > 	an assertion error, if the type was not set.
> > 	* genmodes.c (struct mode_data): Add field for the complex type of
> > 	the given type.
> > 	(blank_mode): Likewise.
> > 	(make_complex_modes): Remember the complex mode created in the
> > 	base type.
> > 	(emit_mode_complex): Write out the mode_complex array to map a
> > 	type mode to the complex version.
> > 	(emit_insn_modes_c): Likewise.
> > 	* tree.c (build_complex_type): Set the complex type to use before
> > 	calling layout_type.
> > 	* config/rs6000/rs6000.c (rs6000_hard_regno_nregs_internal): Add
> > 	support for __float128 complex datatypes.
> > 	(rs6000_hard_regno_mode_ok): Likewise.
> > 	(rs6000_setup_reg_addr_masks): Likewise.
> > 	(rs6000_complex_function_value): Likewise.
> > 	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Likewise.
> > 	__float128 and __ibm128 complex.
> > 	(FLOAT128_IBM_P): Likewise.
> > 	(ALTIVEC_ARG_MAX_RETURN): Likewise.
> > 	* doc/extend.texi (Additional Floating Types): Document that
> > 	-mfloat128 must be used to enable __float128.  Document complex
> > 	__float128 and __ibm128 support.
> > 
> > [gcc/fortran]
> > 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> > 
> > 	Back port from trunk
> > 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> > 
> > 	* trans-types.c (gfc_build_complex_type):
> > 
> > [gcc/testsuite]
> > 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> > 
> > 	Back port from trunk
> > 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> > 
> > 	* gcc.target/powerpc/float128-complex-1.c: New tests for complex
> > 	__float128.
> > 	* gcc.target/powerpc/float128-complex-2.c: Likewise.
> > 
> > -- 
> > Michael Meissner, IBM
> > IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
> > email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797
> 
> > Index: gcc/machmode.h
> > ===================================================================
> > --- gcc/machmode.h	(revision 237045)
> > +++ gcc/machmode.h	(working copy)
> > @@ -269,6 +269,10 @@ extern const unsigned char mode_wider[NU
> >  extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
> >  #define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
> > 
> > +/* Get the complex mode from the component mode.  */
> > +extern const unsigned char mode_complex[NUM_MACHINE_MODES];
> > +#define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE])
> > +
> >  /* Return the mode for data of a given size SIZE and mode class CLASS.
> >     If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
> >     The value is BLKmode if no other mode is found.  */
> > Index: gcc/stor-layout.c
> > ===================================================================
> > --- gcc/stor-layout.c	(revision 237045)
> > +++ gcc/stor-layout.c	(working copy)
> > @@ -2146,11 +2146,13 @@ layout_type (tree type)
> > 
> >      case COMPLEX_TYPE:
> >        TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
> > -      SET_TYPE_MODE (type,
> > -		     mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)),
> > -				    (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
> > -				     ? MODE_COMPLEX_FLOAT : MODE_COMPLEX_INT),
> > -				     0));
> > +
> > +      /* build_complex_type and fortran's gfc_build_complex_type have set the
> > +	 expected mode to allow having multiple complex types for multiple
> > +	 floating point types that have the same size such as the PowerPC with
> > +	 __ibm128 and __float128.  */
> > +      gcc_assert (TYPE_MODE (type) != VOIDmode);
> > +
> >        TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
> >        TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
> >        break;
> > Index: gcc/genmodes.c
> > ===================================================================
> > --- gcc/genmodes.c	(revision 237045)
> > +++ gcc/genmodes.c	(working copy)
> > @@ -66,6 +66,7 @@ struct mode_data
> >  				   this mode as a component.  */
> >    struct mode_data *next_cont;  /* Next mode in that list.  */
> > 
> > +  struct mode_data *complex;	/* complex type with mode as component.  */
> >    const char *file;		/* file and line of definition, */
> >    unsigned int line;		/* for error reporting */
> >    unsigned int counter;		/* Rank ordering of modes */
> > @@ -83,7 +84,7 @@ static struct mode_data *void_mode;
> >  static const struct mode_data blank_mode = {
> >    0, "<unknown>", MAX_MODE_CLASS,
> >    -1U, -1U, -1U, -1U,
> > -  0, 0, 0, 0, 0,
> > +  0, 0, 0, 0, 0, 0,
> >    "<unknown>", 0, 0, 0, 0, false, 0
> >  };
> > 
> > @@ -472,6 +473,7 @@ make_complex_modes (enum mode_class cl,
> > 
> >        c = new_mode (cclass, buf, file, line);
> >        c->component = m;
> > +      m->complex = c;
> >      }
> >  }
> > 
> > @@ -1381,6 +1383,22 @@ emit_mode_wider (void)
> >  }
> > 
> >  static void
> > +emit_mode_complex (void)
> > +{
> > +  int c;
> > +  struct mode_data *m;
> > +
> > +  print_decl ("unsigned char", "mode_complex", "NUM_MACHINE_MODES");
> > +
> > +  for_all_modes (c, m)
> > +    tagged_printf ("%smode",
> > +		   m->complex ? m->complex->name : void_mode->name,
> > +		   m->name);
> > +
> > +  print_closer ();
> > +}
> > +
> > +static void
> >  emit_mode_mask (void)
> >  {
> >    int c;
> > @@ -1745,6 +1763,7 @@ emit_insn_modes_c (void)
> >    emit_mode_size ();
> >    emit_mode_nunits ();
> >    emit_mode_wider ();
> > +  emit_mode_complex ();
> >    emit_mode_mask ();
> >    emit_mode_inner ();
> >    emit_mode_unit_size ();
> > Index: gcc/tree.c
> > ===================================================================
> > --- gcc/tree.c	(revision 237045)
> > +++ gcc/tree.c	(working copy)
> > @@ -8675,6 +8675,7 @@ build_complex_type (tree component_type)
> >    t = make_node (COMPLEX_TYPE);
> > 
> >    TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
> > +  SET_TYPE_MODE (t, GET_MODE_COMPLEX_MODE (TYPE_MODE (component_type)));
> > 
> >    /* If we already have such a type, use the old one.  */
> >    hstate.add_object (TYPE_HASH (component_type));
> > Index: gcc/config/rs6000/rs6000.c
> > ===================================================================
> > --- gcc/config/rs6000/rs6000.c	(revision 237045)
> > +++ gcc/config/rs6000/rs6000.c	(working copy)
> > @@ -1882,7 +1882,7 @@ rs6000_hard_regno_nregs_internal (int re
> >       128-bit floating point that can go in vector registers, which has VSX
> >       memory addressing.  */
> >    if (FP_REGNO_P (regno))
> > -    reg_size = (VECTOR_MEM_VSX_P (mode)
> > +    reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode)
> >  		? UNITS_PER_VSX_WORD
> >  		: UNITS_PER_FP_WORD);
> > 
> > @@ -1914,6 +1914,9 @@ rs6000_hard_regno_mode_ok (int regno, ma
> >  {
> >    int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1;
> > 
> > +  if (COMPLEX_MODE_P (mode))
> > +    mode = GET_MODE_INNER (mode);
> > +
> >    /* PTImode can only go in GPRs.  Quad word memory operations require even/odd
> >       register combinations, and use PTImode where we need to deal with quad
> >       word memory operations.  Don't allow quad words in the argument or frame
> > @@ -2716,8 +2719,17 @@ rs6000_setup_reg_addr_masks (void)
> > 
> >    for (m = 0; m < NUM_MACHINE_MODES; ++m)
> >      {
> > -      machine_mode m2 = (machine_mode)m;
> > -      unsigned short msize = GET_MODE_SIZE (m2);
> > +      machine_mode m2 = (machine_mode) m;
> > +      bool complex_p = false;
> > +      size_t msize;
> > +
> > +      if (COMPLEX_MODE_P (m2))
> > +	{
> > +	  complex_p = true;
> > +	  m2 = GET_MODE_INNER (m2);
> > +	}
> > +
> > +      msize = GET_MODE_SIZE (m2);
> > 
> >        /* SDmode is special in that we want to access it only via REG+REG
> >  	 addressing on power7 and above, since we want to use the LFIWZX and
> > @@ -2739,7 +2751,7 @@ rs6000_setup_reg_addr_masks (void)
> >  	      /* Indicate if the mode takes more than 1 physical register.  If
> >  		 it takes a single register, indicate it can do REG+REG
> >  		 addressing.  */
> > -	      if (nregs > 1 || m == BLKmode)
> > +	      if (nregs > 1 || m == BLKmode || complex_p)
> >  		addr_mask |= RELOAD_REG_MULTIPLE;
> >  	      else
> >  		addr_mask |= RELOAD_REG_INDEXED;
> > @@ -2755,7 +2767,7 @@ rs6000_setup_reg_addr_masks (void)
> >  		  && msize <= 8
> >  		  && !VECTOR_MODE_P (m2)
> >  		  && !FLOAT128_VECTOR_P (m2)
> > -		  && !COMPLEX_MODE_P (m2)
> > +		  && !complex_p
> >  		  && (m2 != DFmode || !TARGET_UPPER_REGS_DF)
> >  		  && (m2 != SFmode || !TARGET_UPPER_REGS_SF)
> >  		  && !(TARGET_E500_DOUBLE && msize == 8))
> > @@ -10266,6 +10278,35 @@ rs6000_must_pass_in_stack (machine_mode 
> >      return must_pass_in_stack_var_size_or_pad (mode, type);
> >  }
> > 
> > +static inline bool
> > +is_complex_IBM_long_double (machine_mode mode)
> > +{
> > +  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
> > +}
> > +
> > +/* Whether ABI_V4 passes MODE args to a function in floating point
> > +   registers.  */
> > +
> > +static bool
> > +abi_v4_pass_in_fpr (machine_mode mode)
> > +{
> > +  if (!TARGET_FPRS || !TARGET_HARD_FLOAT)
> > +    return false;
> > +  if (TARGET_SINGLE_FLOAT && mode == SFmode)
> > +    return true;
> > +  if (TARGET_DOUBLE_FLOAT && mode == DFmode)
> > +    return true;
> > +  /* ABI_V4 passes complex IBM long double in 8 gprs.
> > +     Stupid, but we can't change the ABI now.  */
> > +  if (is_complex_IBM_long_double (mode))
> > +    return false;
> > +  if (FLOAT128_2REG_P (mode))
> > +    return true;
> > +  if (DECIMAL_FLOAT_MODE_P (mode))
> > +    return true;
> > +  return false;
> > +}
> > +
> >  /* If defined, a C expression which determines whether, and in which
> >     direction, to pad out an argument with extra space.  The value
> >     should be of type `enum direction': either `upward' to pad above
> > @@ -10350,6 +10391,7 @@ rs6000_function_arg_boundary (machine_mo
> >        && (GET_MODE_SIZE (mode) == 8
> >  	  || (TARGET_HARD_FLOAT
> >  	      && TARGET_FPRS
> > +	      && !is_complex_IBM_long_double (mode)
> >  	      && FLOAT128_2REG_P (mode))))
> >      return 64;
> >    else if (FLOAT128_VECTOR_P (mode))
> > @@ -10729,11 +10771,7 @@ rs6000_function_arg_advance_1 (CUMULATIV
> >      }
> >    else if (DEFAULT_ABI == ABI_V4)
> >      {
> > -      if (TARGET_HARD_FLOAT && TARGET_FPRS
> > -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
> > -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
> > -	      || FLOAT128_2REG_P (mode)
> > -	      || DECIMAL_FLOAT_MODE_P (mode)))
> > +      if (abi_v4_pass_in_fpr (mode))
> >  	{
> >  	  /* _Decimal128 must use an even/odd register pair.  This assumes
> >  	     that the register number is odd when fregno is odd.  */
> > @@ -11390,11 +11428,7 @@ rs6000_function_arg (cumulative_args_t c
> > 
> >    else if (abi == ABI_V4)
> >      {
> > -      if (TARGET_HARD_FLOAT && TARGET_FPRS
> > -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
> > -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
> > -	      || FLOAT128_2REG_P (mode)
> > -	      || DECIMAL_FLOAT_MODE_P (mode)))
> > +      if (abi_v4_pass_in_fpr (mode))
> >  	{
> >  	  /* _Decimal128 must use an even/odd register pair.  This assumes
> >  	     that the register number is odd when fregno is odd.  */
> > @@ -12315,19 +12349,15 @@ rs6000_gimplify_va_arg (tree valist, tre
> >    rsize = (size + 3) / 4;
> >    align = 1;
> > 
> > -  if (TARGET_HARD_FLOAT && TARGET_FPRS
> > -      && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode)
> > -          || (TARGET_DOUBLE_FLOAT 
> > -              && (TYPE_MODE (type) == DFmode 
> > -		  || FLOAT128_2REG_P (TYPE_MODE (type))
> > -		  || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))))))
> > +  machine_mode mode = TYPE_MODE (type);
> > +  if (abi_v4_pass_in_fpr (mode))
> >      {
> >        /* FP args go in FP registers, if present.  */
> >        reg = fpr;
> >        n_reg = (size + 7) / 8;
> >        sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4;
> >        sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4);
> > -      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
> > +      if (mode != SFmode && mode != SDmode)
> >  	align = 8;
> >      }
> >    else
> > @@ -12347,7 +12377,7 @@ rs6000_gimplify_va_arg (tree valist, tre
> >    addr = create_tmp_var (ptr_type_node, "addr");
> > 
> >    /*  AltiVec vectors never go in registers when -mabi=altivec.  */
> > -  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
> > +  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
> >      align = 16;
> >    else
> >      {
> > @@ -12368,7 +12398,7 @@ rs6000_gimplify_va_arg (tree valist, tre
> >  	}
> >        /* _Decimal128 is passed in even/odd fpr pairs; the stored
> >  	 reg number is 0 for f1, so we want to make it odd.  */
> > -      else if (reg == fpr && TYPE_MODE (type) == TDmode)
> > +      else if (reg == fpr && mode == TDmode)
> >  	{
> >  	  t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg),
> >  		      build_int_cst (TREE_TYPE (reg), 1));
> > @@ -12395,7 +12425,7 @@ rs6000_gimplify_va_arg (tree valist, tre
> >  	 FP register for 32-bit binaries.  */
> >        if (TARGET_32BIT
> >  	  && TARGET_HARD_FLOAT && TARGET_FPRS
> > -	  && TYPE_MODE (type) == SDmode)
> > +	  && mode == SDmode)
> >  	t = fold_build_pointer_plus_hwi (t, size);
> > 
> >        gimplify_assign (addr, t, pre_p);
> > @@ -18464,25 +18494,33 @@ rs6000_secondary_reload_memory (rtx addr
> >      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX]
> >  		 & ~RELOAD_REG_AND_M16);
> > 
> > -  else
> > +  /* If the register allocator hasn't made up its mind yet on the register
> > +     class to use, settle on defaults to use.  */
> > +  else if (rclass == NO_REGS)
> >      {
> > -      if (TARGET_DEBUG_ADDR)
> > -	fprintf (stderr,
> > -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> > -		 "class is not GPR, FPR, VMX\n",
> > -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
> > +      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_ANY]
> > +		   & ~RELOAD_REG_AND_M16);
> > 
> > -      return -1;
> > +      if ((addr_mask & RELOAD_REG_MULTIPLE) != 0)
> > +	addr_mask &= ~(RELOAD_REG_INDEXED
> > +		       | RELOAD_REG_PRE_INCDEC
> > +		       | RELOAD_REG_PRE_MODIFY);
> >      }
> > 
> > +  else
> > +    addr_mask = 0;
> > +
> >    /* If the register isn't valid in this register class, just return now.  */
> >    if ((addr_mask & RELOAD_REG_VALID) == 0)
> >      {
> >        if (TARGET_DEBUG_ADDR)
> > -	fprintf (stderr,
> > -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> > -		 "not valid in class\n",
> > -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
> > +	{
> > +	  fprintf (stderr,
> > +		   "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> > +		   "not valid in class\n",
> > +		   GET_MODE_NAME (mode), reg_class_names[rclass]);
> > +	  debug_rtx (addr);
> > +	}
> > 
> >        return -1;
> >      }
> > @@ -19143,6 +19181,9 @@ rs6000_secondary_reload (bool in_p,
> >  	fprintf (stderr, ", reload func = %s, extra cost = %d",
> >  		 insn_data[sri->icode].name, sri->extra_cost);
> > 
> > +      else if (sri->extra_cost > 0)
> > +	fprintf (stderr, ", extra cost = %d", sri->extra_cost);
> > +
> >        fputs ("\n", stderr);
> >        debug_rtx (x);
> >      }
> > @@ -19553,6 +19594,16 @@ rs6000_preferred_reload_class (rtx x, en
> >    machine_mode mode = GET_MODE (x);
> >    bool is_constant = CONSTANT_P (x);
> > 
> > +  /* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred
> > +     reload class for it.  */
> > +  if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS)
> > +      && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0)
> > +    return NO_REGS;
> > +
> > +  if ((rclass == FLOAT_REGS || rclass == VSX_REGS)
> > +      && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
> > +    return NO_REGS;
> > +
> >    /* For VSX, see if we should prefer FLOAT_REGS or ALTIVEC_REGS.  Do not allow
> >       the reloading of address expressions using PLUS into floating point
> >       registers.  */
> > @@ -19603,6 +19654,25 @@ rs6000_preferred_reload_class (rtx x, en
> >        return NO_REGS;
> >      }
> > 
> > +  /* If we haven't picked a register class, and the type is a vector or
> > +     floating point type, prefer to use the VSX, FPR, or Altivec register
> > +     classes.  */
> > +  if (rclass == NO_REGS)
> > +    {
> > +      if (TARGET_VSX && VECTOR_MEM_VSX_OR_P8_VECTOR_P (mode))
> > +	return VSX_REGS;
> > +
> > +      if (TARGET_ALTIVEC && VECTOR_MEM_ALTIVEC_P (mode))
> > +	return ALTIVEC_REGS;
> > +
> > +      if (DECIMAL_FLOAT_MODE_P (mode))
> > +	return TARGET_DFP ? FLOAT_REGS : NO_REGS;
> > +
> > +      if (TARGET_FPRS && TARGET_HARD_FLOAT && FLOAT_MODE_P (mode)
> > +	  && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
> > +	return FLOAT_REGS;
> > +    }
> > +
> >    if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS)
> >      return GENERAL_REGS;
> > 
> > @@ -34549,8 +34619,14 @@ rs6000_complex_function_value (machine_m
> >    machine_mode inner = GET_MODE_INNER (mode);
> >    unsigned int inner_bytes = GET_MODE_UNIT_SIZE (mode);
> > 
> > -  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
> > +  if (TARGET_FLOAT128
> > +      && (mode == KCmode
> > +	  || (mode == TCmode && TARGET_IEEEQUAD)))
> > +    regno = ALTIVEC_ARG_RETURN;
> > +
> > +  else if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
> >      regno = FP_ARG_RETURN;
> > +
> >    else
> >      {
> >        regno = GP_ARG_RETURN;
> > Index: gcc/config/rs6000/rs6000.h
> > ===================================================================
> > --- gcc/config/rs6000/rs6000.h	(revision 237045)
> > +++ gcc/config/rs6000/rs6000.h	(working copy)
> > @@ -418,12 +418,12 @@ extern const char *host_detect_local_cpu
> >     Similarly IFmode is the IBM long double format even if the default is IEEE
> >     128-bit.  */
> >  #define FLOAT128_IEEE_P(MODE)						\
> > -  (((MODE) == TFmode && TARGET_IEEEQUAD)				\
> > -   || ((MODE) == KFmode))
> > +  ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
> > +   || ((MODE) == KFmode) || ((MODE) == KCmode))
> > 
> >  #define FLOAT128_IBM_P(MODE)						\
> > -  (((MODE) == TFmode && !TARGET_IEEEQUAD)				\
> > -   || ((MODE) == IFmode))
> > +  ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
> > +   || ((MODE) == IFmode) || ((MODE) == ICmode))
> > 
> >  /* Helper macros to say whether a 128-bit floating point type can go in a
> >     single vector register, or whether it needs paired scalar values.  */
> > @@ -1789,7 +1789,9 @@ extern enum reg_class rs6000_constraints
> >  #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
> >  #define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN	\
> >  			   : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> > -#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
> > +#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2		\
> > +				? (ALTIVEC_ARG_RETURN			\
> > +				   + (TARGET_FLOAT128 ? 1 : 0))		\
> >  			        : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> > 
> >  /* Flags for the call/call_value rtl operations set up by function_arg */
> > Index: gcc/doc/extend.texi
> > ===================================================================
> > --- gcc/doc/extend.texi	(revision 237045)
> > +++ gcc/doc/extend.texi	(working copy)
> > @@ -962,8 +962,13 @@ complex @code{__float128} type.  When th
> >  would use the following syntax to declare @code{_Complex128} to be a
> >  complex @code{__float128} type:
> > 
> > +On the PowerPC Linux VSX targets, you can declare complex types using
> > +the corresponding internal complex type, @code{KCmode} for
> > +@code{__float128} type and @code{ICmode} for @code{__ibm128} type:
> > +
> >  @smallexample
> > -typedef _Complex float __attribute__((mode(KC))) _Complex128;
> > +typedef _Complex float __attribute__((mode(KC))) _Complex_float128;
> > +typedef _Complex float __attribute__((mode(IC))) _Complex_ibm128;
> >  @end smallexample
> > 
> >  Not all targets support additional floating-point types.
> > Index: gcc/fortran/trans-types.c
> > ===================================================================
> > --- gcc/fortran/trans-types.c	(revision 237045)
> > +++ gcc/fortran/trans-types.c	(working copy)
> > @@ -828,6 +828,7 @@ gfc_build_complex_type (tree scalar_type
> > 
> >    new_type = make_node (COMPLEX_TYPE);
> >    TREE_TYPE (new_type) = scalar_type;
> > +  SET_TYPE_MODE (new_type, GET_MODE_COMPLEX_MODE (TYPE_MODE (scalar_type)));
> >    layout_type (new_type);
> >    return new_type;
> >  }
> > Index: gcc/testsuite/gcc.target/powerpc/float128-complex-1.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
> > +++ gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
> > @@ -0,0 +1,157 @@
> > +/* { dg-do compile { target { powerpc*-*-linux* } } } */
> > +/* { dg-require-effective-target powerpc_float128_sw_ok } */
> > +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
> > +/* { dg-options "-O2 -mcpu=power7 -mfloat128" } */
> > +
> > +#ifndef NO_FLOAT
> > +typedef _Complex float	float_complex;
> > +extern float_complex cfloat1 (void);
> > +extern float_complex cfloat2 (void);
> > +
> > +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
> > +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
> > +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
> > +
> > +#else
> > +#define FLOAT_ARG(NAME, OP)
> > +#define FLOAT_PTR(NAME, OP)
> > +#define FLOAT_CALL()
> > +#endif
> > +
> > +#ifndef NO_DOUBLE
> > +typedef _Complex double	double_complex;
> > +extern double_complex cdouble1 (void);
> > +extern double_complex cdouble2 (void);
> > +
> > +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
> > +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
> > +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
> > +
> > +#else
> > +#define DOUBLE_ARG(NAME, OP)
> > +#define DOUBLE_PTR(NAME, OP)
> > +#define DOUBLE_CALL()
> > +#endif
> > +
> > +#ifndef NO_FLOAT128
> > +#ifdef __VSX__
> > +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
> > +#else
> > +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
> > +#endif
> > +
> > +extern float128_complex cfloat128_1 (void);
> > +extern float128_complex cfloat128_2 (void);
> > +
> > +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
> > +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
> > +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
> > +
> > +#else
> > +#define FLOAT128_ARG(NAME, OP)
> > +#define FLOAT128_PTR(NAME, OP)
> > +#define FLOAT128_CALL()
> > +#endif
> > +
> > +#ifndef NO_LDOUBLE
> > +typedef _Complex long double ldouble_complex;
> > +extern ldouble_complex cldouble1 (void);
> > +extern ldouble_complex cldouble2 (void);
> > +
> > +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
> > +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
> > +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
> > +
> > +#else
> > +#define LDOUBLE_ARG(NAME, OP)
> > +#define LDOUBLE_PTR(NAME, OP)
> > +#define LDOUBLE_CALL()
> > +#endif
> > +
> > +
> > +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
> > +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
> > +{									\
> > +  return a OP b;							\
> > +}
> > +
> > +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
> > +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
> > +{									\
> > +  *p = *a OP *b;							\
> > +}
> > +
> > +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
> > +TYPE call_ ## SUFFIX (void)						\
> > +{									\
> > +  TYPE value1 = FUNC1 ();						\
> > +  TYPE value2 = FUNC2 ();						\
> > +  return value1 + value2;						\
> > +}
> > +
> > +#ifndef NO_ARG
> > +#ifndef NO_ADD
> > +FLOAT_ARG    (add, +)
> > +DOUBLE_ARG   (add, +)
> > +FLOAT128_ARG (add, +)
> > +LDOUBLE_ARG  (add, +)
> > +#endif
> > +
> > +#ifndef NO_SUB
> > +FLOAT_ARG    (sub, -)
> > +DOUBLE_ARG   (sub, -)
> > +FLOAT128_ARG (sub, -)
> > +LDOUBLE_ARG  (sub, -)
> > +#endif
> > +
> > +#ifndef NO_MUL
> > +FLOAT_ARG    (mul, *)
> > +DOUBLE_ARG   (mul, *)
> > +FLOAT128_ARG (mul, *)
> > +LDOUBLE_ARG  (mul, *)
> > +#endif
> > +
> > +#ifndef NO_DIV
> > +FLOAT_ARG    (div, /)
> > +DOUBLE_ARG   (div, /)
> > +FLOAT128_ARG (div, /)
> > +LDOUBLE_ARG  (div, /)
> > +#endif
> > +#endif
> > +
> > +#ifndef NO_PTR
> > +#ifndef NO_ADD
> > +FLOAT_PTR    (add, +)
> > +DOUBLE_PTR   (add, +)
> > +FLOAT128_PTR (add, +)
> > +LDOUBLE_PTR  (add, +)
> > +#endif
> > +
> > +#ifndef NO_SUB
> > +FLOAT_PTR    (sub, -)
> > +DOUBLE_PTR   (sub, -)
> > +FLOAT128_PTR (sub, -)
> > +LDOUBLE_PTR  (sub, -)
> > +#endif
> > +
> > +#ifndef NO_MUL
> > +FLOAT_PTR    (mul, *)
> > +DOUBLE_PTR   (mul, *)
> > +FLOAT128_PTR (mul, *)
> > +LDOUBLE_PTR  (mul, *)
> > +#endif
> > +
> > +#ifndef NO_DIV
> > +FLOAT_PTR    (div, /)
> > +DOUBLE_PTR   (div, /)
> > +FLOAT128_PTR (div, /)
> > +LDOUBLE_PTR  (div, /)
> > +#endif
> > +#endif
> > +
> > +#ifndef NO_CALL
> > +FLOAT_CALL    ()
> > +DOUBLE_CALL   ()
> > +FLOAT128_CALL ()
> > +LDOUBLE_CALL  ()
> > +#endif
> > Index: gcc/testsuite/gcc.target/powerpc/float128-complex-2.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
> > +++ gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
> > @@ -0,0 +1,160 @@
> > +/* { dg-do compile { target { powerpc*-*-linux* } } } */
> > +/* { dg-require-effective-target powerpc_float128_hw_ok } */
> > +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
> > +/* { dg-options "-O2 -mcpu=power9 -mfloat128 -mfloat128-hardware" } */
> > +
> > +#ifndef NO_FLOAT
> > +typedef _Complex float	float_complex;
> > +extern float_complex cfloat1 (void);
> > +extern float_complex cfloat2 (void);
> > +
> > +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
> > +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
> > +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
> > +
> > +#else
> > +#define FLOAT_ARG(NAME, OP)
> > +#define FLOAT_PTR(NAME, OP)
> > +#define FLOAT_CALL()
> > +#endif
> > +
> > +#ifndef NO_DOUBLE
> > +typedef _Complex double	double_complex;
> > +extern double_complex cdouble1 (void);
> > +extern double_complex cdouble2 (void);
> > +
> > +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
> > +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
> > +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
> > +
> > +#else
> > +#define DOUBLE_ARG(NAME, OP)
> > +#define DOUBLE_PTR(NAME, OP)
> > +#define DOUBLE_CALL()
> > +#endif
> > +
> > +#ifndef NO_FLOAT128
> > +#ifdef __VSX__
> > +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
> > +#else
> > +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
> > +#endif
> > +
> > +extern float128_complex cfloat128_1 (void);
> > +extern float128_complex cfloat128_2 (void);
> > +
> > +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
> > +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
> > +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
> > +
> > +#else
> > +#define FLOAT128_ARG(NAME, OP)
> > +#define FLOAT128_PTR(NAME, OP)
> > +#define FLOAT128_CALL()
> > +#endif
> > +
> > +#ifndef NO_LDOUBLE
> > +typedef _Complex long double ldouble_complex;
> > +extern ldouble_complex cldouble1 (void);
> > +extern ldouble_complex cldouble2 (void);
> > +
> > +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
> > +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
> > +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
> > +
> > +#else
> > +#define LDOUBLE_ARG(NAME, OP)
> > +#define LDOUBLE_PTR(NAME, OP)
> > +#define LDOUBLE_CALL()
> > +#endif
> > +
> > +
> > +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
> > +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
> > +{									\
> > +  return a OP b;							\
> > +}
> > +
> > +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
> > +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
> > +{									\
> > +  *p = *a OP *b;							\
> > +}
> > +
> > +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
> > +TYPE call_ ## SUFFIX (void)						\
> > +{									\
> > +  TYPE value1 = FUNC1 ();						\
> > +  TYPE value2 = FUNC2 ();						\
> > +  return value1 + value2;						\
> > +}
> > +
> > +#ifndef NO_ARG
> > +#ifndef NO_ADD
> > +FLOAT_ARG    (add, +)
> > +DOUBLE_ARG   (add, +)
> > +FLOAT128_ARG (add, +)
> > +LDOUBLE_ARG  (add, +)
> > +#endif
> > +
> > +#ifndef NO_SUB
> > +FLOAT_ARG    (sub, -)
> > +DOUBLE_ARG   (sub, -)
> > +FLOAT128_ARG (sub, -)
> > +LDOUBLE_ARG  (sub, -)
> > +#endif
> > +
> > +#ifndef NO_MUL
> > +FLOAT_ARG    (mul, *)
> > +DOUBLE_ARG   (mul, *)
> > +FLOAT128_ARG (mul, *)
> > +LDOUBLE_ARG  (mul, *)
> > +#endif
> > +
> > +#ifndef NO_DIV
> > +FLOAT_ARG    (div, /)
> > +DOUBLE_ARG   (div, /)
> > +FLOAT128_ARG (div, /)
> > +LDOUBLE_ARG  (div, /)
> > +#endif
> > +#endif
> > +
> > +#ifndef NO_PTR
> > +#ifndef NO_ADD
> > +FLOAT_PTR    (add, +)
> > +DOUBLE_PTR   (add, +)
> > +FLOAT128_PTR (add, +)
> > +LDOUBLE_PTR  (add, +)
> > +#endif
> > +
> > +#ifndef NO_SUB
> > +FLOAT_PTR    (sub, -)
> > +DOUBLE_PTR   (sub, -)
> > +FLOAT128_PTR (sub, -)
> > +LDOUBLE_PTR  (sub, -)
> > +#endif
> > +
> > +#ifndef NO_MUL
> > +FLOAT_PTR    (mul, *)
> > +DOUBLE_PTR   (mul, *)
> > +FLOAT128_PTR (mul, *)
> > +LDOUBLE_PTR  (mul, *)
> > +#endif
> > +
> > +#ifndef NO_DIV
> > +FLOAT_PTR    (div, /)
> > +DOUBLE_PTR   (div, /)
> > +FLOAT128_PTR (div, /)
> > +LDOUBLE_PTR  (div, /)
> > +#endif
> > +#endif
> > +
> > +#ifndef NO_CALL
> > +FLOAT_CALL    ()
> > +DOUBLE_CALL   ()
> > +FLOAT128_CALL ()
> > +LDOUBLE_CALL  ()
> > +#endif
> > +
> > +/* { dg-final { scan-assembler "xsaddqp"  } } */
> > +/* { dg-final { scan-assembler "xssubqp"  } } */
> 
> 
>
Bill Schmidt June 14, 2016, 3:40 p.m. UTC | #4
Hi Richard,

As nobody else has replied, let me take a stab at this one.

> On Jun 10, 2016, at 2:06 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Thu, 9 Jun 2016, Michael Meissner wrote:
> 
>> I'm including the global reviewers on the list.  I just want to be sure that
>> there is no problem installing these patches on the GCC 6.2 branch.  While it
>> is technically an enchancement, it is needed to be able to install the glibc
>> support that is needed to complete the work to add IEEE 128-bit floating point.
>> 
>> The issue being fixed is that when we are creating the complex type, we used to
>> do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
>> floating point types (__ibm128 and __float128, with long double currently
>> defaulting to __ibm128).
> 
> As this enhancement includes middle-end changes I am hesitant to approve
> it for the branch.  Why is it desirable to backport this change?

It comes down to community requirements and schedules.  We are in the process of
replacing the incompatible IBM long double type with true IEEE-754 128-bit floating
point (__float128).  This is a complex multi-stage process where we will have to
maintain the functionality of the existing IBM long double for backward compatibility
while the new type is implemented.  This impacts multiple packages, starting with
gcc and glibc.

The glibc maintainers have indicated that work there depends on a certain level of
functionality within GCC.  Specifically, both the old and new types must be supported,
including corresponding complex types.  Unfortunately the realization that the complex
types had to be supported came late, and this work didn't fully make it into GCC 6.1.

(Part of the problem that has made this whole effort difficult is that it is complicated to
maintain two floating-point types of the exact same size.)

In any case, the glibc maintainers require this work in GCC 6 so that work can begin
in glibc 2.24, with completion scheduled in glibc 2.25.  We are asking for an exception 
for this patch in order to allow those schedules to move forward.

So that's the history as I understand it... Perhaps others can jump in if I've munged
or omitted anything important.

Thanks!
Bill

> 
> Thanks,
> Richard.
> 
>> On Fri, Jun 03, 2016 at 09:33:35AM -0400, Michael Meissner wrote:
>>> These patches were installed on the trunk on May 2nd, with a fix from Alan
>>> Modra on May 11th.  Unless I here objections in the next few days, I will
>>> commit these changes to the GCC 6.x branch.  These changes will allow people to
>>> use complex __float128 types (via an attribute) on the PowerPC.
>>> 
>>> Note, we will need patches to libgcc to fully enable complex __float128 support
>>> on the PowerPC.  These patches enable the compiler support, so that the libgcc
>>> changes can be coded.
>>> 
>>> In addition to bootstrapping and regtesting on the PowerPC (little endian
>>> power8), I also bootstrapped and regested the changes on x86_64 running RHEL
>>> 6.2.  There were no regressions in either case.
>>> 
>>> [gcc]
>>> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
>>> 
>>> 	Back port from trunk
>>> 	2016-05-11  Alan Modra  <amodra@gmail.com>
>>> 
>>> 	* config/rs6000/rs6000.c (is_complex_IBM_long_double,
>>> 	abi_v4_pass_in_fpr): New functions.
>>> 	(rs6000_function_arg_boundary): Exclude complex IBM long double
>>> 	from 64-bit alignment when ABI_V4.
>>> 	(rs6000_function_arg, rs6000_function_arg_advance_1,
>>> 	rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.
>>> 
>>> 	Back port from trunk
>>> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
>>> 
>>> 	* machmode.h (mode_complex): Add support to give the complex mode
>>> 	for a given mode.
>>> 	(GET_MODE_COMPLEX_MODE): Likewise.
>>> 	* stor-layout.c (layout_type): For COMPLEX_TYPE, use the mode
>>> 	stored by build_complex_type and gfc_build_complex_type instead of
>>> 	trying to figure out the appropriate mode based on the size. Raise
>>> 	an assertion error, if the type was not set.
>>> 	* genmodes.c (struct mode_data): Add field for the complex type of
>>> 	the given type.
>>> 	(blank_mode): Likewise.
>>> 	(make_complex_modes): Remember the complex mode created in the
>>> 	base type.
>>> 	(emit_mode_complex): Write out the mode_complex array to map a
>>> 	type mode to the complex version.
>>> 	(emit_insn_modes_c): Likewise.
>>> 	* tree.c (build_complex_type): Set the complex type to use before
>>> 	calling layout_type.
>>> 	* config/rs6000/rs6000.c (rs6000_hard_regno_nregs_internal): Add
>>> 	support for __float128 complex datatypes.
>>> 	(rs6000_hard_regno_mode_ok): Likewise.
>>> 	(rs6000_setup_reg_addr_masks): Likewise.
>>> 	(rs6000_complex_function_value): Likewise.
>>> 	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Likewise.
>>> 	__float128 and __ibm128 complex.
>>> 	(FLOAT128_IBM_P): Likewise.
>>> 	(ALTIVEC_ARG_MAX_RETURN): Likewise.
>>> 	* doc/extend.texi (Additional Floating Types): Document that
>>> 	-mfloat128 must be used to enable __float128.  Document complex
>>> 	__float128 and __ibm128 support.
>>> 
>>> [gcc/fortran]
>>> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
>>> 
>>> 	Back port from trunk
>>> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
>>> 
>>> 	* trans-types.c (gfc_build_complex_type):
>>> 
>>> [gcc/testsuite]
>>> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
>>> 
>>> 	Back port from trunk
>>> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
>>> 
>>> 	* gcc.target/powerpc/float128-complex-1.c: New tests for complex
>>> 	__float128.
>>> 	* gcc.target/powerpc/float128-complex-2.c: Likewise.
>>> 
>>> -- 
>>> Michael Meissner, IBM
>>> IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
>>> email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797
>> 
>>> Index: gcc/machmode.h
>>> ===================================================================
>>> --- gcc/machmode.h	(revision 237045)
>>> +++ gcc/machmode.h	(working copy)
>>> @@ -269,6 +269,10 @@ extern const unsigned char mode_wider[NU
>>> extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
>>> #define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
>>> 
>>> +/* Get the complex mode from the component mode.  */
>>> +extern const unsigned char mode_complex[NUM_MACHINE_MODES];
>>> +#define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE])
>>> +
>>> /* Return the mode for data of a given size SIZE and mode class CLASS.
>>>    If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
>>>    The value is BLKmode if no other mode is found.  */
>>> Index: gcc/stor-layout.c
>>> ===================================================================
>>> --- gcc/stor-layout.c	(revision 237045)
>>> +++ gcc/stor-layout.c	(working copy)
>>> @@ -2146,11 +2146,13 @@ layout_type (tree type)
>>> 
>>>     case COMPLEX_TYPE:
>>>       TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
>>> -      SET_TYPE_MODE (type,
>>> -		     mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)),
>>> -				    (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
>>> -				     ? MODE_COMPLEX_FLOAT : MODE_COMPLEX_INT),
>>> -				     0));
>>> +
>>> +      /* build_complex_type and fortran's gfc_build_complex_type have set the
>>> +	 expected mode to allow having multiple complex types for multiple
>>> +	 floating point types that have the same size such as the PowerPC with
>>> +	 __ibm128 and __float128.  */
>>> +      gcc_assert (TYPE_MODE (type) != VOIDmode);
>>> +
>>>       TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
>>>       TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
>>>       break;
>>> Index: gcc/genmodes.c
>>> ===================================================================
>>> --- gcc/genmodes.c	(revision 237045)
>>> +++ gcc/genmodes.c	(working copy)
>>> @@ -66,6 +66,7 @@ struct mode_data
>>> 				   this mode as a component.  */
>>>   struct mode_data *next_cont;  /* Next mode in that list.  */
>>> 
>>> +  struct mode_data *complex;	/* complex type with mode as component.  */
>>>   const char *file;		/* file and line of definition, */
>>>   unsigned int line;		/* for error reporting */
>>>   unsigned int counter;		/* Rank ordering of modes */
>>> @@ -83,7 +84,7 @@ static struct mode_data *void_mode;
>>> static const struct mode_data blank_mode = {
>>>   0, "<unknown>", MAX_MODE_CLASS,
>>>   -1U, -1U, -1U, -1U,
>>> -  0, 0, 0, 0, 0,
>>> +  0, 0, 0, 0, 0, 0,
>>>   "<unknown>", 0, 0, 0, 0, false, 0
>>> };
>>> 
>>> @@ -472,6 +473,7 @@ make_complex_modes (enum mode_class cl,
>>> 
>>>       c = new_mode (cclass, buf, file, line);
>>>       c->component = m;
>>> +      m->complex = c;
>>>     }
>>> }
>>> 
>>> @@ -1381,6 +1383,22 @@ emit_mode_wider (void)
>>> }
>>> 
>>> static void
>>> +emit_mode_complex (void)
>>> +{
>>> +  int c;
>>> +  struct mode_data *m;
>>> +
>>> +  print_decl ("unsigned char", "mode_complex", "NUM_MACHINE_MODES");
>>> +
>>> +  for_all_modes (c, m)
>>> +    tagged_printf ("%smode",
>>> +		   m->complex ? m->complex->name : void_mode->name,
>>> +		   m->name);
>>> +
>>> +  print_closer ();
>>> +}
>>> +
>>> +static void
>>> emit_mode_mask (void)
>>> {
>>>   int c;
>>> @@ -1745,6 +1763,7 @@ emit_insn_modes_c (void)
>>>   emit_mode_size ();
>>>   emit_mode_nunits ();
>>>   emit_mode_wider ();
>>> +  emit_mode_complex ();
>>>   emit_mode_mask ();
>>>   emit_mode_inner ();
>>>   emit_mode_unit_size ();
>>> Index: gcc/tree.c
>>> ===================================================================
>>> --- gcc/tree.c	(revision 237045)
>>> +++ gcc/tree.c	(working copy)
>>> @@ -8675,6 +8675,7 @@ build_complex_type (tree component_type)
>>>   t = make_node (COMPLEX_TYPE);
>>> 
>>>   TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
>>> +  SET_TYPE_MODE (t, GET_MODE_COMPLEX_MODE (TYPE_MODE (component_type)));
>>> 
>>>   /* If we already have such a type, use the old one.  */
>>>   hstate.add_object (TYPE_HASH (component_type));
>>> Index: gcc/config/rs6000/rs6000.c
>>> ===================================================================
>>> --- gcc/config/rs6000/rs6000.c	(revision 237045)
>>> +++ gcc/config/rs6000/rs6000.c	(working copy)
>>> @@ -1882,7 +1882,7 @@ rs6000_hard_regno_nregs_internal (int re
>>>      128-bit floating point that can go in vector registers, which has VSX
>>>      memory addressing.  */
>>>   if (FP_REGNO_P (regno))
>>> -    reg_size = (VECTOR_MEM_VSX_P (mode)
>>> +    reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode)
>>> 		? UNITS_PER_VSX_WORD
>>> 		: UNITS_PER_FP_WORD);
>>> 
>>> @@ -1914,6 +1914,9 @@ rs6000_hard_regno_mode_ok (int regno, ma
>>> {
>>>   int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1;
>>> 
>>> +  if (COMPLEX_MODE_P (mode))
>>> +    mode = GET_MODE_INNER (mode);
>>> +
>>>   /* PTImode can only go in GPRs.  Quad word memory operations require even/odd
>>>      register combinations, and use PTImode where we need to deal with quad
>>>      word memory operations.  Don't allow quad words in the argument or frame
>>> @@ -2716,8 +2719,17 @@ rs6000_setup_reg_addr_masks (void)
>>> 
>>>   for (m = 0; m < NUM_MACHINE_MODES; ++m)
>>>     {
>>> -      machine_mode m2 = (machine_mode)m;
>>> -      unsigned short msize = GET_MODE_SIZE (m2);
>>> +      machine_mode m2 = (machine_mode) m;
>>> +      bool complex_p = false;
>>> +      size_t msize;
>>> +
>>> +      if (COMPLEX_MODE_P (m2))
>>> +	{
>>> +	  complex_p = true;
>>> +	  m2 = GET_MODE_INNER (m2);
>>> +	}
>>> +
>>> +      msize = GET_MODE_SIZE (m2);
>>> 
>>>       /* SDmode is special in that we want to access it only via REG+REG
>>> 	 addressing on power7 and above, since we want to use the LFIWZX and
>>> @@ -2739,7 +2751,7 @@ rs6000_setup_reg_addr_masks (void)
>>> 	      /* Indicate if the mode takes more than 1 physical register.  If
>>> 		 it takes a single register, indicate it can do REG+REG
>>> 		 addressing.  */
>>> -	      if (nregs > 1 || m == BLKmode)
>>> +	      if (nregs > 1 || m == BLKmode || complex_p)
>>> 		addr_mask |= RELOAD_REG_MULTIPLE;
>>> 	      else
>>> 		addr_mask |= RELOAD_REG_INDEXED;
>>> @@ -2755,7 +2767,7 @@ rs6000_setup_reg_addr_masks (void)
>>> 		  && msize <= 8
>>> 		  && !VECTOR_MODE_P (m2)
>>> 		  && !FLOAT128_VECTOR_P (m2)
>>> -		  && !COMPLEX_MODE_P (m2)
>>> +		  && !complex_p
>>> 		  && (m2 != DFmode || !TARGET_UPPER_REGS_DF)
>>> 		  && (m2 != SFmode || !TARGET_UPPER_REGS_SF)
>>> 		  && !(TARGET_E500_DOUBLE && msize == 8))
>>> @@ -10266,6 +10278,35 @@ rs6000_must_pass_in_stack (machine_mode 
>>>     return must_pass_in_stack_var_size_or_pad (mode, type);
>>> }
>>> 
>>> +static inline bool
>>> +is_complex_IBM_long_double (machine_mode mode)
>>> +{
>>> +  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
>>> +}
>>> +
>>> +/* Whether ABI_V4 passes MODE args to a function in floating point
>>> +   registers.  */
>>> +
>>> +static bool
>>> +abi_v4_pass_in_fpr (machine_mode mode)
>>> +{
>>> +  if (!TARGET_FPRS || !TARGET_HARD_FLOAT)
>>> +    return false;
>>> +  if (TARGET_SINGLE_FLOAT && mode == SFmode)
>>> +    return true;
>>> +  if (TARGET_DOUBLE_FLOAT && mode == DFmode)
>>> +    return true;
>>> +  /* ABI_V4 passes complex IBM long double in 8 gprs.
>>> +     Stupid, but we can't change the ABI now.  */
>>> +  if (is_complex_IBM_long_double (mode))
>>> +    return false;
>>> +  if (FLOAT128_2REG_P (mode))
>>> +    return true;
>>> +  if (DECIMAL_FLOAT_MODE_P (mode))
>>> +    return true;
>>> +  return false;
>>> +}
>>> +
>>> /* If defined, a C expression which determines whether, and in which
>>>    direction, to pad out an argument with extra space.  The value
>>>    should be of type `enum direction': either `upward' to pad above
>>> @@ -10350,6 +10391,7 @@ rs6000_function_arg_boundary (machine_mo
>>>       && (GET_MODE_SIZE (mode) == 8
>>> 	  || (TARGET_HARD_FLOAT
>>> 	      && TARGET_FPRS
>>> +	      && !is_complex_IBM_long_double (mode)
>>> 	      && FLOAT128_2REG_P (mode))))
>>>     return 64;
>>>   else if (FLOAT128_VECTOR_P (mode))
>>> @@ -10729,11 +10771,7 @@ rs6000_function_arg_advance_1 (CUMULATIV
>>>     }
>>>   else if (DEFAULT_ABI == ABI_V4)
>>>     {
>>> -      if (TARGET_HARD_FLOAT && TARGET_FPRS
>>> -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
>>> -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
>>> -	      || FLOAT128_2REG_P (mode)
>>> -	      || DECIMAL_FLOAT_MODE_P (mode)))
>>> +      if (abi_v4_pass_in_fpr (mode))
>>> 	{
>>> 	  /* _Decimal128 must use an even/odd register pair.  This assumes
>>> 	     that the register number is odd when fregno is odd.  */
>>> @@ -11390,11 +11428,7 @@ rs6000_function_arg (cumulative_args_t c
>>> 
>>>   else if (abi == ABI_V4)
>>>     {
>>> -      if (TARGET_HARD_FLOAT && TARGET_FPRS
>>> -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
>>> -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
>>> -	      || FLOAT128_2REG_P (mode)
>>> -	      || DECIMAL_FLOAT_MODE_P (mode)))
>>> +      if (abi_v4_pass_in_fpr (mode))
>>> 	{
>>> 	  /* _Decimal128 must use an even/odd register pair.  This assumes
>>> 	     that the register number is odd when fregno is odd.  */
>>> @@ -12315,19 +12349,15 @@ rs6000_gimplify_va_arg (tree valist, tre
>>>   rsize = (size + 3) / 4;
>>>   align = 1;
>>> 
>>> -  if (TARGET_HARD_FLOAT && TARGET_FPRS
>>> -      && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode)
>>> -          || (TARGET_DOUBLE_FLOAT 
>>> -              && (TYPE_MODE (type) == DFmode 
>>> -		  || FLOAT128_2REG_P (TYPE_MODE (type))
>>> -		  || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))))))
>>> +  machine_mode mode = TYPE_MODE (type);
>>> +  if (abi_v4_pass_in_fpr (mode))
>>>     {
>>>       /* FP args go in FP registers, if present.  */
>>>       reg = fpr;
>>>       n_reg = (size + 7) / 8;
>>>       sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4;
>>>       sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4);
>>> -      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
>>> +      if (mode != SFmode && mode != SDmode)
>>> 	align = 8;
>>>     }
>>>   else
>>> @@ -12347,7 +12377,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>>>   addr = create_tmp_var (ptr_type_node, "addr");
>>> 
>>>   /*  AltiVec vectors never go in registers when -mabi=altivec.  */
>>> -  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
>>> +  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
>>>     align = 16;
>>>   else
>>>     {
>>> @@ -12368,7 +12398,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>>> 	}
>>>       /* _Decimal128 is passed in even/odd fpr pairs; the stored
>>> 	 reg number is 0 for f1, so we want to make it odd.  */
>>> -      else if (reg == fpr && TYPE_MODE (type) == TDmode)
>>> +      else if (reg == fpr && mode == TDmode)
>>> 	{
>>> 	  t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg),
>>> 		      build_int_cst (TREE_TYPE (reg), 1));
>>> @@ -12395,7 +12425,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>>> 	 FP register for 32-bit binaries.  */
>>>       if (TARGET_32BIT
>>> 	  && TARGET_HARD_FLOAT && TARGET_FPRS
>>> -	  && TYPE_MODE (type) == SDmode)
>>> +	  && mode == SDmode)
>>> 	t = fold_build_pointer_plus_hwi (t, size);
>>> 
>>>       gimplify_assign (addr, t, pre_p);
>>> @@ -18464,25 +18494,33 @@ rs6000_secondary_reload_memory (rtx addr
>>>     addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX]
>>> 		 & ~RELOAD_REG_AND_M16);
>>> 
>>> -  else
>>> +  /* If the register allocator hasn't made up its mind yet on the register
>>> +     class to use, settle on defaults to use.  */
>>> +  else if (rclass == NO_REGS)
>>>     {
>>> -      if (TARGET_DEBUG_ADDR)
>>> -	fprintf (stderr,
>>> -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
>>> -		 "class is not GPR, FPR, VMX\n",
>>> -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
>>> +      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_ANY]
>>> +		   & ~RELOAD_REG_AND_M16);
>>> 
>>> -      return -1;
>>> +      if ((addr_mask & RELOAD_REG_MULTIPLE) != 0)
>>> +	addr_mask &= ~(RELOAD_REG_INDEXED
>>> +		       | RELOAD_REG_PRE_INCDEC
>>> +		       | RELOAD_REG_PRE_MODIFY);
>>>     }
>>> 
>>> +  else
>>> +    addr_mask = 0;
>>> +
>>>   /* If the register isn't valid in this register class, just return now.  */
>>>   if ((addr_mask & RELOAD_REG_VALID) == 0)
>>>     {
>>>       if (TARGET_DEBUG_ADDR)
>>> -	fprintf (stderr,
>>> -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
>>> -		 "not valid in class\n",
>>> -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
>>> +	{
>>> +	  fprintf (stderr,
>>> +		   "rs6000_secondary_reload_memory: mode = %s, class = %s, "
>>> +		   "not valid in class\n",
>>> +		   GET_MODE_NAME (mode), reg_class_names[rclass]);
>>> +	  debug_rtx (addr);
>>> +	}
>>> 
>>>       return -1;
>>>     }
>>> @@ -19143,6 +19181,9 @@ rs6000_secondary_reload (bool in_p,
>>> 	fprintf (stderr, ", reload func = %s, extra cost = %d",
>>> 		 insn_data[sri->icode].name, sri->extra_cost);
>>> 
>>> +      else if (sri->extra_cost > 0)
>>> +	fprintf (stderr, ", extra cost = %d", sri->extra_cost);
>>> +
>>>       fputs ("\n", stderr);
>>>       debug_rtx (x);
>>>     }
>>> @@ -19553,6 +19594,16 @@ rs6000_preferred_reload_class (rtx x, en
>>>   machine_mode mode = GET_MODE (x);
>>>   bool is_constant = CONSTANT_P (x);
>>> 
>>> +  /* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred
>>> +     reload class for it.  */
>>> +  if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS)
>>> +      && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0)
>>> +    return NO_REGS;
>>> +
>>> +  if ((rclass == FLOAT_REGS || rclass == VSX_REGS)
>>> +      && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
>>> +    return NO_REGS;
>>> +
>>>   /* For VSX, see if we should prefer FLOAT_REGS or ALTIVEC_REGS.  Do not allow
>>>      the reloading of address expressions using PLUS into floating point
>>>      registers.  */
>>> @@ -19603,6 +19654,25 @@ rs6000_preferred_reload_class (rtx x, en
>>>       return NO_REGS;
>>>     }
>>> 
>>> +  /* If we haven't picked a register class, and the type is a vector or
>>> +     floating point type, prefer to use the VSX, FPR, or Altivec register
>>> +     classes.  */
>>> +  if (rclass == NO_REGS)
>>> +    {
>>> +      if (TARGET_VSX && VECTOR_MEM_VSX_OR_P8_VECTOR_P (mode))
>>> +	return VSX_REGS;
>>> +
>>> +      if (TARGET_ALTIVEC && VECTOR_MEM_ALTIVEC_P (mode))
>>> +	return ALTIVEC_REGS;
>>> +
>>> +      if (DECIMAL_FLOAT_MODE_P (mode))
>>> +	return TARGET_DFP ? FLOAT_REGS : NO_REGS;
>>> +
>>> +      if (TARGET_FPRS && TARGET_HARD_FLOAT && FLOAT_MODE_P (mode)
>>> +	  && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
>>> +	return FLOAT_REGS;
>>> +    }
>>> +
>>>   if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS)
>>>     return GENERAL_REGS;
>>> 
>>> @@ -34549,8 +34619,14 @@ rs6000_complex_function_value (machine_m
>>>   machine_mode inner = GET_MODE_INNER (mode);
>>>   unsigned int inner_bytes = GET_MODE_UNIT_SIZE (mode);
>>> 
>>> -  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
>>> +  if (TARGET_FLOAT128
>>> +      && (mode == KCmode
>>> +	  || (mode == TCmode && TARGET_IEEEQUAD)))
>>> +    regno = ALTIVEC_ARG_RETURN;
>>> +
>>> +  else if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
>>>     regno = FP_ARG_RETURN;
>>> +
>>>   else
>>>     {
>>>       regno = GP_ARG_RETURN;
>>> Index: gcc/config/rs6000/rs6000.h
>>> ===================================================================
>>> --- gcc/config/rs6000/rs6000.h	(revision 237045)
>>> +++ gcc/config/rs6000/rs6000.h	(working copy)
>>> @@ -418,12 +418,12 @@ extern const char *host_detect_local_cpu
>>>    Similarly IFmode is the IBM long double format even if the default is IEEE
>>>    128-bit.  */
>>> #define FLOAT128_IEEE_P(MODE)						\
>>> -  (((MODE) == TFmode && TARGET_IEEEQUAD)				\
>>> -   || ((MODE) == KFmode))
>>> +  ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
>>> +   || ((MODE) == KFmode) || ((MODE) == KCmode))
>>> 
>>> #define FLOAT128_IBM_P(MODE)						\
>>> -  (((MODE) == TFmode && !TARGET_IEEEQUAD)				\
>>> -   || ((MODE) == IFmode))
>>> +  ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
>>> +   || ((MODE) == IFmode) || ((MODE) == ICmode))
>>> 
>>> /* Helper macros to say whether a 128-bit floating point type can go in a
>>>    single vector register, or whether it needs paired scalar values.  */
>>> @@ -1789,7 +1789,9 @@ extern enum reg_class rs6000_constraints
>>> #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
>>> #define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN	\
>>> 			   : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
>>> -#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
>>> +#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2		\
>>> +				? (ALTIVEC_ARG_RETURN			\
>>> +				   + (TARGET_FLOAT128 ? 1 : 0))		\
>>> 			        : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
>>> 
>>> /* Flags for the call/call_value rtl operations set up by function_arg */
>>> Index: gcc/doc/extend.texi
>>> ===================================================================
>>> --- gcc/doc/extend.texi	(revision 237045)
>>> +++ gcc/doc/extend.texi	(working copy)
>>> @@ -962,8 +962,13 @@ complex @code{__float128} type.  When th
>>> would use the following syntax to declare @code{_Complex128} to be a
>>> complex @code{__float128} type:
>>> 
>>> +On the PowerPC Linux VSX targets, you can declare complex types using
>>> +the corresponding internal complex type, @code{KCmode} for
>>> +@code{__float128} type and @code{ICmode} for @code{__ibm128} type:
>>> +
>>> @smallexample
>>> -typedef _Complex float __attribute__((mode(KC))) _Complex128;
>>> +typedef _Complex float __attribute__((mode(KC))) _Complex_float128;
>>> +typedef _Complex float __attribute__((mode(IC))) _Complex_ibm128;
>>> @end smallexample
>>> 
>>> Not all targets support additional floating-point types.
>>> Index: gcc/fortran/trans-types.c
>>> ===================================================================
>>> --- gcc/fortran/trans-types.c	(revision 237045)
>>> +++ gcc/fortran/trans-types.c	(working copy)
>>> @@ -828,6 +828,7 @@ gfc_build_complex_type (tree scalar_type
>>> 
>>>   new_type = make_node (COMPLEX_TYPE);
>>>   TREE_TYPE (new_type) = scalar_type;
>>> +  SET_TYPE_MODE (new_type, GET_MODE_COMPLEX_MODE (TYPE_MODE (scalar_type)));
>>>   layout_type (new_type);
>>>   return new_type;
>>> }
>>> Index: gcc/testsuite/gcc.target/powerpc/float128-complex-1.c
>>> ===================================================================
>>> --- gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
>>> +++ gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
>>> @@ -0,0 +1,157 @@
>>> +/* { dg-do compile { target { powerpc*-*-linux* } } } */
>>> +/* { dg-require-effective-target powerpc_float128_sw_ok } */
>>> +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
>>> +/* { dg-options "-O2 -mcpu=power7 -mfloat128" } */
>>> +
>>> +#ifndef NO_FLOAT
>>> +typedef _Complex float	float_complex;
>>> +extern float_complex cfloat1 (void);
>>> +extern float_complex cfloat2 (void);
>>> +
>>> +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
>>> +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
>>> +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
>>> +
>>> +#else
>>> +#define FLOAT_ARG(NAME, OP)
>>> +#define FLOAT_PTR(NAME, OP)
>>> +#define FLOAT_CALL()
>>> +#endif
>>> +
>>> +#ifndef NO_DOUBLE
>>> +typedef _Complex double	double_complex;
>>> +extern double_complex cdouble1 (void);
>>> +extern double_complex cdouble2 (void);
>>> +
>>> +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
>>> +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
>>> +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
>>> +
>>> +#else
>>> +#define DOUBLE_ARG(NAME, OP)
>>> +#define DOUBLE_PTR(NAME, OP)
>>> +#define DOUBLE_CALL()
>>> +#endif
>>> +
>>> +#ifndef NO_FLOAT128
>>> +#ifdef __VSX__
>>> +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
>>> +#else
>>> +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
>>> +#endif
>>> +
>>> +extern float128_complex cfloat128_1 (void);
>>> +extern float128_complex cfloat128_2 (void);
>>> +
>>> +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
>>> +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
>>> +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
>>> +
>>> +#else
>>> +#define FLOAT128_ARG(NAME, OP)
>>> +#define FLOAT128_PTR(NAME, OP)
>>> +#define FLOAT128_CALL()
>>> +#endif
>>> +
>>> +#ifndef NO_LDOUBLE
>>> +typedef _Complex long double ldouble_complex;
>>> +extern ldouble_complex cldouble1 (void);
>>> +extern ldouble_complex cldouble2 (void);
>>> +
>>> +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
>>> +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
>>> +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
>>> +
>>> +#else
>>> +#define LDOUBLE_ARG(NAME, OP)
>>> +#define LDOUBLE_PTR(NAME, OP)
>>> +#define LDOUBLE_CALL()
>>> +#endif
>>> +
>>> +
>>> +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
>>> +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
>>> +{									\
>>> +  return a OP b;							\
>>> +}
>>> +
>>> +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
>>> +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
>>> +{									\
>>> +  *p = *a OP *b;							\
>>> +}
>>> +
>>> +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
>>> +TYPE call_ ## SUFFIX (void)						\
>>> +{									\
>>> +  TYPE value1 = FUNC1 ();						\
>>> +  TYPE value2 = FUNC2 ();						\
>>> +  return value1 + value2;						\
>>> +}
>>> +
>>> +#ifndef NO_ARG
>>> +#ifndef NO_ADD
>>> +FLOAT_ARG    (add, +)
>>> +DOUBLE_ARG   (add, +)
>>> +FLOAT128_ARG (add, +)
>>> +LDOUBLE_ARG  (add, +)
>>> +#endif
>>> +
>>> +#ifndef NO_SUB
>>> +FLOAT_ARG    (sub, -)
>>> +DOUBLE_ARG   (sub, -)
>>> +FLOAT128_ARG (sub, -)
>>> +LDOUBLE_ARG  (sub, -)
>>> +#endif
>>> +
>>> +#ifndef NO_MUL
>>> +FLOAT_ARG    (mul, *)
>>> +DOUBLE_ARG   (mul, *)
>>> +FLOAT128_ARG (mul, *)
>>> +LDOUBLE_ARG  (mul, *)
>>> +#endif
>>> +
>>> +#ifndef NO_DIV
>>> +FLOAT_ARG    (div, /)
>>> +DOUBLE_ARG   (div, /)
>>> +FLOAT128_ARG (div, /)
>>> +LDOUBLE_ARG  (div, /)
>>> +#endif
>>> +#endif
>>> +
>>> +#ifndef NO_PTR
>>> +#ifndef NO_ADD
>>> +FLOAT_PTR    (add, +)
>>> +DOUBLE_PTR   (add, +)
>>> +FLOAT128_PTR (add, +)
>>> +LDOUBLE_PTR  (add, +)
>>> +#endif
>>> +
>>> +#ifndef NO_SUB
>>> +FLOAT_PTR    (sub, -)
>>> +DOUBLE_PTR   (sub, -)
>>> +FLOAT128_PTR (sub, -)
>>> +LDOUBLE_PTR  (sub, -)
>>> +#endif
>>> +
>>> +#ifndef NO_MUL
>>> +FLOAT_PTR    (mul, *)
>>> +DOUBLE_PTR   (mul, *)
>>> +FLOAT128_PTR (mul, *)
>>> +LDOUBLE_PTR  (mul, *)
>>> +#endif
>>> +
>>> +#ifndef NO_DIV
>>> +FLOAT_PTR    (div, /)
>>> +DOUBLE_PTR   (div, /)
>>> +FLOAT128_PTR (div, /)
>>> +LDOUBLE_PTR  (div, /)
>>> +#endif
>>> +#endif
>>> +
>>> +#ifndef NO_CALL
>>> +FLOAT_CALL    ()
>>> +DOUBLE_CALL   ()
>>> +FLOAT128_CALL ()
>>> +LDOUBLE_CALL  ()
>>> +#endif
>>> Index: gcc/testsuite/gcc.target/powerpc/float128-complex-2.c
>>> ===================================================================
>>> --- gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
>>> +++ gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
>>> @@ -0,0 +1,160 @@
>>> +/* { dg-do compile { target { powerpc*-*-linux* } } } */
>>> +/* { dg-require-effective-target powerpc_float128_hw_ok } */
>>> +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
>>> +/* { dg-options "-O2 -mcpu=power9 -mfloat128 -mfloat128-hardware" } */
>>> +
>>> +#ifndef NO_FLOAT
>>> +typedef _Complex float	float_complex;
>>> +extern float_complex cfloat1 (void);
>>> +extern float_complex cfloat2 (void);
>>> +
>>> +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
>>> +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
>>> +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
>>> +
>>> +#else
>>> +#define FLOAT_ARG(NAME, OP)
>>> +#define FLOAT_PTR(NAME, OP)
>>> +#define FLOAT_CALL()
>>> +#endif
>>> +
>>> +#ifndef NO_DOUBLE
>>> +typedef _Complex double	double_complex;
>>> +extern double_complex cdouble1 (void);
>>> +extern double_complex cdouble2 (void);
>>> +
>>> +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
>>> +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
>>> +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
>>> +
>>> +#else
>>> +#define DOUBLE_ARG(NAME, OP)
>>> +#define DOUBLE_PTR(NAME, OP)
>>> +#define DOUBLE_CALL()
>>> +#endif
>>> +
>>> +#ifndef NO_FLOAT128
>>> +#ifdef __VSX__
>>> +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
>>> +#else
>>> +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
>>> +#endif
>>> +
>>> +extern float128_complex cfloat128_1 (void);
>>> +extern float128_complex cfloat128_2 (void);
>>> +
>>> +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
>>> +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
>>> +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
>>> +
>>> +#else
>>> +#define FLOAT128_ARG(NAME, OP)
>>> +#define FLOAT128_PTR(NAME, OP)
>>> +#define FLOAT128_CALL()
>>> +#endif
>>> +
>>> +#ifndef NO_LDOUBLE
>>> +typedef _Complex long double ldouble_complex;
>>> +extern ldouble_complex cldouble1 (void);
>>> +extern ldouble_complex cldouble2 (void);
>>> +
>>> +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
>>> +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
>>> +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
>>> +
>>> +#else
>>> +#define LDOUBLE_ARG(NAME, OP)
>>> +#define LDOUBLE_PTR(NAME, OP)
>>> +#define LDOUBLE_CALL()
>>> +#endif
>>> +
>>> +
>>> +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
>>> +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
>>> +{									\
>>> +  return a OP b;							\
>>> +}
>>> +
>>> +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
>>> +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
>>> +{									\
>>> +  *p = *a OP *b;							\
>>> +}
>>> +
>>> +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
>>> +TYPE call_ ## SUFFIX (void)						\
>>> +{									\
>>> +  TYPE value1 = FUNC1 ();						\
>>> +  TYPE value2 = FUNC2 ();						\
>>> +  return value1 + value2;						\
>>> +}
>>> +
>>> +#ifndef NO_ARG
>>> +#ifndef NO_ADD
>>> +FLOAT_ARG    (add, +)
>>> +DOUBLE_ARG   (add, +)
>>> +FLOAT128_ARG (add, +)
>>> +LDOUBLE_ARG  (add, +)
>>> +#endif
>>> +
>>> +#ifndef NO_SUB
>>> +FLOAT_ARG    (sub, -)
>>> +DOUBLE_ARG   (sub, -)
>>> +FLOAT128_ARG (sub, -)
>>> +LDOUBLE_ARG  (sub, -)
>>> +#endif
>>> +
>>> +#ifndef NO_MUL
>>> +FLOAT_ARG    (mul, *)
>>> +DOUBLE_ARG   (mul, *)
>>> +FLOAT128_ARG (mul, *)
>>> +LDOUBLE_ARG  (mul, *)
>>> +#endif
>>> +
>>> +#ifndef NO_DIV
>>> +FLOAT_ARG    (div, /)
>>> +DOUBLE_ARG   (div, /)
>>> +FLOAT128_ARG (div, /)
>>> +LDOUBLE_ARG  (div, /)
>>> +#endif
>>> +#endif
>>> +
>>> +#ifndef NO_PTR
>>> +#ifndef NO_ADD
>>> +FLOAT_PTR    (add, +)
>>> +DOUBLE_PTR   (add, +)
>>> +FLOAT128_PTR (add, +)
>>> +LDOUBLE_PTR  (add, +)
>>> +#endif
>>> +
>>> +#ifndef NO_SUB
>>> +FLOAT_PTR    (sub, -)
>>> +DOUBLE_PTR   (sub, -)
>>> +FLOAT128_PTR (sub, -)
>>> +LDOUBLE_PTR  (sub, -)
>>> +#endif
>>> +
>>> +#ifndef NO_MUL
>>> +FLOAT_PTR    (mul, *)
>>> +DOUBLE_PTR   (mul, *)
>>> +FLOAT128_PTR (mul, *)
>>> +LDOUBLE_PTR  (mul, *)
>>> +#endif
>>> +
>>> +#ifndef NO_DIV
>>> +FLOAT_PTR    (div, /)
>>> +DOUBLE_PTR   (div, /)
>>> +FLOAT128_PTR (div, /)
>>> +LDOUBLE_PTR  (div, /)
>>> +#endif
>>> +#endif
>>> +
>>> +#ifndef NO_CALL
>>> +FLOAT_CALL    ()
>>> +DOUBLE_CALL   ()
>>> +FLOAT128_CALL ()
>>> +LDOUBLE_CALL  ()
>>> +#endif
>>> +
>>> +/* { dg-final { scan-assembler "xsaddqp"  } } */
>>> +/* { dg-final { scan-assembler "xssubqp"  } } */
>> 
>> 
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
Richard Biener June 15, 2016, 9:01 a.m. UTC | #5
On Tue, 14 Jun 2016, Bill Schmidt wrote:

> Hi Richard,
> 
> As nobody else has replied, let me take a stab at this one.
> 
> > On Jun 10, 2016, at 2:06 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Thu, 9 Jun 2016, Michael Meissner wrote:
> > 
> >> I'm including the global reviewers on the list.  I just want to be sure that
> >> there is no problem installing these patches on the GCC 6.2 branch.  While it
> >> is technically an enchancement, it is needed to be able to install the glibc
> >> support that is needed to complete the work to add IEEE 128-bit floating point.
> >> 
> >> The issue being fixed is that when we are creating the complex type, we used to
> >> do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
> >> floating point types (__ibm128 and __float128, with long double currently
> >> defaulting to __ibm128).
> > 
> > As this enhancement includes middle-end changes I am hesitant to approve
> > it for the branch.  Why is it desirable to backport this change?
> 
> It comes down to community requirements and schedules.  We are in the process of
> replacing the incompatible IBM long double type with true IEEE-754 128-bit floating
> point (__float128).  This is a complex multi-stage process where we will have to
> maintain the functionality of the existing IBM long double for backward compatibility
> while the new type is implemented.  This impacts multiple packages, starting with
> gcc and glibc.
> 
> The glibc maintainers have indicated that work there depends on a certain level of
> functionality within GCC.  Specifically, both the old and new types must be supported,
> including corresponding complex types.  Unfortunately the realization that the complex
> types had to be supported came late, and this work didn't fully make it into GCC 6.1.
> 
> (Part of the problem that has made this whole effort difficult is that it is complicated to
> maintain two floating-point types of the exact same size.)
> 
> In any case, the glibc maintainers require this work in GCC 6 so that work can begin
> in glibc 2.24, with completion scheduled in glibc 2.25.  We are asking for an exception 
> for this patch in order to allow those schedules to move forward.
> 
> So that's the history as I understand it... Perhaps others can jump in if I've munged
> or omitted anything important.

Ok, I see the reason for the backport then.  Looking at the patch
the only fragile thing is the layout_type change give it adds an assert
and you did need to change frontends (but not all of them?).  I'm not
sure about testsuite coverage for complex type for, say, Go or Ada
or Java.

And I don't understand the layout_type change either - it looks to me
it could just have used

  SET_TYPE_MODE (type, GET_MODE_COMPLEX_MODE (TYPE_MODE 
(TREE_TYPE (type))));

and be done with it.  To me that looks a lot safer.

With now having two complex FP modes with the same size how does
iteration over MODE_COMPLEX_FLOAT work with GET_MODE_WIDER_MODE?
Is the outcome random?  Or do we visit both modes?  That is, could
GET_MODE_COMPLEX_MODE be implemented with iterating over complex modes
and in addition to size also match the component mode instead?

[I realize this is just backports but at least the layout_type change
looks dangerous to me]

Thanks,
Richard.

> Thanks!
> Bill
> 
> > 
> > Thanks,
> > Richard.
> > 
> >> On Fri, Jun 03, 2016 at 09:33:35AM -0400, Michael Meissner wrote:
> >>> These patches were installed on the trunk on May 2nd, with a fix from Alan
> >>> Modra on May 11th.  Unless I here objections in the next few days, I will
> >>> commit these changes to the GCC 6.x branch.  These changes will allow people to
> >>> use complex __float128 types (via an attribute) on the PowerPC.
> >>> 
> >>> Note, we will need patches to libgcc to fully enable complex __float128 support
> >>> on the PowerPC.  These patches enable the compiler support, so that the libgcc
> >>> changes can be coded.
> >>> 
> >>> In addition to bootstrapping and regtesting on the PowerPC (little endian
> >>> power8), I also bootstrapped and regested the changes on x86_64 running RHEL
> >>> 6.2.  There were no regressions in either case.
> >>> 
> >>> [gcc]
> >>> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> >>> 
> >>> 	Back port from trunk
> >>> 	2016-05-11  Alan Modra  <amodra@gmail.com>
> >>> 
> >>> 	* config/rs6000/rs6000.c (is_complex_IBM_long_double,
> >>> 	abi_v4_pass_in_fpr): New functions.
> >>> 	(rs6000_function_arg_boundary): Exclude complex IBM long double
> >>> 	from 64-bit alignment when ABI_V4.
> >>> 	(rs6000_function_arg, rs6000_function_arg_advance_1,
> >>> 	rs6000_gimplify_va_arg): Use abi_v4_pass_in_fpr.
> >>> 
> >>> 	Back port from trunk
> >>> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> >>> 
> >>> 	* machmode.h (mode_complex): Add support to give the complex mode
> >>> 	for a given mode.
> >>> 	(GET_MODE_COMPLEX_MODE): Likewise.
> >>> 	* stor-layout.c (layout_type): For COMPLEX_TYPE, use the mode
> >>> 	stored by build_complex_type and gfc_build_complex_type instead of
> >>> 	trying to figure out the appropriate mode based on the size. Raise
> >>> 	an assertion error, if the type was not set.
> >>> 	* genmodes.c (struct mode_data): Add field for the complex type of
> >>> 	the given type.
> >>> 	(blank_mode): Likewise.
> >>> 	(make_complex_modes): Remember the complex mode created in the
> >>> 	base type.
> >>> 	(emit_mode_complex): Write out the mode_complex array to map a
> >>> 	type mode to the complex version.
> >>> 	(emit_insn_modes_c): Likewise.
> >>> 	* tree.c (build_complex_type): Set the complex type to use before
> >>> 	calling layout_type.
> >>> 	* config/rs6000/rs6000.c (rs6000_hard_regno_nregs_internal): Add
> >>> 	support for __float128 complex datatypes.
> >>> 	(rs6000_hard_regno_mode_ok): Likewise.
> >>> 	(rs6000_setup_reg_addr_masks): Likewise.
> >>> 	(rs6000_complex_function_value): Likewise.
> >>> 	* config/rs6000/rs6000.h (FLOAT128_IEEE_P): Likewise.
> >>> 	__float128 and __ibm128 complex.
> >>> 	(FLOAT128_IBM_P): Likewise.
> >>> 	(ALTIVEC_ARG_MAX_RETURN): Likewise.
> >>> 	* doc/extend.texi (Additional Floating Types): Document that
> >>> 	-mfloat128 must be used to enable __float128.  Document complex
> >>> 	__float128 and __ibm128 support.
> >>> 
> >>> [gcc/fortran]
> >>> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> >>> 
> >>> 	Back port from trunk
> >>> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> >>> 
> >>> 	* trans-types.c (gfc_build_complex_type):
> >>> 
> >>> [gcc/testsuite]
> >>> 2016-06-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> >>> 
> >>> 	Back port from trunk
> >>> 	2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
> >>> 
> >>> 	* gcc.target/powerpc/float128-complex-1.c: New tests for complex
> >>> 	__float128.
> >>> 	* gcc.target/powerpc/float128-complex-2.c: Likewise.
> >>> 
> >>> -- 
> >>> Michael Meissner, IBM
> >>> IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
> >>> email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797
> >> 
> >>> Index: gcc/machmode.h
> >>> ===================================================================
> >>> --- gcc/machmode.h	(revision 237045)
> >>> +++ gcc/machmode.h	(working copy)
> >>> @@ -269,6 +269,10 @@ extern const unsigned char mode_wider[NU
> >>> extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
> >>> #define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
> >>> 
> >>> +/* Get the complex mode from the component mode.  */
> >>> +extern const unsigned char mode_complex[NUM_MACHINE_MODES];
> >>> +#define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE])
> >>> +
> >>> /* Return the mode for data of a given size SIZE and mode class CLASS.
> >>>    If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
> >>>    The value is BLKmode if no other mode is found.  */
> >>> Index: gcc/stor-layout.c
> >>> ===================================================================
> >>> --- gcc/stor-layout.c	(revision 237045)
> >>> +++ gcc/stor-layout.c	(working copy)
> >>> @@ -2146,11 +2146,13 @@ layout_type (tree type)
> >>> 
> >>>     case COMPLEX_TYPE:
> >>>       TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
> >>> -      SET_TYPE_MODE (type,
> >>> -		     mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)),
> >>> -				    (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
> >>> -				     ? MODE_COMPLEX_FLOAT : MODE_COMPLEX_INT),
> >>> -				     0));
> >>> +
> >>> +      /* build_complex_type and fortran's gfc_build_complex_type have set the
> >>> +	 expected mode to allow having multiple complex types for multiple
> >>> +	 floating point types that have the same size such as the PowerPC with
> >>> +	 __ibm128 and __float128.  */
> >>> +      gcc_assert (TYPE_MODE (type) != VOIDmode);
> >>> +
> >>>       TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
> >>>       TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
> >>>       break;
> >>> Index: gcc/genmodes.c
> >>> ===================================================================
> >>> --- gcc/genmodes.c	(revision 237045)
> >>> +++ gcc/genmodes.c	(working copy)
> >>> @@ -66,6 +66,7 @@ struct mode_data
> >>> 				   this mode as a component.  */
> >>>   struct mode_data *next_cont;  /* Next mode in that list.  */
> >>> 
> >>> +  struct mode_data *complex;	/* complex type with mode as component.  */
> >>>   const char *file;		/* file and line of definition, */
> >>>   unsigned int line;		/* for error reporting */
> >>>   unsigned int counter;		/* Rank ordering of modes */
> >>> @@ -83,7 +84,7 @@ static struct mode_data *void_mode;
> >>> static const struct mode_data blank_mode = {
> >>>   0, "<unknown>", MAX_MODE_CLASS,
> >>>   -1U, -1U, -1U, -1U,
> >>> -  0, 0, 0, 0, 0,
> >>> +  0, 0, 0, 0, 0, 0,
> >>>   "<unknown>", 0, 0, 0, 0, false, 0
> >>> };
> >>> 
> >>> @@ -472,6 +473,7 @@ make_complex_modes (enum mode_class cl,
> >>> 
> >>>       c = new_mode (cclass, buf, file, line);
> >>>       c->component = m;
> >>> +      m->complex = c;
> >>>     }
> >>> }
> >>> 
> >>> @@ -1381,6 +1383,22 @@ emit_mode_wider (void)
> >>> }
> >>> 
> >>> static void
> >>> +emit_mode_complex (void)
> >>> +{
> >>> +  int c;
> >>> +  struct mode_data *m;
> >>> +
> >>> +  print_decl ("unsigned char", "mode_complex", "NUM_MACHINE_MODES");
> >>> +
> >>> +  for_all_modes (c, m)
> >>> +    tagged_printf ("%smode",
> >>> +		   m->complex ? m->complex->name : void_mode->name,
> >>> +		   m->name);
> >>> +
> >>> +  print_closer ();
> >>> +}
> >>> +
> >>> +static void
> >>> emit_mode_mask (void)
> >>> {
> >>>   int c;
> >>> @@ -1745,6 +1763,7 @@ emit_insn_modes_c (void)
> >>>   emit_mode_size ();
> >>>   emit_mode_nunits ();
> >>>   emit_mode_wider ();
> >>> +  emit_mode_complex ();
> >>>   emit_mode_mask ();
> >>>   emit_mode_inner ();
> >>>   emit_mode_unit_size ();
> >>> Index: gcc/tree.c
> >>> ===================================================================
> >>> --- gcc/tree.c	(revision 237045)
> >>> +++ gcc/tree.c	(working copy)
> >>> @@ -8675,6 +8675,7 @@ build_complex_type (tree component_type)
> >>>   t = make_node (COMPLEX_TYPE);
> >>> 
> >>>   TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
> >>> +  SET_TYPE_MODE (t, GET_MODE_COMPLEX_MODE (TYPE_MODE (component_type)));
> >>> 
> >>>   /* If we already have such a type, use the old one.  */
> >>>   hstate.add_object (TYPE_HASH (component_type));
> >>> Index: gcc/config/rs6000/rs6000.c
> >>> ===================================================================
> >>> --- gcc/config/rs6000/rs6000.c	(revision 237045)
> >>> +++ gcc/config/rs6000/rs6000.c	(working copy)
> >>> @@ -1882,7 +1882,7 @@ rs6000_hard_regno_nregs_internal (int re
> >>>      128-bit floating point that can go in vector registers, which has VSX
> >>>      memory addressing.  */
> >>>   if (FP_REGNO_P (regno))
> >>> -    reg_size = (VECTOR_MEM_VSX_P (mode)
> >>> +    reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode)
> >>> 		? UNITS_PER_VSX_WORD
> >>> 		: UNITS_PER_FP_WORD);
> >>> 
> >>> @@ -1914,6 +1914,9 @@ rs6000_hard_regno_mode_ok (int regno, ma
> >>> {
> >>>   int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1;
> >>> 
> >>> +  if (COMPLEX_MODE_P (mode))
> >>> +    mode = GET_MODE_INNER (mode);
> >>> +
> >>>   /* PTImode can only go in GPRs.  Quad word memory operations require even/odd
> >>>      register combinations, and use PTImode where we need to deal with quad
> >>>      word memory operations.  Don't allow quad words in the argument or frame
> >>> @@ -2716,8 +2719,17 @@ rs6000_setup_reg_addr_masks (void)
> >>> 
> >>>   for (m = 0; m < NUM_MACHINE_MODES; ++m)
> >>>     {
> >>> -      machine_mode m2 = (machine_mode)m;
> >>> -      unsigned short msize = GET_MODE_SIZE (m2);
> >>> +      machine_mode m2 = (machine_mode) m;
> >>> +      bool complex_p = false;
> >>> +      size_t msize;
> >>> +
> >>> +      if (COMPLEX_MODE_P (m2))
> >>> +	{
> >>> +	  complex_p = true;
> >>> +	  m2 = GET_MODE_INNER (m2);
> >>> +	}
> >>> +
> >>> +      msize = GET_MODE_SIZE (m2);
> >>> 
> >>>       /* SDmode is special in that we want to access it only via REG+REG
> >>> 	 addressing on power7 and above, since we want to use the LFIWZX and
> >>> @@ -2739,7 +2751,7 @@ rs6000_setup_reg_addr_masks (void)
> >>> 	      /* Indicate if the mode takes more than 1 physical register.  If
> >>> 		 it takes a single register, indicate it can do REG+REG
> >>> 		 addressing.  */
> >>> -	      if (nregs > 1 || m == BLKmode)
> >>> +	      if (nregs > 1 || m == BLKmode || complex_p)
> >>> 		addr_mask |= RELOAD_REG_MULTIPLE;
> >>> 	      else
> >>> 		addr_mask |= RELOAD_REG_INDEXED;
> >>> @@ -2755,7 +2767,7 @@ rs6000_setup_reg_addr_masks (void)
> >>> 		  && msize <= 8
> >>> 		  && !VECTOR_MODE_P (m2)
> >>> 		  && !FLOAT128_VECTOR_P (m2)
> >>> -		  && !COMPLEX_MODE_P (m2)
> >>> +		  && !complex_p
> >>> 		  && (m2 != DFmode || !TARGET_UPPER_REGS_DF)
> >>> 		  && (m2 != SFmode || !TARGET_UPPER_REGS_SF)
> >>> 		  && !(TARGET_E500_DOUBLE && msize == 8))
> >>> @@ -10266,6 +10278,35 @@ rs6000_must_pass_in_stack (machine_mode 
> >>>     return must_pass_in_stack_var_size_or_pad (mode, type);
> >>> }
> >>> 
> >>> +static inline bool
> >>> +is_complex_IBM_long_double (machine_mode mode)
> >>> +{
> >>> +  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
> >>> +}
> >>> +
> >>> +/* Whether ABI_V4 passes MODE args to a function in floating point
> >>> +   registers.  */
> >>> +
> >>> +static bool
> >>> +abi_v4_pass_in_fpr (machine_mode mode)
> >>> +{
> >>> +  if (!TARGET_FPRS || !TARGET_HARD_FLOAT)
> >>> +    return false;
> >>> +  if (TARGET_SINGLE_FLOAT && mode == SFmode)
> >>> +    return true;
> >>> +  if (TARGET_DOUBLE_FLOAT && mode == DFmode)
> >>> +    return true;
> >>> +  /* ABI_V4 passes complex IBM long double in 8 gprs.
> >>> +     Stupid, but we can't change the ABI now.  */
> >>> +  if (is_complex_IBM_long_double (mode))
> >>> +    return false;
> >>> +  if (FLOAT128_2REG_P (mode))
> >>> +    return true;
> >>> +  if (DECIMAL_FLOAT_MODE_P (mode))
> >>> +    return true;
> >>> +  return false;
> >>> +}
> >>> +
> >>> /* If defined, a C expression which determines whether, and in which
> >>>    direction, to pad out an argument with extra space.  The value
> >>>    should be of type `enum direction': either `upward' to pad above
> >>> @@ -10350,6 +10391,7 @@ rs6000_function_arg_boundary (machine_mo
> >>>       && (GET_MODE_SIZE (mode) == 8
> >>> 	  || (TARGET_HARD_FLOAT
> >>> 	      && TARGET_FPRS
> >>> +	      && !is_complex_IBM_long_double (mode)
> >>> 	      && FLOAT128_2REG_P (mode))))
> >>>     return 64;
> >>>   else if (FLOAT128_VECTOR_P (mode))
> >>> @@ -10729,11 +10771,7 @@ rs6000_function_arg_advance_1 (CUMULATIV
> >>>     }
> >>>   else if (DEFAULT_ABI == ABI_V4)
> >>>     {
> >>> -      if (TARGET_HARD_FLOAT && TARGET_FPRS
> >>> -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
> >>> -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
> >>> -	      || FLOAT128_2REG_P (mode)
> >>> -	      || DECIMAL_FLOAT_MODE_P (mode)))
> >>> +      if (abi_v4_pass_in_fpr (mode))
> >>> 	{
> >>> 	  /* _Decimal128 must use an even/odd register pair.  This assumes
> >>> 	     that the register number is odd when fregno is odd.  */
> >>> @@ -11390,11 +11428,7 @@ rs6000_function_arg (cumulative_args_t c
> >>> 
> >>>   else if (abi == ABI_V4)
> >>>     {
> >>> -      if (TARGET_HARD_FLOAT && TARGET_FPRS
> >>> -	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
> >>> -	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
> >>> -	      || FLOAT128_2REG_P (mode)
> >>> -	      || DECIMAL_FLOAT_MODE_P (mode)))
> >>> +      if (abi_v4_pass_in_fpr (mode))
> >>> 	{
> >>> 	  /* _Decimal128 must use an even/odd register pair.  This assumes
> >>> 	     that the register number is odd when fregno is odd.  */
> >>> @@ -12315,19 +12349,15 @@ rs6000_gimplify_va_arg (tree valist, tre
> >>>   rsize = (size + 3) / 4;
> >>>   align = 1;
> >>> 
> >>> -  if (TARGET_HARD_FLOAT && TARGET_FPRS
> >>> -      && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode)
> >>> -          || (TARGET_DOUBLE_FLOAT 
> >>> -              && (TYPE_MODE (type) == DFmode 
> >>> -		  || FLOAT128_2REG_P (TYPE_MODE (type))
> >>> -		  || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))))))
> >>> +  machine_mode mode = TYPE_MODE (type);
> >>> +  if (abi_v4_pass_in_fpr (mode))
> >>>     {
> >>>       /* FP args go in FP registers, if present.  */
> >>>       reg = fpr;
> >>>       n_reg = (size + 7) / 8;
> >>>       sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4;
> >>>       sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4);
> >>> -      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
> >>> +      if (mode != SFmode && mode != SDmode)
> >>> 	align = 8;
> >>>     }
> >>>   else
> >>> @@ -12347,7 +12377,7 @@ rs6000_gimplify_va_arg (tree valist, tre
> >>>   addr = create_tmp_var (ptr_type_node, "addr");
> >>> 
> >>>   /*  AltiVec vectors never go in registers when -mabi=altivec.  */
> >>> -  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
> >>> +  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
> >>>     align = 16;
> >>>   else
> >>>     {
> >>> @@ -12368,7 +12398,7 @@ rs6000_gimplify_va_arg (tree valist, tre
> >>> 	}
> >>>       /* _Decimal128 is passed in even/odd fpr pairs; the stored
> >>> 	 reg number is 0 for f1, so we want to make it odd.  */
> >>> -      else if (reg == fpr && TYPE_MODE (type) == TDmode)
> >>> +      else if (reg == fpr && mode == TDmode)
> >>> 	{
> >>> 	  t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg),
> >>> 		      build_int_cst (TREE_TYPE (reg), 1));
> >>> @@ -12395,7 +12425,7 @@ rs6000_gimplify_va_arg (tree valist, tre
> >>> 	 FP register for 32-bit binaries.  */
> >>>       if (TARGET_32BIT
> >>> 	  && TARGET_HARD_FLOAT && TARGET_FPRS
> >>> -	  && TYPE_MODE (type) == SDmode)
> >>> +	  && mode == SDmode)
> >>> 	t = fold_build_pointer_plus_hwi (t, size);
> >>> 
> >>>       gimplify_assign (addr, t, pre_p);
> >>> @@ -18464,25 +18494,33 @@ rs6000_secondary_reload_memory (rtx addr
> >>>     addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX]
> >>> 		 & ~RELOAD_REG_AND_M16);
> >>> 
> >>> -  else
> >>> +  /* If the register allocator hasn't made up its mind yet on the register
> >>> +     class to use, settle on defaults to use.  */
> >>> +  else if (rclass == NO_REGS)
> >>>     {
> >>> -      if (TARGET_DEBUG_ADDR)
> >>> -	fprintf (stderr,
> >>> -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> >>> -		 "class is not GPR, FPR, VMX\n",
> >>> -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
> >>> +      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_ANY]
> >>> +		   & ~RELOAD_REG_AND_M16);
> >>> 
> >>> -      return -1;
> >>> +      if ((addr_mask & RELOAD_REG_MULTIPLE) != 0)
> >>> +	addr_mask &= ~(RELOAD_REG_INDEXED
> >>> +		       | RELOAD_REG_PRE_INCDEC
> >>> +		       | RELOAD_REG_PRE_MODIFY);
> >>>     }
> >>> 
> >>> +  else
> >>> +    addr_mask = 0;
> >>> +
> >>>   /* If the register isn't valid in this register class, just return now.  */
> >>>   if ((addr_mask & RELOAD_REG_VALID) == 0)
> >>>     {
> >>>       if (TARGET_DEBUG_ADDR)
> >>> -	fprintf (stderr,
> >>> -		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> >>> -		 "not valid in class\n",
> >>> -		 GET_MODE_NAME (mode), reg_class_names[rclass]);
> >>> +	{
> >>> +	  fprintf (stderr,
> >>> +		   "rs6000_secondary_reload_memory: mode = %s, class = %s, "
> >>> +		   "not valid in class\n",
> >>> +		   GET_MODE_NAME (mode), reg_class_names[rclass]);
> >>> +	  debug_rtx (addr);
> >>> +	}
> >>> 
> >>>       return -1;
> >>>     }
> >>> @@ -19143,6 +19181,9 @@ rs6000_secondary_reload (bool in_p,
> >>> 	fprintf (stderr, ", reload func = %s, extra cost = %d",
> >>> 		 insn_data[sri->icode].name, sri->extra_cost);
> >>> 
> >>> +      else if (sri->extra_cost > 0)
> >>> +	fprintf (stderr, ", extra cost = %d", sri->extra_cost);
> >>> +
> >>>       fputs ("\n", stderr);
> >>>       debug_rtx (x);
> >>>     }
> >>> @@ -19553,6 +19594,16 @@ rs6000_preferred_reload_class (rtx x, en
> >>>   machine_mode mode = GET_MODE (x);
> >>>   bool is_constant = CONSTANT_P (x);
> >>> 
> >>> +  /* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred
> >>> +     reload class for it.  */
> >>> +  if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS)
> >>> +      && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0)
> >>> +    return NO_REGS;
> >>> +
> >>> +  if ((rclass == FLOAT_REGS || rclass == VSX_REGS)
> >>> +      && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
> >>> +    return NO_REGS;
> >>> +
> >>>   /* For VSX, see if we should prefer FLOAT_REGS or ALTIVEC_REGS.  Do not allow
> >>>      the reloading of address expressions using PLUS into floating point
> >>>      registers.  */
> >>> @@ -19603,6 +19654,25 @@ rs6000_preferred_reload_class (rtx x, en
> >>>       return NO_REGS;
> >>>     }
> >>> 
> >>> +  /* If we haven't picked a register class, and the type is a vector or
> >>> +     floating point type, prefer to use the VSX, FPR, or Altivec register
> >>> +     classes.  */
> >>> +  if (rclass == NO_REGS)
> >>> +    {
> >>> +      if (TARGET_VSX && VECTOR_MEM_VSX_OR_P8_VECTOR_P (mode))
> >>> +	return VSX_REGS;
> >>> +
> >>> +      if (TARGET_ALTIVEC && VECTOR_MEM_ALTIVEC_P (mode))
> >>> +	return ALTIVEC_REGS;
> >>> +
> >>> +      if (DECIMAL_FLOAT_MODE_P (mode))
> >>> +	return TARGET_DFP ? FLOAT_REGS : NO_REGS;
> >>> +
> >>> +      if (TARGET_FPRS && TARGET_HARD_FLOAT && FLOAT_MODE_P (mode)
> >>> +	  && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
> >>> +	return FLOAT_REGS;
> >>> +    }
> >>> +
> >>>   if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS)
> >>>     return GENERAL_REGS;
> >>> 
> >>> @@ -34549,8 +34619,14 @@ rs6000_complex_function_value (machine_m
> >>>   machine_mode inner = GET_MODE_INNER (mode);
> >>>   unsigned int inner_bytes = GET_MODE_UNIT_SIZE (mode);
> >>> 
> >>> -  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
> >>> +  if (TARGET_FLOAT128
> >>> +      && (mode == KCmode
> >>> +	  || (mode == TCmode && TARGET_IEEEQUAD)))
> >>> +    regno = ALTIVEC_ARG_RETURN;
> >>> +
> >>> +  else if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
> >>>     regno = FP_ARG_RETURN;
> >>> +
> >>>   else
> >>>     {
> >>>       regno = GP_ARG_RETURN;
> >>> Index: gcc/config/rs6000/rs6000.h
> >>> ===================================================================
> >>> --- gcc/config/rs6000/rs6000.h	(revision 237045)
> >>> +++ gcc/config/rs6000/rs6000.h	(working copy)
> >>> @@ -418,12 +418,12 @@ extern const char *host_detect_local_cpu
> >>>    Similarly IFmode is the IBM long double format even if the default is IEEE
> >>>    128-bit.  */
> >>> #define FLOAT128_IEEE_P(MODE)						\
> >>> -  (((MODE) == TFmode && TARGET_IEEEQUAD)				\
> >>> -   || ((MODE) == KFmode))
> >>> +  ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
> >>> +   || ((MODE) == KFmode) || ((MODE) == KCmode))
> >>> 
> >>> #define FLOAT128_IBM_P(MODE)						\
> >>> -  (((MODE) == TFmode && !TARGET_IEEEQUAD)				\
> >>> -   || ((MODE) == IFmode))
> >>> +  ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
> >>> +   || ((MODE) == IFmode) || ((MODE) == ICmode))
> >>> 
> >>> /* Helper macros to say whether a 128-bit floating point type can go in a
> >>>    single vector register, or whether it needs paired scalar values.  */
> >>> @@ -1789,7 +1789,9 @@ extern enum reg_class rs6000_constraints
> >>> #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
> >>> #define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN	\
> >>> 			   : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> >>> -#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
> >>> +#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2		\
> >>> +				? (ALTIVEC_ARG_RETURN			\
> >>> +				   + (TARGET_FLOAT128 ? 1 : 0))		\
> >>> 			        : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> >>> 
> >>> /* Flags for the call/call_value rtl operations set up by function_arg */
> >>> Index: gcc/doc/extend.texi
> >>> ===================================================================
> >>> --- gcc/doc/extend.texi	(revision 237045)
> >>> +++ gcc/doc/extend.texi	(working copy)
> >>> @@ -962,8 +962,13 @@ complex @code{__float128} type.  When th
> >>> would use the following syntax to declare @code{_Complex128} to be a
> >>> complex @code{__float128} type:
> >>> 
> >>> +On the PowerPC Linux VSX targets, you can declare complex types using
> >>> +the corresponding internal complex type, @code{KCmode} for
> >>> +@code{__float128} type and @code{ICmode} for @code{__ibm128} type:
> >>> +
> >>> @smallexample
> >>> -typedef _Complex float __attribute__((mode(KC))) _Complex128;
> >>> +typedef _Complex float __attribute__((mode(KC))) _Complex_float128;
> >>> +typedef _Complex float __attribute__((mode(IC))) _Complex_ibm128;
> >>> @end smallexample
> >>> 
> >>> Not all targets support additional floating-point types.
> >>> Index: gcc/fortran/trans-types.c
> >>> ===================================================================
> >>> --- gcc/fortran/trans-types.c	(revision 237045)
> >>> +++ gcc/fortran/trans-types.c	(working copy)
> >>> @@ -828,6 +828,7 @@ gfc_build_complex_type (tree scalar_type
> >>> 
> >>>   new_type = make_node (COMPLEX_TYPE);
> >>>   TREE_TYPE (new_type) = scalar_type;
> >>> +  SET_TYPE_MODE (new_type, GET_MODE_COMPLEX_MODE (TYPE_MODE (scalar_type)));
> >>>   layout_type (new_type);
> >>>   return new_type;
> >>> }
> >>> Index: gcc/testsuite/gcc.target/powerpc/float128-complex-1.c
> >>> ===================================================================
> >>> --- gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
> >>> +++ gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
> >>> @@ -0,0 +1,157 @@
> >>> +/* { dg-do compile { target { powerpc*-*-linux* } } } */
> >>> +/* { dg-require-effective-target powerpc_float128_sw_ok } */
> >>> +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
> >>> +/* { dg-options "-O2 -mcpu=power7 -mfloat128" } */
> >>> +
> >>> +#ifndef NO_FLOAT
> >>> +typedef _Complex float	float_complex;
> >>> +extern float_complex cfloat1 (void);
> >>> +extern float_complex cfloat2 (void);
> >>> +
> >>> +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
> >>> +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
> >>> +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
> >>> +
> >>> +#else
> >>> +#define FLOAT_ARG(NAME, OP)
> >>> +#define FLOAT_PTR(NAME, OP)
> >>> +#define FLOAT_CALL()
> >>> +#endif
> >>> +
> >>> +#ifndef NO_DOUBLE
> >>> +typedef _Complex double	double_complex;
> >>> +extern double_complex cdouble1 (void);
> >>> +extern double_complex cdouble2 (void);
> >>> +
> >>> +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
> >>> +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
> >>> +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
> >>> +
> >>> +#else
> >>> +#define DOUBLE_ARG(NAME, OP)
> >>> +#define DOUBLE_PTR(NAME, OP)
> >>> +#define DOUBLE_CALL()
> >>> +#endif
> >>> +
> >>> +#ifndef NO_FLOAT128
> >>> +#ifdef __VSX__
> >>> +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
> >>> +#else
> >>> +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
> >>> +#endif
> >>> +
> >>> +extern float128_complex cfloat128_1 (void);
> >>> +extern float128_complex cfloat128_2 (void);
> >>> +
> >>> +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
> >>> +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
> >>> +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
> >>> +
> >>> +#else
> >>> +#define FLOAT128_ARG(NAME, OP)
> >>> +#define FLOAT128_PTR(NAME, OP)
> >>> +#define FLOAT128_CALL()
> >>> +#endif
> >>> +
> >>> +#ifndef NO_LDOUBLE
> >>> +typedef _Complex long double ldouble_complex;
> >>> +extern ldouble_complex cldouble1 (void);
> >>> +extern ldouble_complex cldouble2 (void);
> >>> +
> >>> +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
> >>> +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
> >>> +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
> >>> +
> >>> +#else
> >>> +#define LDOUBLE_ARG(NAME, OP)
> >>> +#define LDOUBLE_PTR(NAME, OP)
> >>> +#define LDOUBLE_CALL()
> >>> +#endif
> >>> +
> >>> +
> >>> +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
> >>> +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
> >>> +{									\
> >>> +  return a OP b;							\
> >>> +}
> >>> +
> >>> +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
> >>> +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
> >>> +{									\
> >>> +  *p = *a OP *b;							\
> >>> +}
> >>> +
> >>> +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
> >>> +TYPE call_ ## SUFFIX (void)						\
> >>> +{									\
> >>> +  TYPE value1 = FUNC1 ();						\
> >>> +  TYPE value2 = FUNC2 ();						\
> >>> +  return value1 + value2;						\
> >>> +}
> >>> +
> >>> +#ifndef NO_ARG
> >>> +#ifndef NO_ADD
> >>> +FLOAT_ARG    (add, +)
> >>> +DOUBLE_ARG   (add, +)
> >>> +FLOAT128_ARG (add, +)
> >>> +LDOUBLE_ARG  (add, +)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_SUB
> >>> +FLOAT_ARG    (sub, -)
> >>> +DOUBLE_ARG   (sub, -)
> >>> +FLOAT128_ARG (sub, -)
> >>> +LDOUBLE_ARG  (sub, -)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_MUL
> >>> +FLOAT_ARG    (mul, *)
> >>> +DOUBLE_ARG   (mul, *)
> >>> +FLOAT128_ARG (mul, *)
> >>> +LDOUBLE_ARG  (mul, *)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_DIV
> >>> +FLOAT_ARG    (div, /)
> >>> +DOUBLE_ARG   (div, /)
> >>> +FLOAT128_ARG (div, /)
> >>> +LDOUBLE_ARG  (div, /)
> >>> +#endif
> >>> +#endif
> >>> +
> >>> +#ifndef NO_PTR
> >>> +#ifndef NO_ADD
> >>> +FLOAT_PTR    (add, +)
> >>> +DOUBLE_PTR   (add, +)
> >>> +FLOAT128_PTR (add, +)
> >>> +LDOUBLE_PTR  (add, +)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_SUB
> >>> +FLOAT_PTR    (sub, -)
> >>> +DOUBLE_PTR   (sub, -)
> >>> +FLOAT128_PTR (sub, -)
> >>> +LDOUBLE_PTR  (sub, -)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_MUL
> >>> +FLOAT_PTR    (mul, *)
> >>> +DOUBLE_PTR   (mul, *)
> >>> +FLOAT128_PTR (mul, *)
> >>> +LDOUBLE_PTR  (mul, *)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_DIV
> >>> +FLOAT_PTR    (div, /)
> >>> +DOUBLE_PTR   (div, /)
> >>> +FLOAT128_PTR (div, /)
> >>> +LDOUBLE_PTR  (div, /)
> >>> +#endif
> >>> +#endif
> >>> +
> >>> +#ifndef NO_CALL
> >>> +FLOAT_CALL    ()
> >>> +DOUBLE_CALL   ()
> >>> +FLOAT128_CALL ()
> >>> +LDOUBLE_CALL  ()
> >>> +#endif
> >>> Index: gcc/testsuite/gcc.target/powerpc/float128-complex-2.c
> >>> ===================================================================
> >>> --- gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
> >>> +++ gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
> >>> @@ -0,0 +1,160 @@
> >>> +/* { dg-do compile { target { powerpc*-*-linux* } } } */
> >>> +/* { dg-require-effective-target powerpc_float128_hw_ok } */
> >>> +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
> >>> +/* { dg-options "-O2 -mcpu=power9 -mfloat128 -mfloat128-hardware" } */
> >>> +
> >>> +#ifndef NO_FLOAT
> >>> +typedef _Complex float	float_complex;
> >>> +extern float_complex cfloat1 (void);
> >>> +extern float_complex cfloat2 (void);
> >>> +
> >>> +#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
> >>> +#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
> >>> +#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
> >>> +
> >>> +#else
> >>> +#define FLOAT_ARG(NAME, OP)
> >>> +#define FLOAT_PTR(NAME, OP)
> >>> +#define FLOAT_CALL()
> >>> +#endif
> >>> +
> >>> +#ifndef NO_DOUBLE
> >>> +typedef _Complex double	double_complex;
> >>> +extern double_complex cdouble1 (void);
> >>> +extern double_complex cdouble2 (void);
> >>> +
> >>> +#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
> >>> +#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
> >>> +#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
> >>> +
> >>> +#else
> >>> +#define DOUBLE_ARG(NAME, OP)
> >>> +#define DOUBLE_PTR(NAME, OP)
> >>> +#define DOUBLE_CALL()
> >>> +#endif
> >>> +
> >>> +#ifndef NO_FLOAT128
> >>> +#ifdef __VSX__
> >>> +typedef _Complex float __attribute__((mode(KC)))	float128_complex;
> >>> +#else
> >>> +typedef _Complex float __attribute__((mode(TC)))	float128_complex;
> >>> +#endif
> >>> +
> >>> +extern float128_complex cfloat128_1 (void);
> >>> +extern float128_complex cfloat128_2 (void);
> >>> +
> >>> +#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
> >>> +#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
> >>> +#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
> >>> +
> >>> +#else
> >>> +#define FLOAT128_ARG(NAME, OP)
> >>> +#define FLOAT128_PTR(NAME, OP)
> >>> +#define FLOAT128_CALL()
> >>> +#endif
> >>> +
> >>> +#ifndef NO_LDOUBLE
> >>> +typedef _Complex long double ldouble_complex;
> >>> +extern ldouble_complex cldouble1 (void);
> >>> +extern ldouble_complex cldouble2 (void);
> >>> +
> >>> +#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
> >>> +#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
> >>> +#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
> >>> +
> >>> +#else
> >>> +#define LDOUBLE_ARG(NAME, OP)
> >>> +#define LDOUBLE_PTR(NAME, OP)
> >>> +#define LDOUBLE_CALL()
> >>> +#endif
> >>> +
> >>> +
> >>> +#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
> >>> +TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
> >>> +{									\
> >>> +  return a OP b;							\
> >>> +}
> >>> +
> >>> +#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
> >>> +void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
> >>> +{									\
> >>> +  *p = *a OP *b;							\
> >>> +}
> >>> +
> >>> +#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
> >>> +TYPE call_ ## SUFFIX (void)						\
> >>> +{									\
> >>> +  TYPE value1 = FUNC1 ();						\
> >>> +  TYPE value2 = FUNC2 ();						\
> >>> +  return value1 + value2;						\
> >>> +}
> >>> +
> >>> +#ifndef NO_ARG
> >>> +#ifndef NO_ADD
> >>> +FLOAT_ARG    (add, +)
> >>> +DOUBLE_ARG   (add, +)
> >>> +FLOAT128_ARG (add, +)
> >>> +LDOUBLE_ARG  (add, +)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_SUB
> >>> +FLOAT_ARG    (sub, -)
> >>> +DOUBLE_ARG   (sub, -)
> >>> +FLOAT128_ARG (sub, -)
> >>> +LDOUBLE_ARG  (sub, -)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_MUL
> >>> +FLOAT_ARG    (mul, *)
> >>> +DOUBLE_ARG   (mul, *)
> >>> +FLOAT128_ARG (mul, *)
> >>> +LDOUBLE_ARG  (mul, *)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_DIV
> >>> +FLOAT_ARG    (div, /)
> >>> +DOUBLE_ARG   (div, /)
> >>> +FLOAT128_ARG (div, /)
> >>> +LDOUBLE_ARG  (div, /)
> >>> +#endif
> >>> +#endif
> >>> +
> >>> +#ifndef NO_PTR
> >>> +#ifndef NO_ADD
> >>> +FLOAT_PTR    (add, +)
> >>> +DOUBLE_PTR   (add, +)
> >>> +FLOAT128_PTR (add, +)
> >>> +LDOUBLE_PTR  (add, +)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_SUB
> >>> +FLOAT_PTR    (sub, -)
> >>> +DOUBLE_PTR   (sub, -)
> >>> +FLOAT128_PTR (sub, -)
> >>> +LDOUBLE_PTR  (sub, -)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_MUL
> >>> +FLOAT_PTR    (mul, *)
> >>> +DOUBLE_PTR   (mul, *)
> >>> +FLOAT128_PTR (mul, *)
> >>> +LDOUBLE_PTR  (mul, *)
> >>> +#endif
> >>> +
> >>> +#ifndef NO_DIV
> >>> +FLOAT_PTR    (div, /)
> >>> +DOUBLE_PTR   (div, /)
> >>> +FLOAT128_PTR (div, /)
> >>> +LDOUBLE_PTR  (div, /)
> >>> +#endif
> >>> +#endif
> >>> +
> >>> +#ifndef NO_CALL
> >>> +FLOAT_CALL    ()
> >>> +DOUBLE_CALL   ()
> >>> +FLOAT128_CALL ()
> >>> +LDOUBLE_CALL  ()
> >>> +#endif
> >>> +
> >>> +/* { dg-final { scan-assembler "xsaddqp"  } } */
> >>> +/* { dg-final { scan-assembler "xssubqp"  } } */
> >> 
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
> 
> 
>
Michael Meissner June 15, 2016, 12:34 p.m. UTC | #6
On Wed, Jun 15, 2016 at 11:01:05AM +0200, Richard Biener wrote:
> On Tue, 14 Jun 2016, Bill Schmidt wrote:
> 
> > Hi Richard,
> > 
> > As nobody else has replied, let me take a stab at this one.
> > 
> > > On Jun 10, 2016, at 2:06 AM, Richard Biener <rguenther@suse.de> wrote:
> > > 
> > > On Thu, 9 Jun 2016, Michael Meissner wrote:
> > > 
> > >> I'm including the global reviewers on the list.  I just want to be sure that
> > >> there is no problem installing these patches on the GCC 6.2 branch.  While it
> > >> is technically an enchancement, it is needed to be able to install the glibc
> > >> support that is needed to complete the work to add IEEE 128-bit floating point.
> > >> 
> > >> The issue being fixed is that when we are creating the complex type, we used to
> > >> do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
> > >> floating point types (__ibm128 and __float128, with long double currently
> > >> defaulting to __ibm128).
> > > 
> > > As this enhancement includes middle-end changes I am hesitant to approve
> > > it for the branch.  Why is it desirable to backport this change?
> > 
> > It comes down to community requirements and schedules.  We are in the process of
> > replacing the incompatible IBM long double type with true IEEE-754 128-bit floating
> > point (__float128).  This is a complex multi-stage process where we will have to
> > maintain the functionality of the existing IBM long double for backward compatibility
> > while the new type is implemented.  This impacts multiple packages, starting with
> > gcc and glibc.
> > 
> > The glibc maintainers have indicated that work there depends on a certain level of
> > functionality within GCC.  Specifically, both the old and new types must be supported,
> > including corresponding complex types.  Unfortunately the realization that the complex
> > types had to be supported came late, and this work didn't fully make it into GCC 6.1.
> > 
> > (Part of the problem that has made this whole effort difficult is that it is complicated to
> > maintain two floating-point types of the exact same size.)
> > 
> > In any case, the glibc maintainers require this work in GCC 6 so that work can begin
> > in glibc 2.24, with completion scheduled in glibc 2.25.  We are asking for an exception 
> > for this patch in order to allow those schedules to move forward.
> > 
> > So that's the history as I understand it... Perhaps others can jump in if I've munged
> > or omitted anything important.
> 
> Ok, I see the reason for the backport then.  Looking at the patch
> the only fragile thing is the layout_type change give it adds an assert
> and you did need to change frontends (but not all of them?).  I'm not
> sure about testsuite coverage for complex type for, say, Go or Ada
> or Java.

I added the assert after the review from Berndt.  It was to make sure there
were no other callers to layout_type to create complex nodes.
https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00077.html

> And I don't understand the layout_type change either - it looks to me
> it could just have used
> 
>   SET_TYPE_MODE (type, GET_MODE_COMPLEX_MODE (TYPE_MODE 
> (TREE_TYPE (type))));
> 
> and be done with it.  To me that looks a lot safer.

It has been some time since I looked at the code, I will have to investigate
it futher.

Note, I will be offline for the next 4 days.

> With now having two complex FP modes with the same size how does
> iteration over MODE_COMPLEX_FLOAT work with GET_MODE_WIDER_MODE?
> Is the outcome random?  Or do we visit both modes?  That is, could
> GET_MODE_COMPLEX_MODE be implemented with iterating over complex modes
> and in addition to size also match the component mode instead?

I struggled quite a bit with GET_WIDER_MODE.  There are three distinct usage
cases in the compiler.  One case uses GET_WIDER_MODE to initialize all of the
types.  Here you want to visit all of the types (though we could change the
code, since genmode does sort the types so that all of the types for a given
class are together).

Another case is the normal case, where given a type, go up to a wider type that
might implment the code you are looking for.

A third case is when generating floating point constants in the constant pool,
see if there is a smaller type that maintains the precision.

Eventually, I decided to punt having to have explicit paths for widening.  I
used fractional modes for IFmode (ibm long double format) and KFmode (IEEE
128-bit format).  IFmode widens to KFmode which widens to TFmode.  A backend
hook is used to not allow IBM long double to widen to IEEE long double and vice
versa.  At the moment, since there is no wider type than 128-bits, it isn't an
issue.

Note, I do feel the front ends should be modified to allow __complex __float128
directly rather than having to use an attribute to force the complex type (and
to use mode(TF) on x86 or mode(KF) on PowerPC).  It would clean up both x86 and
PowerPC.  However, those patches aren't written yet.

> [I realize this is just backports but at least the layout_type change
> looks dangerous to me]
> 
> Thanks,
> Richard.
>
Richard Biener June 15, 2016, 1:12 p.m. UTC | #7
On Wed, 15 Jun 2016, Michael Meissner wrote:

> On Wed, Jun 15, 2016 at 11:01:05AM +0200, Richard Biener wrote:
> > On Tue, 14 Jun 2016, Bill Schmidt wrote:
> > 
> > > Hi Richard,
> > > 
> > > As nobody else has replied, let me take a stab at this one.
> > > 
> > > > On Jun 10, 2016, at 2:06 AM, Richard Biener <rguenther@suse.de> wrote:
> > > > 
> > > > On Thu, 9 Jun 2016, Michael Meissner wrote:
> > > > 
> > > >> I'm including the global reviewers on the list.  I just want to be sure that
> > > >> there is no problem installing these patches on the GCC 6.2 branch.  While it
> > > >> is technically an enchancement, it is needed to be able to install the glibc
> > > >> support that is needed to complete the work to add IEEE 128-bit floating point.
> > > >> 
> > > >> The issue being fixed is that when we are creating the complex type, we used to
> > > >> do a lookup for the size, and that fails on the PowerPC which has 2 128-bit
> > > >> floating point types (__ibm128 and __float128, with long double currently
> > > >> defaulting to __ibm128).
> > > > 
> > > > As this enhancement includes middle-end changes I am hesitant to approve
> > > > it for the branch.  Why is it desirable to backport this change?
> > > 
> > > It comes down to community requirements and schedules.  We are in the process of
> > > replacing the incompatible IBM long double type with true IEEE-754 128-bit floating
> > > point (__float128).  This is a complex multi-stage process where we will have to
> > > maintain the functionality of the existing IBM long double for backward compatibility
> > > while the new type is implemented.  This impacts multiple packages, starting with
> > > gcc and glibc.
> > > 
> > > The glibc maintainers have indicated that work there depends on a certain level of
> > > functionality within GCC.  Specifically, both the old and new types must be supported,
> > > including corresponding complex types.  Unfortunately the realization that the complex
> > > types had to be supported came late, and this work didn't fully make it into GCC 6.1.
> > > 
> > > (Part of the problem that has made this whole effort difficult is that it is complicated to
> > > maintain two floating-point types of the exact same size.)
> > > 
> > > In any case, the glibc maintainers require this work in GCC 6 so that work can begin
> > > in glibc 2.24, with completion scheduled in glibc 2.25.  We are asking for an exception 
> > > for this patch in order to allow those schedules to move forward.
> > > 
> > > So that's the history as I understand it... Perhaps others can jump in if I've munged
> > > or omitted anything important.
> > 
> > Ok, I see the reason for the backport then.  Looking at the patch
> > the only fragile thing is the layout_type change give it adds an assert
> > and you did need to change frontends (but not all of them?).  I'm not
> > sure about testsuite coverage for complex type for, say, Go or Ada
> > or Java.
> 
> I added the assert after the review from Berndt.  It was to make sure there
> were no other callers to layout_type to create complex nodes.
> https://gcc.gnu.org/ml/gcc-patches/2016-05/msg00077.html
> 
> > And I don't understand the layout_type change either - it looks to me
> > it could just have used
> > 
> >   SET_TYPE_MODE (type, GET_MODE_COMPLEX_MODE (TYPE_MODE 
> > (TREE_TYPE (type))));
> > 
> > and be done with it.  To me that looks a lot safer.
> 
> It has been some time since I looked at the code, I will have to investigate
> it futher.
> 
> Note, I will be offline for the next 4 days.
> 
> > With now having two complex FP modes with the same size how does
> > iteration over MODE_COMPLEX_FLOAT work with GET_MODE_WIDER_MODE?
> > Is the outcome random?  Or do we visit both modes?  That is, could
> > GET_MODE_COMPLEX_MODE be implemented with iterating over complex modes
> > and in addition to size also match the component mode instead?
> 
> I struggled quite a bit with GET_WIDER_MODE.  There are three distinct usage
> cases in the compiler.  One case uses GET_WIDER_MODE to initialize all of the
> types.  Here you want to visit all of the types (though we could change the
> code, since genmode does sort the types so that all of the types for a given
> class are together).
> 
> Another case is the normal case, where given a type, go up to a wider type that
> might implment the code you are looking for.
> 
> A third case is when generating floating point constants in the constant pool,
> see if there is a smaller type that maintains the precision.
> 
> Eventually, I decided to punt having to have explicit paths for widening.  I
> used fractional modes for IFmode (ibm long double format) and KFmode (IEEE
> 128-bit format).  IFmode widens to KFmode which widens to TFmode.  A backend
> hook is used to not allow IBM long double to widen to IEEE long double and vice
> versa.  At the moment, since there is no wider type than 128-bits, it isn't an
> issue.

Ok, using fractional float modes is a lie though as both IFmode and KFmode
have no insignificant bits.  I checked that if you have two same-size
FLOAT_MODEs they still get iterated over with GET_MODE_WIDER_MODE,
in order of appearance.  So your reason to use fractional modes was
to make the order explicit and to avoid bogus handling in for example
the constant pool handling which would mistake say IFmode as being
smaller than KFmode just because one is GET_MODE_WIDER_MODE of the other
(and both have the same precision)?  Interestingly for 
GET_MODE_2XWIDER_MODE it "skips" the duplicate-sized and chooses
the "first" one.

I guess having to have both float formats usable at the same time
is not really supported by our mode machinery.

> Note, I do feel the front ends should be modified to allow __complex 
> __float128 directly rather than having to use an attribute to force the 
> complex type (and to use mode(TF) on x86 or mode(KF) on PowerPC).  It 
> would clean up both x86 and PowerPC.  However, those patches aren't 
> written yet.

Sure, but that's independent of the modes issue.

Anyway, I'm fine with the backport if you sort out the issue with
the assert in layout_type.

Thanks,
Richard.
Michael Meissner June 15, 2016, 11:09 p.m. UTC | #8
On Wed, Jun 15, 2016 at 03:12:55PM +0200, Richard Biener wrote:
> On Wed, 15 Jun 2016, Michael Meissner wrote:
> > Eventually, I decided to punt having to have explicit paths for widening.  I
> > used fractional modes for IFmode (ibm long double format) and KFmode (IEEE
> > 128-bit format).  IFmode widens to KFmode which widens to TFmode.  A backend
> > hook is used to not allow IBM long double to widen to IEEE long double and vice
> > versa.  At the moment, since there is no wider type than 128-bits, it isn't an
> > issue.
> 
> Ok, using fractional float modes is a lie though as both IFmode and KFmode
> have no insignificant bits.  I checked that if you have two same-size
> FLOAT_MODEs they still get iterated over with GET_MODE_WIDER_MODE,
> in order of appearance.  So your reason to use fractional modes was
> to make the order explicit and to avoid bogus handling in for example
> the constant pool handling which would mistake say IFmode as being
> smaller than KFmode just because one is GET_MODE_WIDER_MODE of the other
> (and both have the same precision)?  Interestingly for 
> GET_MODE_2XWIDER_MODE it "skips" the duplicate-sized and chooses
> the "first" one.
> 
> I guess having to have both float formats usable at the same time
> is not really supported by our mode machinery.
> 
> > Note, I do feel the front ends should be modified to allow __complex 
> > __float128 directly rather than having to use an attribute to force the 
> > complex type (and to use mode(TF) on x86 or mode(KF) on PowerPC).  It 
> > would clean up both x86 and PowerPC.  However, those patches aren't 
> > written yet.
> 
> Sure, but that's independent of the modes issue.
> 
> Anyway, I'm fine with the backport if you sort out the issue with
> the assert in layout_type.

I did change the code as you suggested, and it did bootstrap and have no
regressions.  When I get back on Monday, I will look at implementing the fix in
trunk, and then putting the revised patch into GCC 6.2.

Thanks.
Joseph Myers June 16, 2016, 10:06 p.m. UTC | #9
On Wed, 15 Jun 2016, Michael Meissner wrote:

> Note, I do feel the front ends should be modified to allow __complex __float128
> directly rather than having to use an attribute to force the complex type (and
> to use mode(TF) on x86 or mode(KF) on PowerPC).  It would clean up both x86 and
> PowerPC.  However, those patches aren't written yet.

I'm now working on support for TS 18661-3 _FloatN / _FloatNx type names 
(keywords), constant suffixes and <float.h> addiitions.  That will 
address, for C, the need to use modes for complex float128 (bug 32187) by 
allowing the standard _Complex _Float128 to be used.  The issue would 
still apply for C++ (I'm not including any C++ support for these type 
names / constant suffixes in my patch), and for complex ibm128.
Michael Meissner June 21, 2016, 6:51 p.m. UTC | #10
On Thu, Jun 16, 2016 at 10:06:48PM +0000, Joseph Myers wrote:
> On Wed, 15 Jun 2016, Michael Meissner wrote:
> 
> > Note, I do feel the front ends should be modified to allow __complex __float128
> > directly rather than having to use an attribute to force the complex type (and
> > to use mode(TF) on x86 or mode(KF) on PowerPC).  It would clean up both x86 and
> > PowerPC.  However, those patches aren't written yet.
> 
> I'm now working on support for TS 18661-3 _FloatN / _FloatNx type names 
> (keywords), constant suffixes and <float.h> addiitions.  That will 
> address, for C, the need to use modes for complex float128 (bug 32187) by 
> allowing the standard _Complex _Float128 to be used.  The issue would 
> still apply for C++ (I'm not including any C++ support for these type 
> names / constant suffixes in my patch), and for complex ibm128.

Great!

Of course we will need to have some solution for C++.

And we will have to live with the current stuff in GCC 6.x.
Joseph Myers June 21, 2016, 8:55 p.m. UTC | #11
On Tue, 21 Jun 2016, Michael Meissner wrote:

> > I'm now working on support for TS 18661-3 _FloatN / _FloatNx type names 
> > (keywords), constant suffixes and <float.h> addiitions.  That will 
> > address, for C, the need to use modes for complex float128 (bug 32187) by 
> > allowing the standard _Complex _Float128 to be used.  The issue would 
> > still apply for C++ (I'm not including any C++ support for these type 
> > names / constant suffixes in my patch), and for complex ibm128.
> 
> Great!
> 
> Of course we will need to have some solution for C++.

Since the C++-standard way of using complex numbers is std::complex, it's 
not clear to me that the C-compatible _Complex _Float128 needs to be 
particularly conveniently avilable in C++.

Rather, where the C++ standard says "The effect of instantiating the 
template complex for any type other than float, double, or long double is 
unspecified. The specializations complex<float>, complex<double>, and 
complex<long double> are literal types (3.9).", presumably one should aim 
to make complex<__float128> work properly if it doesn't already.  And that 
might internally use _Complex _Float128 in some way to call libm functions 
when available, much as libstdc++ currently has _GLIBCXX_USE_C99_COMPLEX.  
And then I suppose you'd want to make appropriate literal suffixes work as 
well.  That's part of rather more generally making libstdc++ work with a 
new floating-point type; 
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43622> has an overview of 
the sorts of things involved and links to other discussions.

Standard C++ support for decimal floating-point types, TR 24733, took the 
form of classes such as std::decimal::decimal64 rather than the C-style 
_Decimal64.  I don't know what form C++ bindings to IEEE interchange and 
extended types might take, but something similar would seem natural.
diff mbox

Patch

Index: gcc/machmode.h
===================================================================
--- gcc/machmode.h	(revision 237045)
+++ gcc/machmode.h	(working copy)
@@ -269,6 +269,10 @@  extern const unsigned char mode_wider[NU
 extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
 #define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
 
+/* Get the complex mode from the component mode.  */
+extern const unsigned char mode_complex[NUM_MACHINE_MODES];
+#define GET_MODE_COMPLEX_MODE(MODE) ((machine_mode) mode_complex[MODE])
+
 /* Return the mode for data of a given size SIZE and mode class CLASS.
    If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
    The value is BLKmode if no other mode is found.  */
Index: gcc/stor-layout.c
===================================================================
--- gcc/stor-layout.c	(revision 237045)
+++ gcc/stor-layout.c	(working copy)
@@ -2146,11 +2146,13 @@  layout_type (tree type)
 
     case COMPLEX_TYPE:
       TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
-      SET_TYPE_MODE (type,
-		     mode_for_size (2 * TYPE_PRECISION (TREE_TYPE (type)),
-				    (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
-				     ? MODE_COMPLEX_FLOAT : MODE_COMPLEX_INT),
-				     0));
+
+      /* build_complex_type and fortran's gfc_build_complex_type have set the
+	 expected mode to allow having multiple complex types for multiple
+	 floating point types that have the same size such as the PowerPC with
+	 __ibm128 and __float128.  */
+      gcc_assert (TYPE_MODE (type) != VOIDmode);
+
       TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
       TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
       break;
Index: gcc/genmodes.c
===================================================================
--- gcc/genmodes.c	(revision 237045)
+++ gcc/genmodes.c	(working copy)
@@ -66,6 +66,7 @@  struct mode_data
 				   this mode as a component.  */
   struct mode_data *next_cont;  /* Next mode in that list.  */
 
+  struct mode_data *complex;	/* complex type with mode as component.  */
   const char *file;		/* file and line of definition, */
   unsigned int line;		/* for error reporting */
   unsigned int counter;		/* Rank ordering of modes */
@@ -83,7 +84,7 @@  static struct mode_data *void_mode;
 static const struct mode_data blank_mode = {
   0, "<unknown>", MAX_MODE_CLASS,
   -1U, -1U, -1U, -1U,
-  0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0,
   "<unknown>", 0, 0, 0, 0, false, 0
 };
 
@@ -472,6 +473,7 @@  make_complex_modes (enum mode_class cl,
 
       c = new_mode (cclass, buf, file, line);
       c->component = m;
+      m->complex = c;
     }
 }
 
@@ -1381,6 +1383,22 @@  emit_mode_wider (void)
 }
 
 static void
+emit_mode_complex (void)
+{
+  int c;
+  struct mode_data *m;
+
+  print_decl ("unsigned char", "mode_complex", "NUM_MACHINE_MODES");
+
+  for_all_modes (c, m)
+    tagged_printf ("%smode",
+		   m->complex ? m->complex->name : void_mode->name,
+		   m->name);
+
+  print_closer ();
+}
+
+static void
 emit_mode_mask (void)
 {
   int c;
@@ -1745,6 +1763,7 @@  emit_insn_modes_c (void)
   emit_mode_size ();
   emit_mode_nunits ();
   emit_mode_wider ();
+  emit_mode_complex ();
   emit_mode_mask ();
   emit_mode_inner ();
   emit_mode_unit_size ();
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 237045)
+++ gcc/tree.c	(working copy)
@@ -8675,6 +8675,7 @@  build_complex_type (tree component_type)
   t = make_node (COMPLEX_TYPE);
 
   TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
+  SET_TYPE_MODE (t, GET_MODE_COMPLEX_MODE (TYPE_MODE (component_type)));
 
   /* If we already have such a type, use the old one.  */
   hstate.add_object (TYPE_HASH (component_type));
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 237045)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1882,7 +1882,7 @@  rs6000_hard_regno_nregs_internal (int re
      128-bit floating point that can go in vector registers, which has VSX
      memory addressing.  */
   if (FP_REGNO_P (regno))
-    reg_size = (VECTOR_MEM_VSX_P (mode)
+    reg_size = (VECTOR_MEM_VSX_P (mode) || FLOAT128_VECTOR_P (mode)
 		? UNITS_PER_VSX_WORD
 		: UNITS_PER_FP_WORD);
 
@@ -1914,6 +1914,9 @@  rs6000_hard_regno_mode_ok (int regno, ma
 {
   int last_regno = regno + rs6000_hard_regno_nregs[mode][regno] - 1;
 
+  if (COMPLEX_MODE_P (mode))
+    mode = GET_MODE_INNER (mode);
+
   /* PTImode can only go in GPRs.  Quad word memory operations require even/odd
      register combinations, and use PTImode where we need to deal with quad
      word memory operations.  Don't allow quad words in the argument or frame
@@ -2716,8 +2719,17 @@  rs6000_setup_reg_addr_masks (void)
 
   for (m = 0; m < NUM_MACHINE_MODES; ++m)
     {
-      machine_mode m2 = (machine_mode)m;
-      unsigned short msize = GET_MODE_SIZE (m2);
+      machine_mode m2 = (machine_mode) m;
+      bool complex_p = false;
+      size_t msize;
+
+      if (COMPLEX_MODE_P (m2))
+	{
+	  complex_p = true;
+	  m2 = GET_MODE_INNER (m2);
+	}
+
+      msize = GET_MODE_SIZE (m2);
 
       /* SDmode is special in that we want to access it only via REG+REG
 	 addressing on power7 and above, since we want to use the LFIWZX and
@@ -2739,7 +2751,7 @@  rs6000_setup_reg_addr_masks (void)
 	      /* Indicate if the mode takes more than 1 physical register.  If
 		 it takes a single register, indicate it can do REG+REG
 		 addressing.  */
-	      if (nregs > 1 || m == BLKmode)
+	      if (nregs > 1 || m == BLKmode || complex_p)
 		addr_mask |= RELOAD_REG_MULTIPLE;
 	      else
 		addr_mask |= RELOAD_REG_INDEXED;
@@ -2755,7 +2767,7 @@  rs6000_setup_reg_addr_masks (void)
 		  && msize <= 8
 		  && !VECTOR_MODE_P (m2)
 		  && !FLOAT128_VECTOR_P (m2)
-		  && !COMPLEX_MODE_P (m2)
+		  && !complex_p
 		  && (m2 != DFmode || !TARGET_UPPER_REGS_DF)
 		  && (m2 != SFmode || !TARGET_UPPER_REGS_SF)
 		  && !(TARGET_E500_DOUBLE && msize == 8))
@@ -10266,6 +10278,35 @@  rs6000_must_pass_in_stack (machine_mode 
     return must_pass_in_stack_var_size_or_pad (mode, type);
 }
 
+static inline bool
+is_complex_IBM_long_double (machine_mode mode)
+{
+  return mode == ICmode || (!TARGET_IEEEQUAD && mode == TCmode);
+}
+
+/* Whether ABI_V4 passes MODE args to a function in floating point
+   registers.  */
+
+static bool
+abi_v4_pass_in_fpr (machine_mode mode)
+{
+  if (!TARGET_FPRS || !TARGET_HARD_FLOAT)
+    return false;
+  if (TARGET_SINGLE_FLOAT && mode == SFmode)
+    return true;
+  if (TARGET_DOUBLE_FLOAT && mode == DFmode)
+    return true;
+  /* ABI_V4 passes complex IBM long double in 8 gprs.
+     Stupid, but we can't change the ABI now.  */
+  if (is_complex_IBM_long_double (mode))
+    return false;
+  if (FLOAT128_2REG_P (mode))
+    return true;
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    return true;
+  return false;
+}
+
 /* If defined, a C expression which determines whether, and in which
    direction, to pad out an argument with extra space.  The value
    should be of type `enum direction': either `upward' to pad above
@@ -10350,6 +10391,7 @@  rs6000_function_arg_boundary (machine_mo
       && (GET_MODE_SIZE (mode) == 8
 	  || (TARGET_HARD_FLOAT
 	      && TARGET_FPRS
+	      && !is_complex_IBM_long_double (mode)
 	      && FLOAT128_2REG_P (mode))))
     return 64;
   else if (FLOAT128_VECTOR_P (mode))
@@ -10729,11 +10771,7 @@  rs6000_function_arg_advance_1 (CUMULATIV
     }
   else if (DEFAULT_ABI == ABI_V4)
     {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS
-	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
-	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
-	      || FLOAT128_2REG_P (mode)
-	      || DECIMAL_FLOAT_MODE_P (mode)))
+      if (abi_v4_pass_in_fpr (mode))
 	{
 	  /* _Decimal128 must use an even/odd register pair.  This assumes
 	     that the register number is odd when fregno is odd.  */
@@ -11390,11 +11428,7 @@  rs6000_function_arg (cumulative_args_t c
 
   else if (abi == ABI_V4)
     {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS
-	  && ((TARGET_SINGLE_FLOAT && mode == SFmode)
-	      || (TARGET_DOUBLE_FLOAT && mode == DFmode)
-	      || FLOAT128_2REG_P (mode)
-	      || DECIMAL_FLOAT_MODE_P (mode)))
+      if (abi_v4_pass_in_fpr (mode))
 	{
 	  /* _Decimal128 must use an even/odd register pair.  This assumes
 	     that the register number is odd when fregno is odd.  */
@@ -12315,19 +12349,15 @@  rs6000_gimplify_va_arg (tree valist, tre
   rsize = (size + 3) / 4;
   align = 1;
 
-  if (TARGET_HARD_FLOAT && TARGET_FPRS
-      && ((TARGET_SINGLE_FLOAT && TYPE_MODE (type) == SFmode)
-          || (TARGET_DOUBLE_FLOAT 
-              && (TYPE_MODE (type) == DFmode 
-		  || FLOAT128_2REG_P (TYPE_MODE (type))
-		  || DECIMAL_FLOAT_MODE_P (TYPE_MODE (type))))))
+  machine_mode mode = TYPE_MODE (type);
+  if (abi_v4_pass_in_fpr (mode))
     {
       /* FP args go in FP registers, if present.  */
       reg = fpr;
       n_reg = (size + 7) / 8;
       sav_ofs = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4) * 4;
       sav_scale = ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) ? 8 : 4);
-      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
+      if (mode != SFmode && mode != SDmode)
 	align = 8;
     }
   else
@@ -12347,7 +12377,7 @@  rs6000_gimplify_va_arg (tree valist, tre
   addr = create_tmp_var (ptr_type_node, "addr");
 
   /*  AltiVec vectors never go in registers when -mabi=altivec.  */
-  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
+  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     align = 16;
   else
     {
@@ -12368,7 +12398,7 @@  rs6000_gimplify_va_arg (tree valist, tre
 	}
       /* _Decimal128 is passed in even/odd fpr pairs; the stored
 	 reg number is 0 for f1, so we want to make it odd.  */
-      else if (reg == fpr && TYPE_MODE (type) == TDmode)
+      else if (reg == fpr && mode == TDmode)
 	{
 	  t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), unshare_expr (reg),
 		      build_int_cst (TREE_TYPE (reg), 1));
@@ -12395,7 +12425,7 @@  rs6000_gimplify_va_arg (tree valist, tre
 	 FP register for 32-bit binaries.  */
       if (TARGET_32BIT
 	  && TARGET_HARD_FLOAT && TARGET_FPRS
-	  && TYPE_MODE (type) == SDmode)
+	  && mode == SDmode)
 	t = fold_build_pointer_plus_hwi (t, size);
 
       gimplify_assign (addr, t, pre_p);
@@ -18464,25 +18494,33 @@  rs6000_secondary_reload_memory (rtx addr
     addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_VMX]
 		 & ~RELOAD_REG_AND_M16);
 
-  else
+  /* If the register allocator hasn't made up its mind yet on the register
+     class to use, settle on defaults to use.  */
+  else if (rclass == NO_REGS)
     {
-      if (TARGET_DEBUG_ADDR)
-	fprintf (stderr,
-		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
-		 "class is not GPR, FPR, VMX\n",
-		 GET_MODE_NAME (mode), reg_class_names[rclass]);
+      addr_mask = (reg_addr[mode].addr_mask[RELOAD_REG_ANY]
+		   & ~RELOAD_REG_AND_M16);
 
-      return -1;
+      if ((addr_mask & RELOAD_REG_MULTIPLE) != 0)
+	addr_mask &= ~(RELOAD_REG_INDEXED
+		       | RELOAD_REG_PRE_INCDEC
+		       | RELOAD_REG_PRE_MODIFY);
     }
 
+  else
+    addr_mask = 0;
+
   /* If the register isn't valid in this register class, just return now.  */
   if ((addr_mask & RELOAD_REG_VALID) == 0)
     {
       if (TARGET_DEBUG_ADDR)
-	fprintf (stderr,
-		 "rs6000_secondary_reload_memory: mode = %s, class = %s, "
-		 "not valid in class\n",
-		 GET_MODE_NAME (mode), reg_class_names[rclass]);
+	{
+	  fprintf (stderr,
+		   "rs6000_secondary_reload_memory: mode = %s, class = %s, "
+		   "not valid in class\n",
+		   GET_MODE_NAME (mode), reg_class_names[rclass]);
+	  debug_rtx (addr);
+	}
 
       return -1;
     }
@@ -19143,6 +19181,9 @@  rs6000_secondary_reload (bool in_p,
 	fprintf (stderr, ", reload func = %s, extra cost = %d",
 		 insn_data[sri->icode].name, sri->extra_cost);
 
+      else if (sri->extra_cost > 0)
+	fprintf (stderr, ", extra cost = %d", sri->extra_cost);
+
       fputs ("\n", stderr);
       debug_rtx (x);
     }
@@ -19553,6 +19594,16 @@  rs6000_preferred_reload_class (rtx x, en
   machine_mode mode = GET_MODE (x);
   bool is_constant = CONSTANT_P (x);
 
+  /* If a mode can't go in FPR/ALTIVEC/VSX registers, don't return a preferred
+     reload class for it.  */
+  if ((rclass == ALTIVEC_REGS || rclass == VSX_REGS)
+      && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0)
+    return NO_REGS;
+
+  if ((rclass == FLOAT_REGS || rclass == VSX_REGS)
+      && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
+    return NO_REGS;
+
   /* For VSX, see if we should prefer FLOAT_REGS or ALTIVEC_REGS.  Do not allow
      the reloading of address expressions using PLUS into floating point
      registers.  */
@@ -19603,6 +19654,25 @@  rs6000_preferred_reload_class (rtx x, en
       return NO_REGS;
     }
 
+  /* If we haven't picked a register class, and the type is a vector or
+     floating point type, prefer to use the VSX, FPR, or Altivec register
+     classes.  */
+  if (rclass == NO_REGS)
+    {
+      if (TARGET_VSX && VECTOR_MEM_VSX_OR_P8_VECTOR_P (mode))
+	return VSX_REGS;
+
+      if (TARGET_ALTIVEC && VECTOR_MEM_ALTIVEC_P (mode))
+	return ALTIVEC_REGS;
+
+      if (DECIMAL_FLOAT_MODE_P (mode))
+	return TARGET_DFP ? FLOAT_REGS : NO_REGS;
+
+      if (TARGET_FPRS && TARGET_HARD_FLOAT && FLOAT_MODE_P (mode)
+	  && (reg_addr[mode].addr_mask[RELOAD_REG_FPR] & RELOAD_REG_VALID) == 0)
+	return FLOAT_REGS;
+    }
+
   if (GET_MODE_CLASS (mode) == MODE_INT && rclass == NON_SPECIAL_REGS)
     return GENERAL_REGS;
 
@@ -34549,8 +34619,14 @@  rs6000_complex_function_value (machine_m
   machine_mode inner = GET_MODE_INNER (mode);
   unsigned int inner_bytes = GET_MODE_UNIT_SIZE (mode);
 
-  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
+  if (TARGET_FLOAT128
+      && (mode == KCmode
+	  || (mode == TCmode && TARGET_IEEEQUAD)))
+    regno = ALTIVEC_ARG_RETURN;
+
+  else if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
+
   else
     {
       regno = GP_ARG_RETURN;
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 237045)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -418,12 +418,12 @@  extern const char *host_detect_local_cpu
    Similarly IFmode is the IBM long double format even if the default is IEEE
    128-bit.  */
 #define FLOAT128_IEEE_P(MODE)						\
-  (((MODE) == TFmode && TARGET_IEEEQUAD)				\
-   || ((MODE) == KFmode))
+  ((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
+   || ((MODE) == KFmode) || ((MODE) == KCmode))
 
 #define FLOAT128_IBM_P(MODE)						\
-  (((MODE) == TFmode && !TARGET_IEEEQUAD)				\
-   || ((MODE) == IFmode))
+  ((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode))		\
+   || ((MODE) == IFmode) || ((MODE) == ICmode))
 
 /* Helper macros to say whether a 128-bit floating point type can go in a
    single vector register, or whether it needs paired scalar values.  */
@@ -1789,7 +1789,9 @@  extern enum reg_class rs6000_constraints
 #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
 #define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN	\
 			   : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
-#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
+#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2		\
+				? (ALTIVEC_ARG_RETURN			\
+				   + (TARGET_FLOAT128 ? 1 : 0))		\
 			        : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
 
 /* Flags for the call/call_value rtl operations set up by function_arg */
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 237045)
+++ gcc/doc/extend.texi	(working copy)
@@ -962,8 +962,13 @@  complex @code{__float128} type.  When th
 would use the following syntax to declare @code{_Complex128} to be a
 complex @code{__float128} type:
 
+On the PowerPC Linux VSX targets, you can declare complex types using
+the corresponding internal complex type, @code{KCmode} for
+@code{__float128} type and @code{ICmode} for @code{__ibm128} type:
+
 @smallexample
-typedef _Complex float __attribute__((mode(KC))) _Complex128;
+typedef _Complex float __attribute__((mode(KC))) _Complex_float128;
+typedef _Complex float __attribute__((mode(IC))) _Complex_ibm128;
 @end smallexample
 
 Not all targets support additional floating-point types.
Index: gcc/fortran/trans-types.c
===================================================================
--- gcc/fortran/trans-types.c	(revision 237045)
+++ gcc/fortran/trans-types.c	(working copy)
@@ -828,6 +828,7 @@  gfc_build_complex_type (tree scalar_type
 
   new_type = make_node (COMPLEX_TYPE);
   TREE_TYPE (new_type) = scalar_type;
+  SET_TYPE_MODE (new_type, GET_MODE_COMPLEX_MODE (TYPE_MODE (scalar_type)));
   layout_type (new_type);
   return new_type;
 }
Index: gcc/testsuite/gcc.target/powerpc/float128-complex-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/float128-complex-1.c	(revision 0)
@@ -0,0 +1,157 @@ 
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target powerpc_float128_sw_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
+/* { dg-options "-O2 -mcpu=power7 -mfloat128" } */
+
+#ifndef NO_FLOAT
+typedef _Complex float	float_complex;
+extern float_complex cfloat1 (void);
+extern float_complex cfloat2 (void);
+
+#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
+#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
+#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
+
+#else
+#define FLOAT_ARG(NAME, OP)
+#define FLOAT_PTR(NAME, OP)
+#define FLOAT_CALL()
+#endif
+
+#ifndef NO_DOUBLE
+typedef _Complex double	double_complex;
+extern double_complex cdouble1 (void);
+extern double_complex cdouble2 (void);
+
+#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
+#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
+#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
+
+#else
+#define DOUBLE_ARG(NAME, OP)
+#define DOUBLE_PTR(NAME, OP)
+#define DOUBLE_CALL()
+#endif
+
+#ifndef NO_FLOAT128
+#ifdef __VSX__
+typedef _Complex float __attribute__((mode(KC)))	float128_complex;
+#else
+typedef _Complex float __attribute__((mode(TC)))	float128_complex;
+#endif
+
+extern float128_complex cfloat128_1 (void);
+extern float128_complex cfloat128_2 (void);
+
+#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
+#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
+#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
+
+#else
+#define FLOAT128_ARG(NAME, OP)
+#define FLOAT128_PTR(NAME, OP)
+#define FLOAT128_CALL()
+#endif
+
+#ifndef NO_LDOUBLE
+typedef _Complex long double ldouble_complex;
+extern ldouble_complex cldouble1 (void);
+extern ldouble_complex cldouble2 (void);
+
+#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
+#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
+#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
+
+#else
+#define LDOUBLE_ARG(NAME, OP)
+#define LDOUBLE_PTR(NAME, OP)
+#define LDOUBLE_CALL()
+#endif
+
+
+#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
+TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
+{									\
+  return a OP b;							\
+}
+
+#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
+void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
+{									\
+  *p = *a OP *b;							\
+}
+
+#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
+TYPE call_ ## SUFFIX (void)						\
+{									\
+  TYPE value1 = FUNC1 ();						\
+  TYPE value2 = FUNC2 ();						\
+  return value1 + value2;						\
+}
+
+#ifndef NO_ARG
+#ifndef NO_ADD
+FLOAT_ARG    (add, +)
+DOUBLE_ARG   (add, +)
+FLOAT128_ARG (add, +)
+LDOUBLE_ARG  (add, +)
+#endif
+
+#ifndef NO_SUB
+FLOAT_ARG    (sub, -)
+DOUBLE_ARG   (sub, -)
+FLOAT128_ARG (sub, -)
+LDOUBLE_ARG  (sub, -)
+#endif
+
+#ifndef NO_MUL
+FLOAT_ARG    (mul, *)
+DOUBLE_ARG   (mul, *)
+FLOAT128_ARG (mul, *)
+LDOUBLE_ARG  (mul, *)
+#endif
+
+#ifndef NO_DIV
+FLOAT_ARG    (div, /)
+DOUBLE_ARG   (div, /)
+FLOAT128_ARG (div, /)
+LDOUBLE_ARG  (div, /)
+#endif
+#endif
+
+#ifndef NO_PTR
+#ifndef NO_ADD
+FLOAT_PTR    (add, +)
+DOUBLE_PTR   (add, +)
+FLOAT128_PTR (add, +)
+LDOUBLE_PTR  (add, +)
+#endif
+
+#ifndef NO_SUB
+FLOAT_PTR    (sub, -)
+DOUBLE_PTR   (sub, -)
+FLOAT128_PTR (sub, -)
+LDOUBLE_PTR  (sub, -)
+#endif
+
+#ifndef NO_MUL
+FLOAT_PTR    (mul, *)
+DOUBLE_PTR   (mul, *)
+FLOAT128_PTR (mul, *)
+LDOUBLE_PTR  (mul, *)
+#endif
+
+#ifndef NO_DIV
+FLOAT_PTR    (div, /)
+DOUBLE_PTR   (div, /)
+FLOAT128_PTR (div, /)
+LDOUBLE_PTR  (div, /)
+#endif
+#endif
+
+#ifndef NO_CALL
+FLOAT_CALL    ()
+DOUBLE_CALL   ()
+FLOAT128_CALL ()
+LDOUBLE_CALL  ()
+#endif
Index: gcc/testsuite/gcc.target/powerpc/float128-complex-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/float128-complex-2.c	(revision 0)
@@ -0,0 +1,160 @@ 
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target powerpc_float128_hw_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-options "-O2 -mcpu=power9 -mfloat128 -mfloat128-hardware" } */
+
+#ifndef NO_FLOAT
+typedef _Complex float	float_complex;
+extern float_complex cfloat1 (void);
+extern float_complex cfloat2 (void);
+
+#define FLOAT_ARG(NAME, OP)	ARG_OP(float, float_complex, NAME, OP)
+#define FLOAT_PTR(NAME, OP)	PTR_OP(float, float_complex, NAME, OP)
+#define FLOAT_CALL()		CALL_OP(float, float_complex, cfloat1, cfloat2)
+
+#else
+#define FLOAT_ARG(NAME, OP)
+#define FLOAT_PTR(NAME, OP)
+#define FLOAT_CALL()
+#endif
+
+#ifndef NO_DOUBLE
+typedef _Complex double	double_complex;
+extern double_complex cdouble1 (void);
+extern double_complex cdouble2 (void);
+
+#define DOUBLE_ARG(NAME, OP)	ARG_OP(double, double_complex, NAME, OP)
+#define DOUBLE_PTR(NAME, OP)	PTR_OP(double, double_complex, NAME, OP)
+#define DOUBLE_CALL()		CALL_OP(double, double_complex, cdouble1, cdouble2)
+
+#else
+#define DOUBLE_ARG(NAME, OP)
+#define DOUBLE_PTR(NAME, OP)
+#define DOUBLE_CALL()
+#endif
+
+#ifndef NO_FLOAT128
+#ifdef __VSX__
+typedef _Complex float __attribute__((mode(KC)))	float128_complex;
+#else
+typedef _Complex float __attribute__((mode(TC)))	float128_complex;
+#endif
+
+extern float128_complex cfloat128_1 (void);
+extern float128_complex cfloat128_2 (void);
+
+#define FLOAT128_ARG(NAME, OP)	ARG_OP(float128, float128_complex, NAME, OP)
+#define FLOAT128_PTR(NAME, OP)	PTR_OP(float128, float128_complex, NAME, OP)
+#define FLOAT128_CALL()		CALL_OP(float128, float128_complex, cfloat128_1, cfloat128_2)
+
+#else
+#define FLOAT128_ARG(NAME, OP)
+#define FLOAT128_PTR(NAME, OP)
+#define FLOAT128_CALL()
+#endif
+
+#ifndef NO_LDOUBLE
+typedef _Complex long double ldouble_complex;
+extern ldouble_complex cldouble1 (void);
+extern ldouble_complex cldouble2 (void);
+
+#define LDOUBLE_ARG(NAME, OP)	ARG_OP(ldouble, ldouble_complex, NAME, OP)
+#define LDOUBLE_PTR(NAME, OP)	PTR_OP(ldouble, ldouble_complex, NAME, OP)
+#define LDOUBLE_CALL()		CALL_OP(ldouble, ldouble_complex, cldouble1, cldouble2)
+
+#else
+#define LDOUBLE_ARG(NAME, OP)
+#define LDOUBLE_PTR(NAME, OP)
+#define LDOUBLE_CALL()
+#endif
+
+
+#define ARG_OP(SUFFIX, TYPE, NAME, OP)					\
+TYPE arg_ ## NAME ## _ ## SUFFIX (TYPE a, TYPE b)			\
+{									\
+  return a OP b;							\
+}
+
+#define PTR_OP(SUFFIX, TYPE, NAME, OP)					\
+void ptr_ ## NAME ## _ ## SUFFIX (TYPE *p, TYPE *a, TYPE *b)		\
+{									\
+  *p = *a OP *b;							\
+}
+
+#define CALL_OP(SUFFIX, TYPE, FUNC1, FUNC2)				\
+TYPE call_ ## SUFFIX (void)						\
+{									\
+  TYPE value1 = FUNC1 ();						\
+  TYPE value2 = FUNC2 ();						\
+  return value1 + value2;						\
+}
+
+#ifndef NO_ARG
+#ifndef NO_ADD
+FLOAT_ARG    (add, +)
+DOUBLE_ARG   (add, +)
+FLOAT128_ARG (add, +)
+LDOUBLE_ARG  (add, +)
+#endif
+
+#ifndef NO_SUB
+FLOAT_ARG    (sub, -)
+DOUBLE_ARG   (sub, -)
+FLOAT128_ARG (sub, -)
+LDOUBLE_ARG  (sub, -)
+#endif
+
+#ifndef NO_MUL
+FLOAT_ARG    (mul, *)
+DOUBLE_ARG   (mul, *)
+FLOAT128_ARG (mul, *)
+LDOUBLE_ARG  (mul, *)
+#endif
+
+#ifndef NO_DIV
+FLOAT_ARG    (div, /)
+DOUBLE_ARG   (div, /)
+FLOAT128_ARG (div, /)
+LDOUBLE_ARG  (div, /)
+#endif
+#endif
+
+#ifndef NO_PTR
+#ifndef NO_ADD
+FLOAT_PTR    (add, +)
+DOUBLE_PTR   (add, +)
+FLOAT128_PTR (add, +)
+LDOUBLE_PTR  (add, +)
+#endif
+
+#ifndef NO_SUB
+FLOAT_PTR    (sub, -)
+DOUBLE_PTR   (sub, -)
+FLOAT128_PTR (sub, -)
+LDOUBLE_PTR  (sub, -)
+#endif
+
+#ifndef NO_MUL
+FLOAT_PTR    (mul, *)
+DOUBLE_PTR   (mul, *)
+FLOAT128_PTR (mul, *)
+LDOUBLE_PTR  (mul, *)
+#endif
+
+#ifndef NO_DIV
+FLOAT_PTR    (div, /)
+DOUBLE_PTR   (div, /)
+FLOAT128_PTR (div, /)
+LDOUBLE_PTR  (div, /)
+#endif
+#endif
+
+#ifndef NO_CALL
+FLOAT_CALL    ()
+DOUBLE_CALL   ()
+FLOAT128_CALL ()
+LDOUBLE_CALL  ()
+#endif
+
+/* { dg-final { scan-assembler "xsaddqp"  } } */
+/* { dg-final { scan-assembler "xssubqp"  } } */