diff mbox

[PATCHv2,rs6000] Add minimum __float128 built-in support required for glibc

Message ID DEA68D1C-CC68-4458-986E-6DF38ABA37F5@linux.vnet.ibm.com
State New
Headers show

Commit Message

Bill Schmidt June 23, 2016, 9:44 p.m. UTC
Hi,

This is a revision of my previous patch, correcting two issues.  The inff128
and huge_valf128 builtins now participate in folding so they are suitable
for use in static initializers, and the new builtins are now documented.
We no longer have a half-clever implementation to construct an infinity
inside vector registers, or the full-clever one that Segher proposed in
response. :)  We can try to add that support later if desired.

Regstrap in progress for powerpc64le-unknown-linux-gnu.  Provided
there are no regressions, is this ok?

Thanks,
Bill


[gcc]

2016-06-23  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	* config/rs6000/rs6000-builtin.def (BU_FLOAT128_2): New #define.
	(BU_FLOAT128_1): Likewise.
	(FABSF128): Likewise.
	(COPYSIGNF128): Likewise.
	(RS6000_BUILTIN_NANF128): Likewise.
	(RS6000_BUILTIN_NANSF128): Likewise.
	(RS6000_BUILTIN_INFF128): Likewise.
	(RS6000_BUILTIN_HUGE_VALF128): Likewise.
	* config/rs6000/rs6000.c (rs6000_fold_builtin): New prototype.
	(TARGET_FOLD_BUILTIN): New #define.
	(rs6000_builtin_mask_calculate): Add TARGET_FLOAT128 entry.
	(rs6000_invalid_builtin): Add handling for RS6000_BTM_FLOAT128.
	(rs6000_fold_builtin): New target hook implementation, handling
	folding of 128-bit NaNs and infinities.
	(rs6000_init_builtins): Initialize const_str_type_node; ensure all
	entries are filled in to avoid problems during bootstrap
	self-test; define builtins for 128-bit NaNs and infinities.
	(rs6000_opt_mask): Add entry for float128.
	* config/rs6000/rs6000.h (RS6000_BTM_FLOAT128): New #define.
	(RS6000_BTM_COMMON): Include RS6000_BTM_FLOAT128.
	(rs6000_builtin_type_index): Add RS6000_BTI_const_str.
	(const_str_type_node): New #define.
	* config/rs6000/rs6000.md (copysign<mode>3 for IEEE128): Convert
	to a define_expand that dispatches to either copysign<mode>3_soft
	or copysign<mode>3_hard.
	(copysign<mode>3_hard): Rename from copysign<mode>3.
	(copysign<mode>3_soft): New define_insn.
	* doc/extend.texi: Document new builtins.

[gcc/testsuite]

2016-06-23  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	* gcc.target/powerpc/abs128-1.c: New.
	* gcc.target/powerpc/copysign128-1.c: New.
	* gcc.target/powerpc/inf128-1.c: New.
	* gcc.target/powerpc/nan128-1.c: New.

Comments

Bill Schmidt June 23, 2016, 9:57 p.m. UTC | #1
So, I wasn't quite clear here... this is what I want to be able to put in 
6.2.  Normally we would put it upstream in trunk for burn-in, and then
backport after a bit.

Unfortunately we are going to have a naming conflict with Joseph's
patch to add the _Floatn, etc., builtin support.  So we can't put this
directly upstream.

We are in a bit of a quandary with timing to get this upstream for 6.2.
It seems for trunk we need to redevelop the patch after Joseph's
patch lands.  It is probably not too hard to make that all work, but I
need to understand it better.  Many portions of this patch won't be
appropriate for trunk, unless we choose to rename all the functions
to use a q suffix instead of f128.  I'm not sure how our glibc fellows
would feel about a change in naming, but probably not excited.

So, not quite sure where to go with this in order to get the code in
6.2 before it closes.  Open to advice.

Bill

> On Jun 23, 2016, at 4:44 PM, Bill Schmidt <wschmidt@linux.vnet.ibm.com> wrote:
> 
> Hi,
> 
> This is a revision of my previous patch, correcting two issues.  The inff128
> and huge_valf128 builtins now participate in folding so they are suitable
> for use in static initializers, and the new builtins are now documented.
> We no longer have a half-clever implementation to construct an infinity
> inside vector registers, or the full-clever one that Segher proposed in
> response. :)  We can try to add that support later if desired.
> 
> Regstrap in progress for powerpc64le-unknown-linux-gnu.  Provided
> there are no regressions, is this ok?
> 
> Thanks,
> Bill
> 
> 
> [gcc]
> 
> 2016-06-23  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	* config/rs6000/rs6000-builtin.def (BU_FLOAT128_2): New #define.
> 	(BU_FLOAT128_1): Likewise.
> 	(FABSF128): Likewise.
> 	(COPYSIGNF128): Likewise.
> 	(RS6000_BUILTIN_NANF128): Likewise.
> 	(RS6000_BUILTIN_NANSF128): Likewise.
> 	(RS6000_BUILTIN_INFF128): Likewise.
> 	(RS6000_BUILTIN_HUGE_VALF128): Likewise.
> 	* config/rs6000/rs6000.c (rs6000_fold_builtin): New prototype.
> 	(TARGET_FOLD_BUILTIN): New #define.
> 	(rs6000_builtin_mask_calculate): Add TARGET_FLOAT128 entry.
> 	(rs6000_invalid_builtin): Add handling for RS6000_BTM_FLOAT128.
> 	(rs6000_fold_builtin): New target hook implementation, handling
> 	folding of 128-bit NaNs and infinities.
> 	(rs6000_init_builtins): Initialize const_str_type_node; ensure all
> 	entries are filled in to avoid problems during bootstrap
> 	self-test; define builtins for 128-bit NaNs and infinities.
> 	(rs6000_opt_mask): Add entry for float128.
> 	* config/rs6000/rs6000.h (RS6000_BTM_FLOAT128): New #define.
> 	(RS6000_BTM_COMMON): Include RS6000_BTM_FLOAT128.
> 	(rs6000_builtin_type_index): Add RS6000_BTI_const_str.
> 	(const_str_type_node): New #define.
> 	* config/rs6000/rs6000.md (copysign<mode>3 for IEEE128): Convert
> 	to a define_expand that dispatches to either copysign<mode>3_soft
> 	or copysign<mode>3_hard.
> 	(copysign<mode>3_hard): Rename from copysign<mode>3.
> 	(copysign<mode>3_soft): New define_insn.
> 	* doc/extend.texi: Document new builtins.
> 
> [gcc/testsuite]
> 
> 2016-06-23  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	* gcc.target/powerpc/abs128-1.c: New.
> 	* gcc.target/powerpc/copysign128-1.c: New.
> 	* gcc.target/powerpc/inf128-1.c: New.
> 	* gcc.target/powerpc/nan128-1.c: New.
> 
> 
> Index: gcc/config/rs6000/rs6000-builtin.def
> ===================================================================
> --- gcc/config/rs6000/rs6000-builtin.def	(revision 237619)
> +++ gcc/config/rs6000/rs6000-builtin.def	(working copy)
> @@ -652,7 +652,23 @@
> 		     | RS6000_BTC_BINARY),				\
> 		    CODE_FOR_ ## ICODE)			/* ICODE */
> 
> +/* IEEE 128-bit floating-point builtins.  */
> +#define BU_FLOAT128_2(ENUM, NAME, ATTR, ICODE)                          \
> +  RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM,              /* ENUM */      \
> +                    "__builtin_" NAME,                  /* NAME */      \
> +		    RS6000_BTM_FLOAT128,                /* MASK */      \
> +		    (RS6000_BTC_ ## ATTR                /* ATTR */      \
> +		     | RS6000_BTC_BINARY),                              \
> +		    CODE_FOR_ ## ICODE)                 /* ICODE */
> 
> +#define BU_FLOAT128_1(ENUM, NAME, ATTR, ICODE)                          \
> +  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,              /* ENUM */      \
> +                    "__builtin_" NAME,                  /* NAME */      \
> +		    RS6000_BTM_FLOAT128,                /* MASK */      \
> +		    (RS6000_BTC_ ## ATTR                /* ATTR */      \
> +		     | RS6000_BTC_UNARY),                               \
> +		    CODE_FOR_ ## ICODE)                 /* ICODE */
> +
> /* Miscellaneous builtins for instructions added in ISA 3.0.  These
>    instructions don't require either the DFP or VSX options, just the basic
>    ISA 3.0 enablement since they operate on general purpose registers.  */
> @@ -1814,6 +1830,11 @@ BU_P9V_OVERLOAD_1 (VPRTYBD,	"vprtybd")
> BU_P9V_OVERLOAD_1 (VPRTYBQ,	"vprtybq")
> BU_P9V_OVERLOAD_1 (VPRTYBW,	"vprtybw")
> 
> +/* 1 argument IEEE 128-bit floating-point functions.  */
> +BU_FLOAT128_1 (FABSF128,	"fabsf128",       CONST, abskf2)
> +
> +/* 2 argument IEEE 128-bit floating-point functions.  */
> +BU_FLOAT128_2 (COPYSIGNF128,	"copysignf128",   CONST, copysignkf3)
> 
> /* 1 argument crypto functions.  */
> BU_CRYPTO_1 (VSBOX,		"vsbox",	  CONST, crypto_vsbox)
> @@ -2191,6 +2212,18 @@ BU_SPECIAL_X (RS6000_BUILTIN_CPU_IS, "__builtin_cp
> BU_SPECIAL_X (RS6000_BUILTIN_CPU_SUPPORTS, "__builtin_cpu_supports",
> 	      RS6000_BTM_ALWAYS, RS6000_BTC_MISC)
> 
> +BU_SPECIAL_X (RS6000_BUILTIN_NANF128, "__builtin_nanf128",
> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
> +
> +BU_SPECIAL_X (RS6000_BUILTIN_NANSF128, "__builtin_nansf128",
> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
> +
> +BU_SPECIAL_X (RS6000_BUILTIN_INFF128, "__builtin_inff128",
> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
> +
> +BU_SPECIAL_X (RS6000_BUILTIN_HUGE_VALF128, "__builtin_huge_valf128",
> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
> +
> /* Darwin CfString builtin.  */
> BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS,
> 	      RS6000_BTC_MISC)
> Index: gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc/config/rs6000/rs6000.c	(revision 237619)
> +++ gcc/config/rs6000/rs6000.c	(working copy)
> @@ -1328,6 +1328,7 @@ static bool rs6000_secondary_reload_move (enum rs6
> 					  bool);
> rtl_opt_pass *make_pass_analyze_swaps (gcc::context*);
> static bool rs6000_keep_leaf_when_profiled () __attribute__ ((unused));
> +static tree rs6000_fold_builtin (tree, int, tree *, bool);
> 
> /* Hash table stuff for keeping track of TOC entries.  */
> 
> @@ -1602,6 +1603,9 @@ static const struct attribute_spec rs6000_attribut
> #undef TARGET_BUILTIN_DECL
> #define TARGET_BUILTIN_DECL rs6000_builtin_decl
> 
> +#undef TARGET_FOLD_BUILTIN
> +#define TARGET_FOLD_BUILTIN rs6000_fold_builtin
> +
> #undef TARGET_EXPAND_BUILTIN
> #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
> 
> @@ -3682,7 +3686,8 @@ rs6000_builtin_mask_calculate (void)
> 	  | ((TARGET_HTM)		    ? RS6000_BTM_HTM	   : 0)
> 	  | ((TARGET_DFP)		    ? RS6000_BTM_DFP	   : 0)
> 	  | ((TARGET_HARD_FLOAT)	    ? RS6000_BTM_HARD_FLOAT : 0)
> -	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128 : 0));
> +	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128   : 0)
> +	  | ((TARGET_FLOAT128)              ? RS6000_BTM_FLOAT128  : 0));
> }
> 
> /* Implement TARGET_MD_ASM_ADJUST.  All asm statements are considered
> @@ -15510,11 +15515,57 @@ rs6000_invalid_builtin (enum rs6000_builtins fncod
> 	   " -mlong-double-128 options", name);
>   else if ((fnmask & RS6000_BTM_HARD_FLOAT) != 0)
>     error ("Builtin function %s requires the -mhard-float option", name);
> +  else if ((fnmask & RS6000_BTM_FLOAT128) != 0)
> +    error ("Builtin function %s requires the -mfloat128 option", name);
>   else
>     error ("Builtin function %s is not supported with the current options",
> 	   name);
> }
> 
> +/* Target hook for early folding of built-ins, shamelessly stolen
> +   from ia64.c.  */
> +
> +static tree
> +rs6000_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
> +		     tree *args, bool ignore ATTRIBUTE_UNUSED)
> +{
> +  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
> +    {
> +      enum rs6000_builtins fn_code
> +	= (enum rs6000_builtins) DECL_FUNCTION_CODE (fndecl);
> +      switch (fn_code)
> +	{
> +	case RS6000_BUILTIN_NANF128:
> +	case RS6000_BUILTIN_NANSF128:
> +	  {
> +	    tree type = TREE_TYPE (TREE_TYPE (fndecl));
> +	    const char *str = c_getstr (*args);
> +	    int quiet = fn_code == RS6000_BUILTIN_NANF128;
> +	    REAL_VALUE_TYPE real;
> +
> +	    if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
> +	      return build_real (type, real);
> +	    return NULL_TREE;
> +	  }
> +	case RS6000_BUILTIN_INFF128:
> +	case RS6000_BUILTIN_HUGE_VALF128:
> +	  {
> +	    tree type = TREE_TYPE (TREE_TYPE (fndecl));
> +	    REAL_VALUE_TYPE inf;
> +	    real_inf (&inf);
> +	    return build_real (type, inf);
> +	  }
> +	default:
> +	  break;
> +	}
> +    }
> +#ifdef SUBTARGET_FOLD_BUILTIN
> +  return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
> +#else
> +  return NULL_TREE;
> +#endif
> +}
> +
> /* Expand an expression EXP that calls a built-in function,
>    with result going to TARGET if that's convenient
>    (and in mode MODE if that's convenient).
> @@ -15769,6 +15820,10 @@ rs6000_init_builtins (void)
>   opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
>   opaque_V4SI_type_node = build_opaque_vector_type (intSI_type_node, 4);
> 
> +  const_str_type_node
> +    = build_pointer_type (build_qualified_type (char_type_node,
> +						TYPE_QUAL_CONST));
> +
>   /* We use V1TI mode as a special container to hold __int128_t items that
>      must live in VSX registers.  */
>   if (intTI_type_node)
> @@ -15831,6 +15886,12 @@ rs6000_init_builtins (void)
>       lang_hooks.types.register_builtin_type (ibm128_float_type_node,
> 					      "__ibm128");
>     }
> +  else
> +    {
> +      /* All types must be nonzero, or self-test barfs during bootstrap.  */
> +      ieee128_float_type_node = long_double_type_node;
> +      ibm128_float_type_node = long_double_type_node;
> +    }
> 
>   /* Initialize the modes for builtin_function_type, mapping a machine mode to
>      tree type node.  */
> @@ -15972,6 +16033,15 @@ rs6000_init_builtins (void)
>   if (TARGET_EXTRA_BUILTINS || TARGET_SPE || TARGET_PAIRED_FLOAT)
>     rs6000_common_init_builtins ();
> 
> +  ftype = build_function_type_list (ieee128_float_type_node,
> +				    const_str_type_node, NULL_TREE);
> +  def_builtin ("__builtin_nanf128", ftype, RS6000_BUILTIN_NANF128);
> +  def_builtin ("__builtin_nansf128", ftype, RS6000_BUILTIN_NANSF128);
> +
> +  ftype = build_function_type_list (ieee128_float_type_node, NULL_TREE);
> +  def_builtin ("__builtin_inff128", ftype, RS6000_BUILTIN_INFF128);
> +  def_builtin ("__builtin_huge_valf128", ftype, RS6000_BUILTIN_HUGE_VALF128);
> +
>   ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode,
> 				 RS6000_BUILTIN_RECIP, "__builtin_recipdiv");
>   def_builtin ("__builtin_recipdiv", ftype, RS6000_BUILTIN_RECIP);
> @@ -35569,6 +35639,7 @@ static struct rs6000_opt_mask const rs6000_builtin
>   { "hard-dfp",		 RS6000_BTM_DFP,	false, false },
>   { "hard-float",	 RS6000_BTM_HARD_FLOAT,	false, false },
>   { "long-double-128",	 RS6000_BTM_LDBL128,	false, false },
> +  { "float128",          RS6000_BTM_FLOAT128,   false, false },
> };
> 
> /* Option variables that we want to support inside attribute((target)) and
> Index: gcc/config/rs6000/rs6000.h
> ===================================================================
> --- gcc/config/rs6000/rs6000.h	(revision 237619)
> +++ gcc/config/rs6000/rs6000.h	(working copy)
> @@ -2689,6 +2689,7 @@ extern int frame_pointer_needed;
> #define RS6000_BTM_HARD_FLOAT	MASK_SOFT_FLOAT	/* Hardware floating point.  */
> #define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit long double.  */
> #define RS6000_BTM_64BIT	MASK_64BIT	/* 64-bit addressing.  */
> +#define RS6000_BTM_FLOAT128     MASK_P9_VECTOR  /* IEEE 128-bit float.  */
> 
> #define RS6000_BTM_COMMON	(RS6000_BTM_ALTIVEC			\
> 				 | RS6000_BTM_VSX			\
> @@ -2705,7 +2706,8 @@ extern int frame_pointer_needed;
> 				 | RS6000_BTM_CELL			\
> 				 | RS6000_BTM_DFP			\
> 				 | RS6000_BTM_HARD_FLOAT		\
> -				 | RS6000_BTM_LDBL128)
> +				 | RS6000_BTM_LDBL128                   \
> +				 | RS6000_BTM_FLOAT128)
> 
> /* Define builtin enum index.  */
> 
> @@ -2809,6 +2811,7 @@ enum rs6000_builtin_type_index
>   RS6000_BTI_void,	         /* void_type_node */
>   RS6000_BTI_ieee128_float,	 /* ieee 128-bit floating point */
>   RS6000_BTI_ibm128_float,	 /* IBM 128-bit floating point */
> +  RS6000_BTI_const_str,          /* pointer to const char * */
>   RS6000_BTI_MAX
> };
> 
> @@ -2865,6 +2868,7 @@ enum rs6000_builtin_type_index
> #define void_type_internal_node		 (rs6000_builtin_types[RS6000_BTI_void])
> #define ieee128_float_type_node		 (rs6000_builtin_types[RS6000_BTI_ieee128_float])
> #define ibm128_float_type_node		 (rs6000_builtin_types[RS6000_BTI_ibm128_float])
> +#define const_str_type_node	         (rs6000_builtin_types[RS6000_BTI_const_str])
> 
> extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX];
> extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
> Index: gcc/config/rs6000/rs6000.md
> ===================================================================
> --- gcc/config/rs6000/rs6000.md	(revision 237619)
> +++ gcc/config/rs6000/rs6000.md	(working copy)
> @@ -13326,7 +13326,25 @@
>    "xssqrtqp %0,%1"
>   [(set_attr "type" "vecdiv")])
> 
> -(define_insn "copysign<mode>3"
> +(define_expand "copysign<mode>3"
> +  [(use (match_operand:IEEE128 0 "altivec_register_operand" ""))
> +   (use (match_operand:IEEE128 1 "altivec_register_operand" ""))
> +   (use (match_operand:IEEE128 2 "altivec_register_operand" ""))]
> +  "FLOAT128_IEEE_P (<MODE>mode)"
> +{
> +  if (TARGET_FLOAT128_HW)
> +    emit_insn (gen_copysign<mode>3_hard (operands[0], operands[1],
> +    	                                 operands[2]));
> +  else
> +    {
> +      rtx tmp = gen_reg_rtx (<MODE>mode);
> +      emit_insn (gen_copysign<mode>3_soft (operands[0], operands[1],
> +      		                           operands[2], tmp));
> +    }
> +  DONE;
> +})
> +
> +(define_insn "copysign<mode>3_hard"
>   [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
> 	(unspec:IEEE128
> 	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
> @@ -13336,6 +13354,18 @@
>    "xscpsgnqp %0,%2,%1"
>   [(set_attr "type" "vecsimple")])
> 
> +(define_insn "copysign<mode>3_soft"
> +  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
> +	(unspec:IEEE128
> +	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
> +	  (match_operand:IEEE128 2 "altivec_register_operand" "v")
> +	  (match_operand:IEEE128 3 "altivec_register_operand" "+v")]
> +	 UNSPEC_COPYSIGN))]
> +  "!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
> +   "xscpsgndp %x3,%x2,%x1\n\txxpermdi %x0,%x3,%x1,1"
> +  [(set_attr "type" "veccomplex")
> +   (set_attr "length" "8")])
> +
> (define_insn "neg<mode>2_hw"
>   [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
> 	(neg:IEEE128
> Index: gcc/doc/extend.texi
> ===================================================================
> --- gcc/doc/extend.texi	(revision 237619)
> +++ gcc/doc/extend.texi	(working copy)
> @@ -14781,6 +14781,38 @@ The @code{__builtin_ppc_mftb} function always gene
> returns the Time Base Register value as an unsigned long, throwing away
> the most significant word on 32-bit environments.
> 
> +Additional built-in functions are available for the 64-bit PowerPC
> +family of processors, for efficient use of 128-bit floating point
> +(@code{__float128}) values.
> +
> +The following floating-point built-in functions are always available.  All
> +of them implement the function that is part of the name.
> +
> +@smallexample
> +__float128 __builtin_fabsf128 (__float128)
> +__float128 __builtin_copysignf128 (__float128, __float128)
> +@end smallexample
> +
> +The following built-in functions are always available.
> +
> +@table @code
> +@item __float128 __builtin_inff128 (void)
> +Similar to @code{__builtin_inf}, except the return type is @code{__float128}.
> +@findex __builtin_inff128
> +
> +@item __float128 __builtin_huge_valf128 (void)
> +Similar to @code{__builtin_huge_val}, except the return type is @code{__float128}.
> +@findex __builtin_huge_valf128
> +
> +@item __float128 __builtin_nanf128 (void)
> +Similar to @code{__builtin_nan}, except the return type is @code{__float128}.
> +@findex __builtin_nanf128
> +
> +@item __float128 __builtin_nansf128 (void)
> +Similar to @code{__builtin_nans}, except the return type is @code{__float128}.
> +@findex __builtin_nansf128
> +@end table
> +
> The following built-in functions are available for the PowerPC family
> of processors, starting with ISA 2.06 or later (@option{-mcpu=power7}
> or @option{-mpopcntd}):
> Index: gcc/testsuite/gcc.target/powerpc/abs128-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/abs128-1.c	(revision 0)
> +++ gcc/testsuite/gcc.target/powerpc/abs128-1.c	(working copy)
> @@ -0,0 +1,61 @@
> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
> +/* { dg-options "-mfloat128" } */
> +
> +void abort ();
> +
> +typedef unsigned long long int uint64_t;
> +
> +typedef union
> +{
> +  __float128 value;
> +
> +  struct
> +  {
> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> +    unsigned negative:1;
> +    unsigned exponent:15;
> +    unsigned quiet_nan:1;
> +    uint64_t mant_high:47;
> +    uint64_t mant_low:64;
> +#else
> +    uint64_t mant_low:64;
> +    uint64_t mant_high:47;
> +    unsigned quiet_nan:1;
> +    unsigned exponent:15;
> +    unsigned negative:1;
> +#endif
> +  } nan;
> +
> +} ieee854_float128;
> +
> +int
> +main (int argc, int *argv[])
> +{
> +  ieee854_float128 x, z;
> +
> +  x.nan.negative = 1;
> +  x.nan.exponent = 0x22;
> +  x.nan.quiet_nan = 0;
> +  x.nan.mant_high = 0x1234;
> +  x.nan.mant_low = 0xabcdef;
> +
> +  z.value = __builtin_fabsf128 (x.value);
> +
> +  if (z.nan.negative != 0
> +      || z.nan.exponent != 0x22
> +      || z.nan.quiet_nan != 0
> +      || z.nan.mant_high != 0x1234
> +      || z.nan.mant_low != 0xabcdef)
> +    abort ();
> +
> +  z.value = __builtin_fabsf128 (z.value);
> +
> +  if (z.nan.negative != 0
> +      || z.nan.exponent != 0x22
> +      || z.nan.quiet_nan != 0
> +      || z.nan.mant_high != 0x1234
> +      || z.nan.mant_low != 0xabcdef)
> +    abort ();
> +
> +  return 0;
> +}
> Index: gcc/testsuite/gcc.target/powerpc/copysign128-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/copysign128-1.c	(revision 0)
> +++ gcc/testsuite/gcc.target/powerpc/copysign128-1.c	(working copy)
> @@ -0,0 +1,58 @@
> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
> +/* { dg-options "-mfloat128" } */
> +
> +void abort ();
> +
> +typedef unsigned long long int uint64_t;
> +
> +typedef union
> +{
> +  __float128 value;
> +
> +  struct
> +  {
> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> +    unsigned negative:1;
> +    unsigned exponent:15;
> +    unsigned quiet_nan:1;
> +    uint64_t mant_high:47;
> +    uint64_t mant_low:64;
> +#else
> +    uint64_t mant_low:64;
> +    uint64_t mant_high:47;
> +    unsigned quiet_nan:1;
> +    unsigned exponent:15;
> +    unsigned negative:1;
> +#endif
> +  } nan;
> +
> +} ieee854_float128;
> +
> +int
> +main (int argc, int *argv[])
> +{
> +  ieee854_float128 x, y, z;
> +
> +  x.nan.negative = 0;
> +  x.nan.exponent = 0x22;
> +  x.nan.quiet_nan = 0;
> +  x.nan.mant_high = 0x1234;
> +  x.nan.mant_low = 0xabcdef;
> +
> +  y.nan.negative = 1;
> +  y.nan.exponent = 0;
> +  y.nan.quiet_nan = 0;
> +  y.nan.mant_high = 0;
> +  y.nan.mant_low = 0;
> +
> +  z.value = __builtin_copysignf128 (x.value, y.value);
> +
> +  if (z.nan.negative != 1
> +      || z.nan.exponent != 0x22
> +      || z.nan.quiet_nan != 0
> +      || z.nan.mant_high != 0x1234
> +      || z.nan.mant_low != 0xabcdef)
> +    abort ();
> +
> +  return 0;
> +}
> Index: gcc/testsuite/gcc.target/powerpc/inf128-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/inf128-1.c	(revision 0)
> +++ gcc/testsuite/gcc.target/powerpc/inf128-1.c	(working copy)
> @@ -0,0 +1,55 @@
> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
> +/* { dg-options "-mfloat128" } */
> +
> +void abort ();
> +
> +typedef unsigned long long int uint64_t;
> +
> +typedef union
> +{
> +  __float128 value;
> +
> +  struct
> +  {
> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> +    unsigned negative:1;
> +    unsigned exponent:15;
> +    unsigned quiet_nan:1;
> +    uint64_t mant_high:47;
> +    uint64_t mant_low:64;
> +#else
> +    uint64_t mant_low:64;
> +    uint64_t mant_high:47;
> +    unsigned quiet_nan:1;
> +    unsigned exponent:15;
> +    unsigned negative:1;
> +#endif
> +  } nan;
> +
> +} ieee854_float128;
> +
> +int
> +main (int argc, int *argv[])
> +{
> +  ieee854_float128 y;
> +
> +  y.value = __builtin_inff128 ();
> +
> +  if (y.nan.negative != 0
> +      || y.nan.exponent != 0x7fff
> +      || y.nan.quiet_nan != 0
> +      || y.nan.mant_high != 0
> +      || y.nan.mant_low != 0)
> +    abort ();
> +
> +  y.value = __builtin_huge_valf128 ();
> +
> +  if (y.nan.negative != 0
> +      || y.nan.exponent != 0x7fff
> +      || y.nan.quiet_nan != 0
> +      || y.nan.mant_high != 0
> +      || y.nan.mant_low != 0)
> +    abort ();
> +
> +  return 0;
> +}
> Index: gcc/testsuite/gcc.target/powerpc/nan128-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/powerpc/nan128-1.c	(revision 0)
> +++ gcc/testsuite/gcc.target/powerpc/nan128-1.c	(working copy)
> @@ -0,0 +1,77 @@
> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
> +/* { dg-options "-mfloat128" } */
> +
> +#include <stdio.h>
> +
> +void abort ();
> +
> +typedef unsigned long long int uint64_t;
> +
> +typedef union
> +{
> +  __float128 value;
> +
> +  struct
> +  {
> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> +    unsigned negative:1;
> +    unsigned exponent:15;
> +    unsigned quiet_nan:1;
> +    uint64_t mant_high:47;
> +    uint64_t mant_low:64;
> +#else
> +    uint64_t mant_low:64;
> +    uint64_t mant_high:47;
> +    unsigned quiet_nan:1;
> +    unsigned exponent:15;
> +    unsigned negative:1;
> +#endif
> +  } nan;
> +
> +} ieee854_float128;
> +
> +int
> +main (int argc, int *argv[])
> +{
> +  ieee854_float128 y;
> +
> +  y.value = __builtin_nanf128 ("1");
> +
> +  if (y.nan.negative != 0
> +      || y.nan.exponent != 0x7fff
> +      || y.nan.quiet_nan != 1
> +      || y.nan.mant_high != 0
> +      || y.nan.mant_low != 1)
> +    abort ();
> +
> +  y.value = __builtin_nanf128 ("0x2ab3c");
> +
> +  if (y.nan.negative != 0
> +      || y.nan.exponent != 0x7fff
> +      || y.nan.quiet_nan != 1
> +      || y.nan.mant_high != 0
> +      || y.nan.mant_low != 0x2ab3c)
> +    abort ();
> +
> +  y.value = __builtin_nansf128 ("1");
> +
> +  if (
> +      y.nan.negative != 0
> +      || y.nan.exponent != 0x7fff
> +      || y.nan.quiet_nan != 0
> +      || y.nan.mant_high != 0
> +      || y.nan.mant_low != 1
> +      )
> +    abort ();
> +
> +  y.value = __builtin_nansf128 ("0x2ab3c");
> +
> +  if (y.nan.negative != 0
> +      || y.nan.exponent != 0x7fff
> +      || y.nan.quiet_nan != 0
> +      || y.nan.mant_high != 0
> +      || y.nan.mant_low != 0x2ab3c)
> +    abort ();
> +
> +  return 0;
> +}
>
Bill Schmidt June 23, 2016, 10:24 p.m. UTC | #2
After discussing with the glibc folks, I'd like to propose that this patch
be altered to use the 'q' suffix for the builtin names.  That way we won't
have a naming conflict with Joseph's patch in the short term, and we'll
be able to stage the movement on trunk to the f128 support.

I've been informed that there are other packages/libraries that assume 
the 'q' suffix, so we will need both anyway.  For the time being, we can
use #defines for glibc using GCC 6 to define the f128 functions to be
the q functions.  We'll plan to normalize to use the arch-neutral f128
builtins after the 6.2 push completes.

If this is acceptable, I'll respin the patch with the new names and we
can move ahead.

Thanks,
Bill

> On Jun 23, 2016, at 4:57 PM, Bill Schmidt <wschmidt@linux.vnet.ibm.com> wrote:
> 
> So, I wasn't quite clear here... this is what I want to be able to put in 
> 6.2.  Normally we would put it upstream in trunk for burn-in, and then
> backport after a bit.
> 
> Unfortunately we are going to have a naming conflict with Joseph's
> patch to add the _Floatn, etc., builtin support.  So we can't put this
> directly upstream.
> 
> We are in a bit of a quandary with timing to get this upstream for 6.2.
> It seems for trunk we need to redevelop the patch after Joseph's
> patch lands.  It is probably not too hard to make that all work, but I
> need to understand it better.  Many portions of this patch won't be
> appropriate for trunk, unless we choose to rename all the functions
> to use a q suffix instead of f128.  I'm not sure how our glibc fellows
> would feel about a change in naming, but probably not excited.
> 
> So, not quite sure where to go with this in order to get the code in
> 6.2 before it closes.  Open to advice.
> 
> Bill
> 
>> On Jun 23, 2016, at 4:44 PM, Bill Schmidt <wschmidt@linux.vnet.ibm.com> wrote:
>> 
>> Hi,
>> 
>> This is a revision of my previous patch, correcting two issues.  The inff128
>> and huge_valf128 builtins now participate in folding so they are suitable
>> for use in static initializers, and the new builtins are now documented.
>> We no longer have a half-clever implementation to construct an infinity
>> inside vector registers, or the full-clever one that Segher proposed in
>> response. :)  We can try to add that support later if desired.
>> 
>> Regstrap in progress for powerpc64le-unknown-linux-gnu.  Provided
>> there are no regressions, is this ok?
>> 
>> Thanks,
>> Bill
>> 
>> 
>> [gcc]
>> 
>> 2016-06-23  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
>> 
>> 	* config/rs6000/rs6000-builtin.def (BU_FLOAT128_2): New #define.
>> 	(BU_FLOAT128_1): Likewise.
>> 	(FABSF128): Likewise.
>> 	(COPYSIGNF128): Likewise.
>> 	(RS6000_BUILTIN_NANF128): Likewise.
>> 	(RS6000_BUILTIN_NANSF128): Likewise.
>> 	(RS6000_BUILTIN_INFF128): Likewise.
>> 	(RS6000_BUILTIN_HUGE_VALF128): Likewise.
>> 	* config/rs6000/rs6000.c (rs6000_fold_builtin): New prototype.
>> 	(TARGET_FOLD_BUILTIN): New #define.
>> 	(rs6000_builtin_mask_calculate): Add TARGET_FLOAT128 entry.
>> 	(rs6000_invalid_builtin): Add handling for RS6000_BTM_FLOAT128.
>> 	(rs6000_fold_builtin): New target hook implementation, handling
>> 	folding of 128-bit NaNs and infinities.
>> 	(rs6000_init_builtins): Initialize const_str_type_node; ensure all
>> 	entries are filled in to avoid problems during bootstrap
>> 	self-test; define builtins for 128-bit NaNs and infinities.
>> 	(rs6000_opt_mask): Add entry for float128.
>> 	* config/rs6000/rs6000.h (RS6000_BTM_FLOAT128): New #define.
>> 	(RS6000_BTM_COMMON): Include RS6000_BTM_FLOAT128.
>> 	(rs6000_builtin_type_index): Add RS6000_BTI_const_str.
>> 	(const_str_type_node): New #define.
>> 	* config/rs6000/rs6000.md (copysign<mode>3 for IEEE128): Convert
>> 	to a define_expand that dispatches to either copysign<mode>3_soft
>> 	or copysign<mode>3_hard.
>> 	(copysign<mode>3_hard): Rename from copysign<mode>3.
>> 	(copysign<mode>3_soft): New define_insn.
>> 	* doc/extend.texi: Document new builtins.
>> 
>> [gcc/testsuite]
>> 
>> 2016-06-23  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
>> 
>> 	* gcc.target/powerpc/abs128-1.c: New.
>> 	* gcc.target/powerpc/copysign128-1.c: New.
>> 	* gcc.target/powerpc/inf128-1.c: New.
>> 	* gcc.target/powerpc/nan128-1.c: New.
>> 
>> 
>> Index: gcc/config/rs6000/rs6000-builtin.def
>> ===================================================================
>> --- gcc/config/rs6000/rs6000-builtin.def	(revision 237619)
>> +++ gcc/config/rs6000/rs6000-builtin.def	(working copy)
>> @@ -652,7 +652,23 @@
>> 		     | RS6000_BTC_BINARY),				\
>> 		    CODE_FOR_ ## ICODE)			/* ICODE */
>> 
>> +/* IEEE 128-bit floating-point builtins.  */
>> +#define BU_FLOAT128_2(ENUM, NAME, ATTR, ICODE)                          \
>> +  RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM,              /* ENUM */      \
>> +                    "__builtin_" NAME,                  /* NAME */      \
>> +		    RS6000_BTM_FLOAT128,                /* MASK */      \
>> +		    (RS6000_BTC_ ## ATTR                /* ATTR */      \
>> +		     | RS6000_BTC_BINARY),                              \
>> +		    CODE_FOR_ ## ICODE)                 /* ICODE */
>> 
>> +#define BU_FLOAT128_1(ENUM, NAME, ATTR, ICODE)                          \
>> +  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,              /* ENUM */      \
>> +                    "__builtin_" NAME,                  /* NAME */      \
>> +		    RS6000_BTM_FLOAT128,                /* MASK */      \
>> +		    (RS6000_BTC_ ## ATTR                /* ATTR */      \
>> +		     | RS6000_BTC_UNARY),                               \
>> +		    CODE_FOR_ ## ICODE)                 /* ICODE */
>> +
>> /* Miscellaneous builtins for instructions added in ISA 3.0.  These
>>   instructions don't require either the DFP or VSX options, just the basic
>>   ISA 3.0 enablement since they operate on general purpose registers.  */
>> @@ -1814,6 +1830,11 @@ BU_P9V_OVERLOAD_1 (VPRTYBD,	"vprtybd")
>> BU_P9V_OVERLOAD_1 (VPRTYBQ,	"vprtybq")
>> BU_P9V_OVERLOAD_1 (VPRTYBW,	"vprtybw")
>> 
>> +/* 1 argument IEEE 128-bit floating-point functions.  */
>> +BU_FLOAT128_1 (FABSF128,	"fabsf128",       CONST, abskf2)
>> +
>> +/* 2 argument IEEE 128-bit floating-point functions.  */
>> +BU_FLOAT128_2 (COPYSIGNF128,	"copysignf128",   CONST, copysignkf3)
>> 
>> /* 1 argument crypto functions.  */
>> BU_CRYPTO_1 (VSBOX,		"vsbox",	  CONST, crypto_vsbox)
>> @@ -2191,6 +2212,18 @@ BU_SPECIAL_X (RS6000_BUILTIN_CPU_IS, "__builtin_cp
>> BU_SPECIAL_X (RS6000_BUILTIN_CPU_SUPPORTS, "__builtin_cpu_supports",
>> 	      RS6000_BTM_ALWAYS, RS6000_BTC_MISC)
>> 
>> +BU_SPECIAL_X (RS6000_BUILTIN_NANF128, "__builtin_nanf128",
>> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
>> +
>> +BU_SPECIAL_X (RS6000_BUILTIN_NANSF128, "__builtin_nansf128",
>> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
>> +
>> +BU_SPECIAL_X (RS6000_BUILTIN_INFF128, "__builtin_inff128",
>> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
>> +
>> +BU_SPECIAL_X (RS6000_BUILTIN_HUGE_VALF128, "__builtin_huge_valf128",
>> +	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
>> +
>> /* Darwin CfString builtin.  */
>> BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS,
>> 	      RS6000_BTC_MISC)
>> Index: gcc/config/rs6000/rs6000.c
>> ===================================================================
>> --- gcc/config/rs6000/rs6000.c	(revision 237619)
>> +++ gcc/config/rs6000/rs6000.c	(working copy)
>> @@ -1328,6 +1328,7 @@ static bool rs6000_secondary_reload_move (enum rs6
>> 					  bool);
>> rtl_opt_pass *make_pass_analyze_swaps (gcc::context*);
>> static bool rs6000_keep_leaf_when_profiled () __attribute__ ((unused));
>> +static tree rs6000_fold_builtin (tree, int, tree *, bool);
>> 
>> /* Hash table stuff for keeping track of TOC entries.  */
>> 
>> @@ -1602,6 +1603,9 @@ static const struct attribute_spec rs6000_attribut
>> #undef TARGET_BUILTIN_DECL
>> #define TARGET_BUILTIN_DECL rs6000_builtin_decl
>> 
>> +#undef TARGET_FOLD_BUILTIN
>> +#define TARGET_FOLD_BUILTIN rs6000_fold_builtin
>> +
>> #undef TARGET_EXPAND_BUILTIN
>> #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
>> 
>> @@ -3682,7 +3686,8 @@ rs6000_builtin_mask_calculate (void)
>> 	  | ((TARGET_HTM)		    ? RS6000_BTM_HTM	   : 0)
>> 	  | ((TARGET_DFP)		    ? RS6000_BTM_DFP	   : 0)
>> 	  | ((TARGET_HARD_FLOAT)	    ? RS6000_BTM_HARD_FLOAT : 0)
>> -	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128 : 0));
>> +	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128   : 0)
>> +	  | ((TARGET_FLOAT128)              ? RS6000_BTM_FLOAT128  : 0));
>> }
>> 
>> /* Implement TARGET_MD_ASM_ADJUST.  All asm statements are considered
>> @@ -15510,11 +15515,57 @@ rs6000_invalid_builtin (enum rs6000_builtins fncod
>> 	   " -mlong-double-128 options", name);
>>  else if ((fnmask & RS6000_BTM_HARD_FLOAT) != 0)
>>    error ("Builtin function %s requires the -mhard-float option", name);
>> +  else if ((fnmask & RS6000_BTM_FLOAT128) != 0)
>> +    error ("Builtin function %s requires the -mfloat128 option", name);
>>  else
>>    error ("Builtin function %s is not supported with the current options",
>> 	   name);
>> }
>> 
>> +/* Target hook for early folding of built-ins, shamelessly stolen
>> +   from ia64.c.  */
>> +
>> +static tree
>> +rs6000_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
>> +		     tree *args, bool ignore ATTRIBUTE_UNUSED)
>> +{
>> +  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
>> +    {
>> +      enum rs6000_builtins fn_code
>> +	= (enum rs6000_builtins) DECL_FUNCTION_CODE (fndecl);
>> +      switch (fn_code)
>> +	{
>> +	case RS6000_BUILTIN_NANF128:
>> +	case RS6000_BUILTIN_NANSF128:
>> +	  {
>> +	    tree type = TREE_TYPE (TREE_TYPE (fndecl));
>> +	    const char *str = c_getstr (*args);
>> +	    int quiet = fn_code == RS6000_BUILTIN_NANF128;
>> +	    REAL_VALUE_TYPE real;
>> +
>> +	    if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
>> +	      return build_real (type, real);
>> +	    return NULL_TREE;
>> +	  }
>> +	case RS6000_BUILTIN_INFF128:
>> +	case RS6000_BUILTIN_HUGE_VALF128:
>> +	  {
>> +	    tree type = TREE_TYPE (TREE_TYPE (fndecl));
>> +	    REAL_VALUE_TYPE inf;
>> +	    real_inf (&inf);
>> +	    return build_real (type, inf);
>> +	  }
>> +	default:
>> +	  break;
>> +	}
>> +    }
>> +#ifdef SUBTARGET_FOLD_BUILTIN
>> +  return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
>> +#else
>> +  return NULL_TREE;
>> +#endif
>> +}
>> +
>> /* Expand an expression EXP that calls a built-in function,
>>   with result going to TARGET if that's convenient
>>   (and in mode MODE if that's convenient).
>> @@ -15769,6 +15820,10 @@ rs6000_init_builtins (void)
>>  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
>>  opaque_V4SI_type_node = build_opaque_vector_type (intSI_type_node, 4);
>> 
>> +  const_str_type_node
>> +    = build_pointer_type (build_qualified_type (char_type_node,
>> +						TYPE_QUAL_CONST));
>> +
>>  /* We use V1TI mode as a special container to hold __int128_t items that
>>     must live in VSX registers.  */
>>  if (intTI_type_node)
>> @@ -15831,6 +15886,12 @@ rs6000_init_builtins (void)
>>      lang_hooks.types.register_builtin_type (ibm128_float_type_node,
>> 					      "__ibm128");
>>    }
>> +  else
>> +    {
>> +      /* All types must be nonzero, or self-test barfs during bootstrap.  */
>> +      ieee128_float_type_node = long_double_type_node;
>> +      ibm128_float_type_node = long_double_type_node;
>> +    }
>> 
>>  /* Initialize the modes for builtin_function_type, mapping a machine mode to
>>     tree type node.  */
>> @@ -15972,6 +16033,15 @@ rs6000_init_builtins (void)
>>  if (TARGET_EXTRA_BUILTINS || TARGET_SPE || TARGET_PAIRED_FLOAT)
>>    rs6000_common_init_builtins ();
>> 
>> +  ftype = build_function_type_list (ieee128_float_type_node,
>> +				    const_str_type_node, NULL_TREE);
>> +  def_builtin ("__builtin_nanf128", ftype, RS6000_BUILTIN_NANF128);
>> +  def_builtin ("__builtin_nansf128", ftype, RS6000_BUILTIN_NANSF128);
>> +
>> +  ftype = build_function_type_list (ieee128_float_type_node, NULL_TREE);
>> +  def_builtin ("__builtin_inff128", ftype, RS6000_BUILTIN_INFF128);
>> +  def_builtin ("__builtin_huge_valf128", ftype, RS6000_BUILTIN_HUGE_VALF128);
>> +
>>  ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode,
>> 				 RS6000_BUILTIN_RECIP, "__builtin_recipdiv");
>>  def_builtin ("__builtin_recipdiv", ftype, RS6000_BUILTIN_RECIP);
>> @@ -35569,6 +35639,7 @@ static struct rs6000_opt_mask const rs6000_builtin
>>  { "hard-dfp",		 RS6000_BTM_DFP,	false, false },
>>  { "hard-float",	 RS6000_BTM_HARD_FLOAT,	false, false },
>>  { "long-double-128",	 RS6000_BTM_LDBL128,	false, false },
>> +  { "float128",          RS6000_BTM_FLOAT128,   false, false },
>> };
>> 
>> /* Option variables that we want to support inside attribute((target)) and
>> Index: gcc/config/rs6000/rs6000.h
>> ===================================================================
>> --- gcc/config/rs6000/rs6000.h	(revision 237619)
>> +++ gcc/config/rs6000/rs6000.h	(working copy)
>> @@ -2689,6 +2689,7 @@ extern int frame_pointer_needed;
>> #define RS6000_BTM_HARD_FLOAT	MASK_SOFT_FLOAT	/* Hardware floating point.  */
>> #define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit long double.  */
>> #define RS6000_BTM_64BIT	MASK_64BIT	/* 64-bit addressing.  */
>> +#define RS6000_BTM_FLOAT128     MASK_P9_VECTOR  /* IEEE 128-bit float.  */
>> 
>> #define RS6000_BTM_COMMON	(RS6000_BTM_ALTIVEC			\
>> 				 | RS6000_BTM_VSX			\
>> @@ -2705,7 +2706,8 @@ extern int frame_pointer_needed;
>> 				 | RS6000_BTM_CELL			\
>> 				 | RS6000_BTM_DFP			\
>> 				 | RS6000_BTM_HARD_FLOAT		\
>> -				 | RS6000_BTM_LDBL128)
>> +				 | RS6000_BTM_LDBL128                   \
>> +				 | RS6000_BTM_FLOAT128)
>> 
>> /* Define builtin enum index.  */
>> 
>> @@ -2809,6 +2811,7 @@ enum rs6000_builtin_type_index
>>  RS6000_BTI_void,	         /* void_type_node */
>>  RS6000_BTI_ieee128_float,	 /* ieee 128-bit floating point */
>>  RS6000_BTI_ibm128_float,	 /* IBM 128-bit floating point */
>> +  RS6000_BTI_const_str,          /* pointer to const char * */
>>  RS6000_BTI_MAX
>> };
>> 
>> @@ -2865,6 +2868,7 @@ enum rs6000_builtin_type_index
>> #define void_type_internal_node		 (rs6000_builtin_types[RS6000_BTI_void])
>> #define ieee128_float_type_node		 (rs6000_builtin_types[RS6000_BTI_ieee128_float])
>> #define ibm128_float_type_node		 (rs6000_builtin_types[RS6000_BTI_ibm128_float])
>> +#define const_str_type_node	         (rs6000_builtin_types[RS6000_BTI_const_str])
>> 
>> extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX];
>> extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
>> Index: gcc/config/rs6000/rs6000.md
>> ===================================================================
>> --- gcc/config/rs6000/rs6000.md	(revision 237619)
>> +++ gcc/config/rs6000/rs6000.md	(working copy)
>> @@ -13326,7 +13326,25 @@
>>   "xssqrtqp %0,%1"
>>  [(set_attr "type" "vecdiv")])
>> 
>> -(define_insn "copysign<mode>3"
>> +(define_expand "copysign<mode>3"
>> +  [(use (match_operand:IEEE128 0 "altivec_register_operand" ""))
>> +   (use (match_operand:IEEE128 1 "altivec_register_operand" ""))
>> +   (use (match_operand:IEEE128 2 "altivec_register_operand" ""))]
>> +  "FLOAT128_IEEE_P (<MODE>mode)"
>> +{
>> +  if (TARGET_FLOAT128_HW)
>> +    emit_insn (gen_copysign<mode>3_hard (operands[0], operands[1],
>> +    	                                 operands[2]));
>> +  else
>> +    {
>> +      rtx tmp = gen_reg_rtx (<MODE>mode);
>> +      emit_insn (gen_copysign<mode>3_soft (operands[0], operands[1],
>> +      		                           operands[2], tmp));
>> +    }
>> +  DONE;
>> +})
>> +
>> +(define_insn "copysign<mode>3_hard"
>>  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
>> 	(unspec:IEEE128
>> 	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
>> @@ -13336,6 +13354,18 @@
>>   "xscpsgnqp %0,%2,%1"
>>  [(set_attr "type" "vecsimple")])
>> 
>> +(define_insn "copysign<mode>3_soft"
>> +  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
>> +	(unspec:IEEE128
>> +	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
>> +	  (match_operand:IEEE128 2 "altivec_register_operand" "v")
>> +	  (match_operand:IEEE128 3 "altivec_register_operand" "+v")]
>> +	 UNSPEC_COPYSIGN))]
>> +  "!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
>> +   "xscpsgndp %x3,%x2,%x1\n\txxpermdi %x0,%x3,%x1,1"
>> +  [(set_attr "type" "veccomplex")
>> +   (set_attr "length" "8")])
>> +
>> (define_insn "neg<mode>2_hw"
>>  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
>> 	(neg:IEEE128
>> Index: gcc/doc/extend.texi
>> ===================================================================
>> --- gcc/doc/extend.texi	(revision 237619)
>> +++ gcc/doc/extend.texi	(working copy)
>> @@ -14781,6 +14781,38 @@ The @code{__builtin_ppc_mftb} function always gene
>> returns the Time Base Register value as an unsigned long, throwing away
>> the most significant word on 32-bit environments.
>> 
>> +Additional built-in functions are available for the 64-bit PowerPC
>> +family of processors, for efficient use of 128-bit floating point
>> +(@code{__float128}) values.
>> +
>> +The following floating-point built-in functions are always available.  All
>> +of them implement the function that is part of the name.
>> +
>> +@smallexample
>> +__float128 __builtin_fabsf128 (__float128)
>> +__float128 __builtin_copysignf128 (__float128, __float128)
>> +@end smallexample
>> +
>> +The following built-in functions are always available.
>> +
>> +@table @code
>> +@item __float128 __builtin_inff128 (void)
>> +Similar to @code{__builtin_inf}, except the return type is @code{__float128}.
>> +@findex __builtin_inff128
>> +
>> +@item __float128 __builtin_huge_valf128 (void)
>> +Similar to @code{__builtin_huge_val}, except the return type is @code{__float128}.
>> +@findex __builtin_huge_valf128
>> +
>> +@item __float128 __builtin_nanf128 (void)
>> +Similar to @code{__builtin_nan}, except the return type is @code{__float128}.
>> +@findex __builtin_nanf128
>> +
>> +@item __float128 __builtin_nansf128 (void)
>> +Similar to @code{__builtin_nans}, except the return type is @code{__float128}.
>> +@findex __builtin_nansf128
>> +@end table
>> +
>> The following built-in functions are available for the PowerPC family
>> of processors, starting with ISA 2.06 or later (@option{-mcpu=power7}
>> or @option{-mpopcntd}):
>> Index: gcc/testsuite/gcc.target/powerpc/abs128-1.c
>> ===================================================================
>> --- gcc/testsuite/gcc.target/powerpc/abs128-1.c	(revision 0)
>> +++ gcc/testsuite/gcc.target/powerpc/abs128-1.c	(working copy)
>> @@ -0,0 +1,61 @@
>> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
>> +/* { dg-options "-mfloat128" } */
>> +
>> +void abort ();
>> +
>> +typedef unsigned long long int uint64_t;
>> +
>> +typedef union
>> +{
>> +  __float128 value;
>> +
>> +  struct
>> +  {
>> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
>> +    unsigned negative:1;
>> +    unsigned exponent:15;
>> +    unsigned quiet_nan:1;
>> +    uint64_t mant_high:47;
>> +    uint64_t mant_low:64;
>> +#else
>> +    uint64_t mant_low:64;
>> +    uint64_t mant_high:47;
>> +    unsigned quiet_nan:1;
>> +    unsigned exponent:15;
>> +    unsigned negative:1;
>> +#endif
>> +  } nan;
>> +
>> +} ieee854_float128;
>> +
>> +int
>> +main (int argc, int *argv[])
>> +{
>> +  ieee854_float128 x, z;
>> +
>> +  x.nan.negative = 1;
>> +  x.nan.exponent = 0x22;
>> +  x.nan.quiet_nan = 0;
>> +  x.nan.mant_high = 0x1234;
>> +  x.nan.mant_low = 0xabcdef;
>> +
>> +  z.value = __builtin_fabsf128 (x.value);
>> +
>> +  if (z.nan.negative != 0
>> +      || z.nan.exponent != 0x22
>> +      || z.nan.quiet_nan != 0
>> +      || z.nan.mant_high != 0x1234
>> +      || z.nan.mant_low != 0xabcdef)
>> +    abort ();
>> +
>> +  z.value = __builtin_fabsf128 (z.value);
>> +
>> +  if (z.nan.negative != 0
>> +      || z.nan.exponent != 0x22
>> +      || z.nan.quiet_nan != 0
>> +      || z.nan.mant_high != 0x1234
>> +      || z.nan.mant_low != 0xabcdef)
>> +    abort ();
>> +
>> +  return 0;
>> +}
>> Index: gcc/testsuite/gcc.target/powerpc/copysign128-1.c
>> ===================================================================
>> --- gcc/testsuite/gcc.target/powerpc/copysign128-1.c	(revision 0)
>> +++ gcc/testsuite/gcc.target/powerpc/copysign128-1.c	(working copy)
>> @@ -0,0 +1,58 @@
>> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
>> +/* { dg-options "-mfloat128" } */
>> +
>> +void abort ();
>> +
>> +typedef unsigned long long int uint64_t;
>> +
>> +typedef union
>> +{
>> +  __float128 value;
>> +
>> +  struct
>> +  {
>> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
>> +    unsigned negative:1;
>> +    unsigned exponent:15;
>> +    unsigned quiet_nan:1;
>> +    uint64_t mant_high:47;
>> +    uint64_t mant_low:64;
>> +#else
>> +    uint64_t mant_low:64;
>> +    uint64_t mant_high:47;
>> +    unsigned quiet_nan:1;
>> +    unsigned exponent:15;
>> +    unsigned negative:1;
>> +#endif
>> +  } nan;
>> +
>> +} ieee854_float128;
>> +
>> +int
>> +main (int argc, int *argv[])
>> +{
>> +  ieee854_float128 x, y, z;
>> +
>> +  x.nan.negative = 0;
>> +  x.nan.exponent = 0x22;
>> +  x.nan.quiet_nan = 0;
>> +  x.nan.mant_high = 0x1234;
>> +  x.nan.mant_low = 0xabcdef;
>> +
>> +  y.nan.negative = 1;
>> +  y.nan.exponent = 0;
>> +  y.nan.quiet_nan = 0;
>> +  y.nan.mant_high = 0;
>> +  y.nan.mant_low = 0;
>> +
>> +  z.value = __builtin_copysignf128 (x.value, y.value);
>> +
>> +  if (z.nan.negative != 1
>> +      || z.nan.exponent != 0x22
>> +      || z.nan.quiet_nan != 0
>> +      || z.nan.mant_high != 0x1234
>> +      || z.nan.mant_low != 0xabcdef)
>> +    abort ();
>> +
>> +  return 0;
>> +}
>> Index: gcc/testsuite/gcc.target/powerpc/inf128-1.c
>> ===================================================================
>> --- gcc/testsuite/gcc.target/powerpc/inf128-1.c	(revision 0)
>> +++ gcc/testsuite/gcc.target/powerpc/inf128-1.c	(working copy)
>> @@ -0,0 +1,55 @@
>> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
>> +/* { dg-options "-mfloat128" } */
>> +
>> +void abort ();
>> +
>> +typedef unsigned long long int uint64_t;
>> +
>> +typedef union
>> +{
>> +  __float128 value;
>> +
>> +  struct
>> +  {
>> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
>> +    unsigned negative:1;
>> +    unsigned exponent:15;
>> +    unsigned quiet_nan:1;
>> +    uint64_t mant_high:47;
>> +    uint64_t mant_low:64;
>> +#else
>> +    uint64_t mant_low:64;
>> +    uint64_t mant_high:47;
>> +    unsigned quiet_nan:1;
>> +    unsigned exponent:15;
>> +    unsigned negative:1;
>> +#endif
>> +  } nan;
>> +
>> +} ieee854_float128;
>> +
>> +int
>> +main (int argc, int *argv[])
>> +{
>> +  ieee854_float128 y;
>> +
>> +  y.value = __builtin_inff128 ();
>> +
>> +  if (y.nan.negative != 0
>> +      || y.nan.exponent != 0x7fff
>> +      || y.nan.quiet_nan != 0
>> +      || y.nan.mant_high != 0
>> +      || y.nan.mant_low != 0)
>> +    abort ();
>> +
>> +  y.value = __builtin_huge_valf128 ();
>> +
>> +  if (y.nan.negative != 0
>> +      || y.nan.exponent != 0x7fff
>> +      || y.nan.quiet_nan != 0
>> +      || y.nan.mant_high != 0
>> +      || y.nan.mant_low != 0)
>> +    abort ();
>> +
>> +  return 0;
>> +}
>> Index: gcc/testsuite/gcc.target/powerpc/nan128-1.c
>> ===================================================================
>> --- gcc/testsuite/gcc.target/powerpc/nan128-1.c	(revision 0)
>> +++ gcc/testsuite/gcc.target/powerpc/nan128-1.c	(working copy)
>> @@ -0,0 +1,77 @@
>> +/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
>> +/* { dg-options "-mfloat128" } */
>> +
>> +#include <stdio.h>
>> +
>> +void abort ();
>> +
>> +typedef unsigned long long int uint64_t;
>> +
>> +typedef union
>> +{
>> +  __float128 value;
>> +
>> +  struct
>> +  {
>> +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
>> +    unsigned negative:1;
>> +    unsigned exponent:15;
>> +    unsigned quiet_nan:1;
>> +    uint64_t mant_high:47;
>> +    uint64_t mant_low:64;
>> +#else
>> +    uint64_t mant_low:64;
>> +    uint64_t mant_high:47;
>> +    unsigned quiet_nan:1;
>> +    unsigned exponent:15;
>> +    unsigned negative:1;
>> +#endif
>> +  } nan;
>> +
>> +} ieee854_float128;
>> +
>> +int
>> +main (int argc, int *argv[])
>> +{
>> +  ieee854_float128 y;
>> +
>> +  y.value = __builtin_nanf128 ("1");
>> +
>> +  if (y.nan.negative != 0
>> +      || y.nan.exponent != 0x7fff
>> +      || y.nan.quiet_nan != 1
>> +      || y.nan.mant_high != 0
>> +      || y.nan.mant_low != 1)
>> +    abort ();
>> +
>> +  y.value = __builtin_nanf128 ("0x2ab3c");
>> +
>> +  if (y.nan.negative != 0
>> +      || y.nan.exponent != 0x7fff
>> +      || y.nan.quiet_nan != 1
>> +      || y.nan.mant_high != 0
>> +      || y.nan.mant_low != 0x2ab3c)
>> +    abort ();
>> +
>> +  y.value = __builtin_nansf128 ("1");
>> +
>> +  if (
>> +      y.nan.negative != 0
>> +      || y.nan.exponent != 0x7fff
>> +      || y.nan.quiet_nan != 0
>> +      || y.nan.mant_high != 0
>> +      || y.nan.mant_low != 1
>> +      )
>> +    abort ();
>> +
>> +  y.value = __builtin_nansf128 ("0x2ab3c");
>> +
>> +  if (y.nan.negative != 0
>> +      || y.nan.exponent != 0x7fff
>> +      || y.nan.quiet_nan != 0
>> +      || y.nan.mant_high != 0
>> +      || y.nan.mant_low != 0x2ab3c)
>> +    abort ();
>> +
>> +  return 0;
>> +}
>> 
>
Joseph Myers June 23, 2016, 10:41 p.m. UTC | #3
On Thu, 23 Jun 2016, Bill Schmidt wrote:

> After discussing with the glibc folks, I'd like to propose that this patch
> be altered to use the 'q' suffix for the builtin names.  That way we won't
> have a naming conflict with Joseph's patch in the short term, and we'll
> be able to stage the movement on trunk to the f128 support.
> 
> I've been informed that there are other packages/libraries that assume 
> the 'q' suffix, so we will need both anyway.  For the time being, we can
> use #defines for glibc using GCC 6 to define the f128 functions to be
> the q functions.  We'll plan to normalize to use the arch-neutral f128
> builtins after the 6.2 push completes.

Those #defines in glibc would be needed anyway for __float128 functions in 
glibc for x86 to support GCC versions before GCC 7 (which x86 support I'm 
minded to look at adding once the __float128 functions for powerpc64le are 
in; adding them for a new architecture shouldn't be hard once the first 
architecture is done).

The 'q' suffix should be considered legacy (just like the __float128 
name!), but if it doesn't conflict with the generic support it's 
essentially a target maintainer matter.  As I said in my patch submission 
for the generic functions, I don't know if target built-in functions can 
be made into aliases for generic ones, but that's what's desirable in 
optimization terms once the generic ones are in, so that optimizations 
apply equally to both.

(I'm presuming that eventually we *will* enable all built-in function and 
other optimizations, that currently are just for float / double / long 
double, for the new types and their corresponding TS 18661-3 functions as 
well - that's just lower priority since it's not at all on the critical 
path for enabling support for the new type, unlike this minimal set of 
functions.)

Do those packages assuming 'q' expect more than the minimal built-in 
functions (i.e., do they want libquadmath)?  I've noted before that while 
libquadmath is not the way forward for libm support for __float128 (that's 
*f128 functions in glibc), and while libquadmath is missing the past few 
years' improvements to glibc libm, enabling it for powerpc64le (once 
you've got built-in functions and complex arithmetic functions in libgcc) 
would allow you to test that the back-end __float128 support works for a 
substantial body of code with __float128 arithmetic....  (While there is 
no libquadmath testsuite, Paul Murphy's recent work should make it much 
easier to run the glibc libm-test with libquadmath than it was when 
libquadmath was first added.)
Segher Boessenkool June 23, 2016, 11:49 p.m. UTC | #4
Hi Bill,

Some little things about the patch...

On Thu, Jun 23, 2016 at 04:44:27PM -0500, Bill Schmidt wrote:
> We no longer have a half-clever implementation to construct an infinity
> inside vector registers, or the full-clever one that Segher proposed in
> response. :)  We can try to add that support later if desired.

For posterity:

Use   vspltisw A,N ; vsrw B,A,A ; vslo D,B,A   to create in D:
N=-16  ffff_0000_0000_0000_0000_0000_0000_0000  (ieee128 -Inf)
N=-17  7fff_0000_0000_0000_0000_0000_0000_0000  (ieee128 +Inf)

> @@ -35569,6 +35639,7 @@ static struct rs6000_opt_mask const rs6000_builtin
>    { "hard-dfp",		 RS6000_BTM_DFP,	false, false },
>    { "hard-float",	 RS6000_BTM_HARD_FLOAT,	false, false },
>    { "long-double-128",	 RS6000_BTM_LDBL128,	false, false },
> +  { "float128",          RS6000_BTM_FLOAT128,   false, false },

The previous entries use tabs for indentation.

> --- gcc/config/rs6000/rs6000.h	(revision 237619)
> +++ gcc/config/rs6000/rs6000.h	(working copy)
> @@ -2689,6 +2689,7 @@ extern int frame_pointer_needed;
>  #define RS6000_BTM_HARD_FLOAT	MASK_SOFT_FLOAT	/* Hardware floating point.  */
>  #define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit long double.  */
>  #define RS6000_BTM_64BIT	MASK_64BIT	/* 64-bit addressing.  */
> +#define RS6000_BTM_FLOAT128     MASK_P9_VECTOR  /* IEEE 128-bit float.  */

Here, too.

> @@ -2705,7 +2706,8 @@ extern int frame_pointer_needed;
>  				 | RS6000_BTM_CELL			\
>  				 | RS6000_BTM_DFP			\
>  				 | RS6000_BTM_HARD_FLOAT		\
> -				 | RS6000_BTM_LDBL128)
> +				 | RS6000_BTM_LDBL128                   \
> +				 | RS6000_BTM_FLOAT128)

And here.  And more later.  Let's try to stick to one style, at least
locally.

> --- gcc/config/rs6000/rs6000.md	(revision 237619)
> +++ gcc/config/rs6000/rs6000.md	(working copy)
> @@ -13326,7 +13326,25 @@
>     "xssqrtqp %0,%1"
>    [(set_attr "type" "vecdiv")])
>  
> -(define_insn "copysign<mode>3"
> +(define_expand "copysign<mode>3"
> +  [(use (match_operand:IEEE128 0 "altivec_register_operand" ""))
> +   (use (match_operand:IEEE128 1 "altivec_register_operand" ""))
> +   (use (match_operand:IEEE128 2 "altivec_register_operand" ""))]

The "" is not needed.

> +  "FLOAT128_IEEE_P (<MODE>mode)"
> +{
> +  if (TARGET_FLOAT128_HW)
> +    emit_insn (gen_copysign<mode>3_hard (operands[0], operands[1],
> +    	                                 operands[2]));

Tabbing here...

> +  else
> +    {
> +      rtx tmp = gen_reg_rtx (<MODE>mode);
> +      emit_insn (gen_copysign<mode>3_soft (operands[0], operands[1],
> +      		                           operands[2], tmp));

... and here is completely broken.

> @@ -13336,6 +13354,18 @@
>     "xscpsgnqp %0,%2,%1"
>    [(set_attr "type" "vecsimple")])
>  
> +(define_insn "copysign<mode>3_soft"
> +  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
> +	(unspec:IEEE128
> +	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
> +	  (match_operand:IEEE128 2 "altivec_register_operand" "v")
> +	  (match_operand:IEEE128 3 "altivec_register_operand" "+v")]
> +	 UNSPEC_COPYSIGN))]
> +  "!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
> +   "xscpsgndp %x3,%x2,%x1\n\txxpermdi %x0,%x3,%x1,1"

Two machine insns in a template should be separated by \; not \n\t .

> +Additional built-in functions are available for the 64-bit PowerPC
> +family of processors, for efficient use of 128-bit floating point
> +(@code{__float128}) values.
> +
> +The following floating-point built-in functions are always available.  All
> +of them implement the function that is part of the name.

"Always"?  Not just with -mfloat128?  And it needs VMX?


Segher
Bill Schmidt June 24, 2016, 12:33 a.m. UTC | #5
Thanks, I'll make these changes and re-spin.  Not sure what was up
with my tabs...

> On Jun 23, 2016, at 6:49 PM, Segher Boessenkool <segher@kernel.crashing.org> wrote:
> 
> Hi Bill,
> 
> Some little things about the patch...
> 
> On Thu, Jun 23, 2016 at 04:44:27PM -0500, Bill Schmidt wrote:
>> We no longer have a half-clever implementation to construct an infinity
>> inside vector registers, or the full-clever one that Segher proposed in
>> response. :)  We can try to add that support later if desired.
> 
> For posterity:
> 
> Use   vspltisw A,N ; vsrw B,A,A ; vslo D,B,A   to create in D:
> N=-16  ffff_0000_0000_0000_0000_0000_0000_0000  (ieee128 -Inf)
> N=-17  7fff_0000_0000_0000_0000_0000_0000_0000  (ieee128 +Inf)

For the latter, it was N=-15 IIRC?  Anyway -17 is an illegal value for vspltisw.

> 
>> @@ -35569,6 +35639,7 @@ static struct rs6000_opt_mask const rs6000_builtin
>>   { "hard-dfp",		 RS6000_BTM_DFP,	false, false },
>>   { "hard-float",	 RS6000_BTM_HARD_FLOAT,	false, false },
>>   { "long-double-128",	 RS6000_BTM_LDBL128,	false, false },
>> +  { "float128",          RS6000_BTM_FLOAT128,   false, false },
> 
> The previous entries use tabs for indentation.
> 
>> --- gcc/config/rs6000/rs6000.h	(revision 237619)
>> +++ gcc/config/rs6000/rs6000.h	(working copy)
>> @@ -2689,6 +2689,7 @@ extern int frame_pointer_needed;
>> #define RS6000_BTM_HARD_FLOAT	MASK_SOFT_FLOAT	/* Hardware floating point.  */
>> #define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit long double.  */
>> #define RS6000_BTM_64BIT	MASK_64BIT	/* 64-bit addressing.  */
>> +#define RS6000_BTM_FLOAT128     MASK_P9_VECTOR  /* IEEE 128-bit float.  */
> 
> Here, too.
> 
>> @@ -2705,7 +2706,8 @@ extern int frame_pointer_needed;
>> 				 | RS6000_BTM_CELL			\
>> 				 | RS6000_BTM_DFP			\
>> 				 | RS6000_BTM_HARD_FLOAT		\
>> -				 | RS6000_BTM_LDBL128)
>> +				 | RS6000_BTM_LDBL128                   \
>> +				 | RS6000_BTM_FLOAT128)
> 
> And here.  And more later.  Let's try to stick to one style, at least
> locally.
> 
>> --- gcc/config/rs6000/rs6000.md	(revision 237619)
>> +++ gcc/config/rs6000/rs6000.md	(working copy)
>> @@ -13326,7 +13326,25 @@
>>    "xssqrtqp %0,%1"
>>   [(set_attr "type" "vecdiv")])
>> 
>> -(define_insn "copysign<mode>3"
>> +(define_expand "copysign<mode>3"
>> +  [(use (match_operand:IEEE128 0 "altivec_register_operand" ""))
>> +   (use (match_operand:IEEE128 1 "altivec_register_operand" ""))
>> +   (use (match_operand:IEEE128 2 "altivec_register_operand" ""))]
> 
> The "" is not needed.
> 
>> +  "FLOAT128_IEEE_P (<MODE>mode)"
>> +{
>> +  if (TARGET_FLOAT128_HW)
>> +    emit_insn (gen_copysign<mode>3_hard (operands[0], operands[1],
>> +    	                                 operands[2]));
> 
> Tabbing here...
> 
>> +  else
>> +    {
>> +      rtx tmp = gen_reg_rtx (<MODE>mode);
>> +      emit_insn (gen_copysign<mode>3_soft (operands[0], operands[1],
>> +      		                           operands[2], tmp));
> 
> ... and here is completely broken.
> 
>> @@ -13336,6 +13354,18 @@
>>    "xscpsgnqp %0,%2,%1"
>>   [(set_attr "type" "vecsimple")])
>> 
>> +(define_insn "copysign<mode>3_soft"
>> +  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
>> +	(unspec:IEEE128
>> +	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
>> +	  (match_operand:IEEE128 2 "altivec_register_operand" "v")
>> +	  (match_operand:IEEE128 3 "altivec_register_operand" "+v")]
>> +	 UNSPEC_COPYSIGN))]
>> +  "!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
>> +   "xscpsgndp %x3,%x2,%x1\n\txxpermdi %x0,%x3,%x1,1"
> 
> Two machine insns in a template should be separated by \; not \n\t .
> 
>> +Additional built-in functions are available for the 64-bit PowerPC
>> +family of processors, for efficient use of 128-bit floating point
>> +(@code{__float128}) values.
>> +
>> +The following floating-point built-in functions are always available.  All
>> +of them implement the function that is part of the name.
> 
> "Always"?  Not just with -mfloat128?  And it needs VMX?

Sorry, pasto from the 386 docs.  I meant to change that, sorry.

Bill

> 
> 
> Segher
>
Bill Schmidt June 24, 2016, 2:19 a.m. UTC | #6
> 
> On Jun 23, 2016, at 5:41 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Thu, 23 Jun 2016, Bill Schmidt wrote:
> 
>> After discussing with the glibc folks, I'd like to propose that this patch
>> be altered to use the 'q' suffix for the builtin names.  That way we won't
>> have a naming conflict with Joseph's patch in the short term, and we'll
>> be able to stage the movement on trunk to the f128 support.
>> 
>> I've been informed that there are other packages/libraries that assume 
>> the 'q' suffix, so we will need both anyway.  For the time being, we can
>> use #defines for glibc using GCC 6 to define the f128 functions to be
>> the q functions.  We'll plan to normalize to use the arch-neutral f128
>> builtins after the 6.2 push completes.
> 
> Those #defines in glibc would be needed anyway for __float128 functions in 
> glibc for x86 to support GCC versions before GCC 7 (which x86 support I'm 
> minded to look at adding once the __float128 functions for powerpc64le are 
> in; adding them for a new architecture shouldn't be hard once the first 
> architecture is done).
> 
> The 'q' suffix should be considered legacy (just like the __float128 
> name!), but if it doesn't conflict with the generic support it's 
> essentially a target maintainer matter.  As I said in my patch submission 
> for the generic functions, I don't know if target built-in functions can 
> be made into aliases for generic ones, but that's what's desirable in 
> optimization terms once the generic ones are in, so that optimizations 
> apply equally to both.

Agreed!

> 
> (I'm presuming that eventually we *will* enable all built-in function and 
> other optimizations, that currently are just for float / double / long 
> double, for the new types and their corresponding TS 18661-3 functions as 
> well - that's just lower priority since it's not at all on the critical 
> path for enabling support for the new type, unlike this minimal set of 
> functions.)

Yes, that's the way we feel too -- it needs to happen, but further down the
road once we're out of this bottleneck.

> 
> Do those packages assuming 'q' expect more than the minimal built-in 
> functions (i.e., do they want libquadmath)?  I've noted before that while 
> libquadmath is not the way forward for libm support for __float128 (that's 
> *f128 functions in glibc), and while libquadmath is missing the past few 
> years' improvements to glibc libm, enabling it for powerpc64le (once 
> you've got built-in functions and complex arithmetic functions in libgcc) 
> would allow you to test that the back-end __float128 support works for a 
> substantial body of code with __float128 arithmetic....  (While there is 
> no libquadmath testsuite, Paul Murphy's recent work should make it much 
> easier to run the glibc libm-test with libquadmath than it was when 
> libquadmath was first added.)

Actually libquadmath is what I was thinking of -- there may be more, but
I'm not very tuned into this side of things.  Once we have the full set of
__float128 support in place, we should be able to do some of this kind
of testing.

Thanks!
Bill

> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com
>
Segher Boessenkool June 24, 2016, 8:05 p.m. UTC | #7
On Thu, Jun 23, 2016 at 07:33:34PM -0500, Bill Schmidt wrote:
> > For posterity:
> > 
> > Use   vspltisw A,N ; vsrw B,A,A ; vslo D,B,A   to create in D:
> > N=-16  ffff_0000_0000_0000_0000_0000_0000_0000  (ieee128 -Inf)
> > N=-17  7fff_0000_0000_0000_0000_0000_0000_0000  (ieee128 +Inf)
> 
> For the latter, it was N=-15 IIRC?  Anyway -17 is an illegal value for vspltisw.

Yes, of course.  Three insns is too much asm to do correctly!  :-)


Segher
diff mbox

Patch

Index: gcc/config/rs6000/rs6000-builtin.def
===================================================================
--- gcc/config/rs6000/rs6000-builtin.def	(revision 237619)
+++ gcc/config/rs6000/rs6000-builtin.def	(working copy)
@@ -652,7 +652,23 @@ 
 		     | RS6000_BTC_BINARY),				\
 		    CODE_FOR_ ## ICODE)			/* ICODE */
 
+/* IEEE 128-bit floating-point builtins.  */
+#define BU_FLOAT128_2(ENUM, NAME, ATTR, ICODE)                          \
+  RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM,              /* ENUM */      \
+                    "__builtin_" NAME,                  /* NAME */      \
+		    RS6000_BTM_FLOAT128,                /* MASK */      \
+		    (RS6000_BTC_ ## ATTR                /* ATTR */      \
+		     | RS6000_BTC_BINARY),                              \
+		    CODE_FOR_ ## ICODE)                 /* ICODE */
 
+#define BU_FLOAT128_1(ENUM, NAME, ATTR, ICODE)                          \
+  RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM,              /* ENUM */      \
+                    "__builtin_" NAME,                  /* NAME */      \
+		    RS6000_BTM_FLOAT128,                /* MASK */      \
+		    (RS6000_BTC_ ## ATTR                /* ATTR */      \
+		     | RS6000_BTC_UNARY),                               \
+		    CODE_FOR_ ## ICODE)                 /* ICODE */
+
 /* Miscellaneous builtins for instructions added in ISA 3.0.  These
    instructions don't require either the DFP or VSX options, just the basic
    ISA 3.0 enablement since they operate on general purpose registers.  */
@@ -1814,6 +1830,11 @@  BU_P9V_OVERLOAD_1 (VPRTYBD,	"vprtybd")
 BU_P9V_OVERLOAD_1 (VPRTYBQ,	"vprtybq")
 BU_P9V_OVERLOAD_1 (VPRTYBW,	"vprtybw")
 
+/* 1 argument IEEE 128-bit floating-point functions.  */
+BU_FLOAT128_1 (FABSF128,	"fabsf128",       CONST, abskf2)
+
+/* 2 argument IEEE 128-bit floating-point functions.  */
+BU_FLOAT128_2 (COPYSIGNF128,	"copysignf128",   CONST, copysignkf3)
 
 /* 1 argument crypto functions.  */
 BU_CRYPTO_1 (VSBOX,		"vsbox",	  CONST, crypto_vsbox)
@@ -2191,6 +2212,18 @@  BU_SPECIAL_X (RS6000_BUILTIN_CPU_IS, "__builtin_cp
 BU_SPECIAL_X (RS6000_BUILTIN_CPU_SUPPORTS, "__builtin_cpu_supports",
 	      RS6000_BTM_ALWAYS, RS6000_BTC_MISC)
 
+BU_SPECIAL_X (RS6000_BUILTIN_NANF128, "__builtin_nanf128",
+	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
+
+BU_SPECIAL_X (RS6000_BUILTIN_NANSF128, "__builtin_nansf128",
+	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
+
+BU_SPECIAL_X (RS6000_BUILTIN_INFF128, "__builtin_inff128",
+	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
+
+BU_SPECIAL_X (RS6000_BUILTIN_HUGE_VALF128, "__builtin_huge_valf128",
+	      RS6000_BTM_FLOAT128, RS6000_BTC_CONST)
+
 /* Darwin CfString builtin.  */
 BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_ALWAYS,
 	      RS6000_BTC_MISC)
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 237619)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1328,6 +1328,7 @@  static bool rs6000_secondary_reload_move (enum rs6
 					  bool);
 rtl_opt_pass *make_pass_analyze_swaps (gcc::context*);
 static bool rs6000_keep_leaf_when_profiled () __attribute__ ((unused));
+static tree rs6000_fold_builtin (tree, int, tree *, bool);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -1602,6 +1603,9 @@  static const struct attribute_spec rs6000_attribut
 #undef TARGET_BUILTIN_DECL
 #define TARGET_BUILTIN_DECL rs6000_builtin_decl
 
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN rs6000_fold_builtin
+
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
 
@@ -3682,7 +3686,8 @@  rs6000_builtin_mask_calculate (void)
 	  | ((TARGET_HTM)		    ? RS6000_BTM_HTM	   : 0)
 	  | ((TARGET_DFP)		    ? RS6000_BTM_DFP	   : 0)
 	  | ((TARGET_HARD_FLOAT)	    ? RS6000_BTM_HARD_FLOAT : 0)
-	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128 : 0));
+	  | ((TARGET_LONG_DOUBLE_128)	    ? RS6000_BTM_LDBL128   : 0)
+	  | ((TARGET_FLOAT128)              ? RS6000_BTM_FLOAT128  : 0));
 }
 
 /* Implement TARGET_MD_ASM_ADJUST.  All asm statements are considered
@@ -15510,11 +15515,57 @@  rs6000_invalid_builtin (enum rs6000_builtins fncod
 	   " -mlong-double-128 options", name);
   else if ((fnmask & RS6000_BTM_HARD_FLOAT) != 0)
     error ("Builtin function %s requires the -mhard-float option", name);
+  else if ((fnmask & RS6000_BTM_FLOAT128) != 0)
+    error ("Builtin function %s requires the -mfloat128 option", name);
   else
     error ("Builtin function %s is not supported with the current options",
 	   name);
 }
 
+/* Target hook for early folding of built-ins, shamelessly stolen
+   from ia64.c.  */
+
+static tree
+rs6000_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
+		     tree *args, bool ignore ATTRIBUTE_UNUSED)
+{
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+    {
+      enum rs6000_builtins fn_code
+	= (enum rs6000_builtins) DECL_FUNCTION_CODE (fndecl);
+      switch (fn_code)
+	{
+	case RS6000_BUILTIN_NANF128:
+	case RS6000_BUILTIN_NANSF128:
+	  {
+	    tree type = TREE_TYPE (TREE_TYPE (fndecl));
+	    const char *str = c_getstr (*args);
+	    int quiet = fn_code == RS6000_BUILTIN_NANF128;
+	    REAL_VALUE_TYPE real;
+
+	    if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
+	      return build_real (type, real);
+	    return NULL_TREE;
+	  }
+	case RS6000_BUILTIN_INFF128:
+	case RS6000_BUILTIN_HUGE_VALF128:
+	  {
+	    tree type = TREE_TYPE (TREE_TYPE (fndecl));
+	    REAL_VALUE_TYPE inf;
+	    real_inf (&inf);
+	    return build_real (type, inf);
+	  }
+	default:
+	  break;
+	}
+    }
+#ifdef SUBTARGET_FOLD_BUILTIN
+  return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
+#else
+  return NULL_TREE;
+#endif
+}
+
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
    (and in mode MODE if that's convenient).
@@ -15769,6 +15820,10 @@  rs6000_init_builtins (void)
   opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
   opaque_V4SI_type_node = build_opaque_vector_type (intSI_type_node, 4);
 
+  const_str_type_node
+    = build_pointer_type (build_qualified_type (char_type_node,
+						TYPE_QUAL_CONST));
+
   /* We use V1TI mode as a special container to hold __int128_t items that
      must live in VSX registers.  */
   if (intTI_type_node)
@@ -15831,6 +15886,12 @@  rs6000_init_builtins (void)
       lang_hooks.types.register_builtin_type (ibm128_float_type_node,
 					      "__ibm128");
     }
+  else
+    {
+      /* All types must be nonzero, or self-test barfs during bootstrap.  */
+      ieee128_float_type_node = long_double_type_node;
+      ibm128_float_type_node = long_double_type_node;
+    }
 
   /* Initialize the modes for builtin_function_type, mapping a machine mode to
      tree type node.  */
@@ -15972,6 +16033,15 @@  rs6000_init_builtins (void)
   if (TARGET_EXTRA_BUILTINS || TARGET_SPE || TARGET_PAIRED_FLOAT)
     rs6000_common_init_builtins ();
 
+  ftype = build_function_type_list (ieee128_float_type_node,
+				    const_str_type_node, NULL_TREE);
+  def_builtin ("__builtin_nanf128", ftype, RS6000_BUILTIN_NANF128);
+  def_builtin ("__builtin_nansf128", ftype, RS6000_BUILTIN_NANSF128);
+
+  ftype = build_function_type_list (ieee128_float_type_node, NULL_TREE);
+  def_builtin ("__builtin_inff128", ftype, RS6000_BUILTIN_INFF128);
+  def_builtin ("__builtin_huge_valf128", ftype, RS6000_BUILTIN_HUGE_VALF128);
+
   ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode,
 				 RS6000_BUILTIN_RECIP, "__builtin_recipdiv");
   def_builtin ("__builtin_recipdiv", ftype, RS6000_BUILTIN_RECIP);
@@ -35569,6 +35639,7 @@  static struct rs6000_opt_mask const rs6000_builtin
   { "hard-dfp",		 RS6000_BTM_DFP,	false, false },
   { "hard-float",	 RS6000_BTM_HARD_FLOAT,	false, false },
   { "long-double-128",	 RS6000_BTM_LDBL128,	false, false },
+  { "float128",          RS6000_BTM_FLOAT128,   false, false },
 };
 
 /* Option variables that we want to support inside attribute((target)) and
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 237619)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -2689,6 +2689,7 @@  extern int frame_pointer_needed;
 #define RS6000_BTM_HARD_FLOAT	MASK_SOFT_FLOAT	/* Hardware floating point.  */
 #define RS6000_BTM_LDBL128	MASK_MULTIPLE	/* 128-bit long double.  */
 #define RS6000_BTM_64BIT	MASK_64BIT	/* 64-bit addressing.  */
+#define RS6000_BTM_FLOAT128     MASK_P9_VECTOR  /* IEEE 128-bit float.  */
 
 #define RS6000_BTM_COMMON	(RS6000_BTM_ALTIVEC			\
 				 | RS6000_BTM_VSX			\
@@ -2705,7 +2706,8 @@  extern int frame_pointer_needed;
 				 | RS6000_BTM_CELL			\
 				 | RS6000_BTM_DFP			\
 				 | RS6000_BTM_HARD_FLOAT		\
-				 | RS6000_BTM_LDBL128)
+				 | RS6000_BTM_LDBL128                   \
+				 | RS6000_BTM_FLOAT128)
 
 /* Define builtin enum index.  */
 
@@ -2809,6 +2811,7 @@  enum rs6000_builtin_type_index
   RS6000_BTI_void,	         /* void_type_node */
   RS6000_BTI_ieee128_float,	 /* ieee 128-bit floating point */
   RS6000_BTI_ibm128_float,	 /* IBM 128-bit floating point */
+  RS6000_BTI_const_str,          /* pointer to const char * */
   RS6000_BTI_MAX
 };
 
@@ -2865,6 +2868,7 @@  enum rs6000_builtin_type_index
 #define void_type_internal_node		 (rs6000_builtin_types[RS6000_BTI_void])
 #define ieee128_float_type_node		 (rs6000_builtin_types[RS6000_BTI_ieee128_float])
 #define ibm128_float_type_node		 (rs6000_builtin_types[RS6000_BTI_ibm128_float])
+#define const_str_type_node	         (rs6000_builtin_types[RS6000_BTI_const_str])
 
 extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX];
 extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 237619)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -13326,7 +13326,25 @@ 
    "xssqrtqp %0,%1"
   [(set_attr "type" "vecdiv")])
 
-(define_insn "copysign<mode>3"
+(define_expand "copysign<mode>3"
+  [(use (match_operand:IEEE128 0 "altivec_register_operand" ""))
+   (use (match_operand:IEEE128 1 "altivec_register_operand" ""))
+   (use (match_operand:IEEE128 2 "altivec_register_operand" ""))]
+  "FLOAT128_IEEE_P (<MODE>mode)"
+{
+  if (TARGET_FLOAT128_HW)
+    emit_insn (gen_copysign<mode>3_hard (operands[0], operands[1],
+    	                                 operands[2]));
+  else
+    {
+      rtx tmp = gen_reg_rtx (<MODE>mode);
+      emit_insn (gen_copysign<mode>3_soft (operands[0], operands[1],
+      		                           operands[2], tmp));
+    }
+  DONE;
+})
+
+(define_insn "copysign<mode>3_hard"
   [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
 	(unspec:IEEE128
 	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
@@ -13336,6 +13354,18 @@ 
    "xscpsgnqp %0,%2,%1"
   [(set_attr "type" "vecsimple")])
 
+(define_insn "copysign<mode>3_soft"
+  [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+	(unspec:IEEE128
+	 [(match_operand:IEEE128 1 "altivec_register_operand" "v")
+	  (match_operand:IEEE128 2 "altivec_register_operand" "v")
+	  (match_operand:IEEE128 3 "altivec_register_operand" "+v")]
+	 UNSPEC_COPYSIGN))]
+  "!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+   "xscpsgndp %x3,%x2,%x1\n\txxpermdi %x0,%x3,%x1,1"
+  [(set_attr "type" "veccomplex")
+   (set_attr "length" "8")])
+
 (define_insn "neg<mode>2_hw"
   [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
 	(neg:IEEE128
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 237619)
+++ gcc/doc/extend.texi	(working copy)
@@ -14781,6 +14781,38 @@  The @code{__builtin_ppc_mftb} function always gene
 returns the Time Base Register value as an unsigned long, throwing away
 the most significant word on 32-bit environments.
 
+Additional built-in functions are available for the 64-bit PowerPC
+family of processors, for efficient use of 128-bit floating point
+(@code{__float128}) values.
+
+The following floating-point built-in functions are always available.  All
+of them implement the function that is part of the name.
+
+@smallexample
+__float128 __builtin_fabsf128 (__float128)
+__float128 __builtin_copysignf128 (__float128, __float128)
+@end smallexample
+
+The following built-in functions are always available.
+
+@table @code
+@item __float128 __builtin_inff128 (void)
+Similar to @code{__builtin_inf}, except the return type is @code{__float128}.
+@findex __builtin_inff128
+
+@item __float128 __builtin_huge_valf128 (void)
+Similar to @code{__builtin_huge_val}, except the return type is @code{__float128}.
+@findex __builtin_huge_valf128
+
+@item __float128 __builtin_nanf128 (void)
+Similar to @code{__builtin_nan}, except the return type is @code{__float128}.
+@findex __builtin_nanf128
+
+@item __float128 __builtin_nansf128 (void)
+Similar to @code{__builtin_nans}, except the return type is @code{__float128}.
+@findex __builtin_nansf128
+@end table
+
 The following built-in functions are available for the PowerPC family
 of processors, starting with ISA 2.06 or later (@option{-mcpu=power7}
 or @option{-mpopcntd}):
Index: gcc/testsuite/gcc.target/powerpc/abs128-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/abs128-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/abs128-1.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
+/* { dg-options "-mfloat128" } */
+
+void abort ();
+
+typedef unsigned long long int uint64_t;
+
+typedef union
+{
+  __float128 value;
+
+  struct
+  {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    unsigned negative:1;
+    unsigned exponent:15;
+    unsigned quiet_nan:1;
+    uint64_t mant_high:47;
+    uint64_t mant_low:64;
+#else
+    uint64_t mant_low:64;
+    uint64_t mant_high:47;
+    unsigned quiet_nan:1;
+    unsigned exponent:15;
+    unsigned negative:1;
+#endif
+  } nan;
+
+} ieee854_float128;
+
+int
+main (int argc, int *argv[])
+{
+  ieee854_float128 x, z;
+
+  x.nan.negative = 1;
+  x.nan.exponent = 0x22;
+  x.nan.quiet_nan = 0;
+  x.nan.mant_high = 0x1234;
+  x.nan.mant_low = 0xabcdef;
+
+  z.value = __builtin_fabsf128 (x.value);
+
+  if (z.nan.negative != 0
+      || z.nan.exponent != 0x22
+      || z.nan.quiet_nan != 0
+      || z.nan.mant_high != 0x1234
+      || z.nan.mant_low != 0xabcdef)
+    abort ();
+
+  z.value = __builtin_fabsf128 (z.value);
+
+  if (z.nan.negative != 0
+      || z.nan.exponent != 0x22
+      || z.nan.quiet_nan != 0
+      || z.nan.mant_high != 0x1234
+      || z.nan.mant_low != 0xabcdef)
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/powerpc/copysign128-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/copysign128-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/copysign128-1.c	(working copy)
@@ -0,0 +1,58 @@ 
+/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
+/* { dg-options "-mfloat128" } */
+
+void abort ();
+
+typedef unsigned long long int uint64_t;
+
+typedef union
+{
+  __float128 value;
+
+  struct
+  {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    unsigned negative:1;
+    unsigned exponent:15;
+    unsigned quiet_nan:1;
+    uint64_t mant_high:47;
+    uint64_t mant_low:64;
+#else
+    uint64_t mant_low:64;
+    uint64_t mant_high:47;
+    unsigned quiet_nan:1;
+    unsigned exponent:15;
+    unsigned negative:1;
+#endif
+  } nan;
+
+} ieee854_float128;
+
+int
+main (int argc, int *argv[])
+{
+  ieee854_float128 x, y, z;
+
+  x.nan.negative = 0;
+  x.nan.exponent = 0x22;
+  x.nan.quiet_nan = 0;
+  x.nan.mant_high = 0x1234;
+  x.nan.mant_low = 0xabcdef;
+
+  y.nan.negative = 1;
+  y.nan.exponent = 0;
+  y.nan.quiet_nan = 0;
+  y.nan.mant_high = 0;
+  y.nan.mant_low = 0;
+
+  z.value = __builtin_copysignf128 (x.value, y.value);
+
+  if (z.nan.negative != 1
+      || z.nan.exponent != 0x22
+      || z.nan.quiet_nan != 0
+      || z.nan.mant_high != 0x1234
+      || z.nan.mant_low != 0xabcdef)
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/powerpc/inf128-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/inf128-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/inf128-1.c	(working copy)
@@ -0,0 +1,55 @@ 
+/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
+/* { dg-options "-mfloat128" } */
+
+void abort ();
+
+typedef unsigned long long int uint64_t;
+
+typedef union
+{
+  __float128 value;
+
+  struct
+  {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    unsigned negative:1;
+    unsigned exponent:15;
+    unsigned quiet_nan:1;
+    uint64_t mant_high:47;
+    uint64_t mant_low:64;
+#else
+    uint64_t mant_low:64;
+    uint64_t mant_high:47;
+    unsigned quiet_nan:1;
+    unsigned exponent:15;
+    unsigned negative:1;
+#endif
+  } nan;
+
+} ieee854_float128;
+
+int
+main (int argc, int *argv[])
+{
+  ieee854_float128 y;
+
+  y.value = __builtin_inff128 ();
+
+  if (y.nan.negative != 0
+      || y.nan.exponent != 0x7fff
+      || y.nan.quiet_nan != 0
+      || y.nan.mant_high != 0
+      || y.nan.mant_low != 0)
+    abort ();
+
+  y.value = __builtin_huge_valf128 ();
+
+  if (y.nan.negative != 0
+      || y.nan.exponent != 0x7fff
+      || y.nan.quiet_nan != 0
+      || y.nan.mant_high != 0
+      || y.nan.mant_low != 0)
+    abort ();
+
+  return 0;
+}
Index: gcc/testsuite/gcc.target/powerpc/nan128-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/nan128-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/nan128-1.c	(working copy)
@@ -0,0 +1,77 @@ 
+/* { dg-do run { target { powerpc64*-*-* && vmx_hw } } } */
+/* { dg-options "-mfloat128" } */
+
+#include <stdio.h>
+
+void abort ();
+
+typedef unsigned long long int uint64_t;
+
+typedef union
+{
+  __float128 value;
+
+  struct
+  {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    unsigned negative:1;
+    unsigned exponent:15;
+    unsigned quiet_nan:1;
+    uint64_t mant_high:47;
+    uint64_t mant_low:64;
+#else
+    uint64_t mant_low:64;
+    uint64_t mant_high:47;
+    unsigned quiet_nan:1;
+    unsigned exponent:15;
+    unsigned negative:1;
+#endif
+  } nan;
+
+} ieee854_float128;
+
+int
+main (int argc, int *argv[])
+{
+  ieee854_float128 y;
+
+  y.value = __builtin_nanf128 ("1");
+
+  if (y.nan.negative != 0
+      || y.nan.exponent != 0x7fff
+      || y.nan.quiet_nan != 1
+      || y.nan.mant_high != 0
+      || y.nan.mant_low != 1)
+    abort ();
+
+  y.value = __builtin_nanf128 ("0x2ab3c");
+
+  if (y.nan.negative != 0
+      || y.nan.exponent != 0x7fff
+      || y.nan.quiet_nan != 1
+      || y.nan.mant_high != 0
+      || y.nan.mant_low != 0x2ab3c)
+    abort ();
+
+  y.value = __builtin_nansf128 ("1");
+
+  if (
+      y.nan.negative != 0
+      || y.nan.exponent != 0x7fff
+      || y.nan.quiet_nan != 0
+      || y.nan.mant_high != 0
+      || y.nan.mant_low != 1
+      )
+    abort ();
+
+  y.value = __builtin_nansf128 ("0x2ab3c");
+
+  if (y.nan.negative != 0
+      || y.nan.exponent != 0x7fff
+      || y.nan.quiet_nan != 0
+      || y.nan.mant_high != 0
+      || y.nan.mant_low != 0x2ab3c)
+    abort ();
+
+  return 0;
+}