public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-5965] rs6000: Remove new_builtins_are_live and dead code it was guarding
@ 2021-12-14 17:23 William Schmidt
  0 siblings, 0 replies; only message in thread
From: William Schmidt @ 2021-12-14 17:23 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:2cf62ef5aa80e3659a8150a48d93a1d333f1d292

commit r12-5965-g2cf62ef5aa80e3659a8150a48d93a1d333f1d292
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date:   Tue Dec 14 11:23:32 2021 -0600

    rs6000: Remove new_builtins_are_live and dead code it was guarding
    
    To allow for a sane switch-over from the old built-in infrastructure to the
    new, both sets of code have co-existed, with the enabled one under the control
    of the boolean variable new_builtins_are_live.  As a first step in removing the
    old code, remove this variable and the now-dead code it was guarding.
    
    2021-12-06  Bill Schmidt  <wschmidt@linux.ibm.com>
    
    gcc/
            * config/rs6000/darwin.h (SUBTARGET_INIT_BUILTINS): Remove
            test for new_builtins_are_live and simplify.
            * config/rs6000/rs6000-c.c (altivec_build_resolved_builtin): Remove
            dead function.
            (altivec_resolve_overloaded_builtin): Remove test for
            new_builtins_are_live and simplify.
            * config/rs6000/rs6000-call.c (altivec_init_builtins): Remove forward
            declaration.
            (builtin_function_type): Likewise.
            (rs6000_common_init_builtins): Likewise.
            (htm_init_builtins): Likewise.
            (mma_init_builtins): Likewise.
            (def_builtin): Remove dead function.
            (rs6000_expand_zeroop_builtin): Likewise.
            (rs6000_expand_mtfsf_builtin): Likewise.
            (rs6000_expand_mtfsb_builtin): Likewise.
            (rs6000_expand_set_fpscr_rn_builtin): Likewise.
            (rs6000_expand_set_fpscr_drn_builtin): Likewise.
            (rs6000_expand_unop_builtin): Likewise.
            (altivec_expand_abs_builtin): Likewise.
            (rs6000_expand_binop_builtin): Likewise.
            (altivec_expand_lxvr_builtin): Likewise.
            (altivec_expand_lv_builtin): Likewise.
            (altivec_expand_stxvl_builtin): Likewise.
            (altivec_expand_stv_builtin): Likewise.
            (mma_expand_builtin): Likewise.
            (htm_expand_builtin): Likewise.
            (cpu_expand_builtin): Likewise.
            (rs6000_expand_quaternop_builtin): Likewise.
            (rs6000_expand_ternop_builtin): Likewise.
            (altivec_expand_dst_builtin): Likewise.
            (altivec_expand_vec_sel_builtin): Likewise.
            (altivec_expand_builtin): Likewise.
            (rs6000_invalid_builtin): Likewise.
            (rs6000_builtin_valid_without_lhs): Likewise.
            (rs6000_gimple_fold_builtin): Remove test for new_builtins_are_live and
            simplify.
            (rs6000_expand_builtin): Likewise.
            (rs6000_init_builtins): Remove tests for new_builtins_are_live and
            simplify.
            (rs6000_builtin_decl): Likewise.
            (altivec_init_builtins): Remove dead function.
            (mma_init_builtins): Likewise.
            (htm_init_builtins): Likewise.
            (builtin_quaternary_function_type): Likewise.
            (builtin_function_type): Likewise.
            (rs6000_common_init_builtins): Likewise.
            * config/rs6000/rs6000-gen-builtins.c (write_header_file): Don't
            declare new_builtins_are_live.
            (write_init_bif_table): In generated code, remove test for
            new_builtins_are_live and simplify.
            (write_init_ovld_table): Likewise.
            (write_init_file): Don't initialize new_builtins_are_live.
            * config/rs6000/rs6000.c (rs6000_builtin_vectorized_function): Remove
            test for new_builtins_are_live and simplify.
            (rs6000_builtin_md_vectorized_function): Likewise.
            (rs6000_builtin_reciprocal): Likewise.
            (add_condition_to_bb): Likewise.
            (rs6000_atomic_assign_expand_fenv): Likewise.

Diff:
---
 gcc/config/rs6000/darwin.h              |     8 +-
 gcc/config/rs6000/rs6000-c.c            |  1084 +--
 gcc/config/rs6000/rs6000-call.c         | 11523 ++++++++----------------------
 gcc/config/rs6000/rs6000-gen-builtins.c |    87 +-
 gcc/config/rs6000/rs6000.c              |   256 +-
 5 files changed, 3208 insertions(+), 9750 deletions(-)

diff --git a/gcc/config/rs6000/darwin.h b/gcc/config/rs6000/darwin.h
index 120b01f9a2b..7bc1009a523 100644
--- a/gcc/config/rs6000/darwin.h
+++ b/gcc/config/rs6000/darwin.h
@@ -507,12 +507,8 @@
 #define SUBTARGET_INIT_BUILTINS						\
 do {									\
   darwin_patch_builtins ();						\
-  if (new_builtins_are_live)						\
-    rs6000_builtin_decls_x[(unsigned) (RS6000_BIF_CFSTRING)]		\
-      = darwin_init_cfstring_builtins ((unsigned) (RS6000_BIF_CFSTRING)); \
-  else									\
-    rs6000_builtin_decls[(unsigned) (RS6000_BUILTIN_CFSTRING)]		\
-      = darwin_init_cfstring_builtins ((unsigned) (RS6000_BUILTIN_CFSTRING)); \
+  rs6000_builtin_decls_x[(unsigned) (RS6000_BIF_CFSTRING)]		\
+    = darwin_init_cfstring_builtins ((unsigned) (RS6000_BIF_CFSTRING)); \
 } while(0)
 
 /* So far, there is no rs6000_fold_builtin, if one is introduced, then
diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index 8e83d97e72f..d44edf585aa 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -873,82 +873,6 @@ fully_fold_convert (tree type, tree expr)
   return result;
 }
 
-/* Build a tree for a function call to an Altivec non-overloaded builtin.
-   The overloaded builtin that matched the types and args is described
-   by DESC.  The N arguments are given in ARGS, respectively.  
-
-   Actually the only thing it does is calling fold_convert on ARGS, with
-   a small exception for vec_{all,any}_{ge,le} predicates. */
-
-static tree
-altivec_build_resolved_builtin (tree *args, int n,
-				const struct altivec_builtin_types *desc)
-{
-  tree impl_fndecl = rs6000_builtin_decls[desc->overloaded_code];
-  tree ret_type = rs6000_builtin_type (desc->ret_type);
-  tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (impl_fndecl));
-  tree arg_type[4];
-  tree call;
-
-  int i;
-  for (i = 0; i < n; i++)
-    arg_type[i] = TREE_VALUE (argtypes), argtypes = TREE_CHAIN (argtypes);
-
-  /* The AltiVec overloading implementation is overall gross, but this
-     is particularly disgusting.  The vec_{all,any}_{ge,le} builtins
-     are completely different for floating-point vs. integer vector
-     types, because the former has vcmpgefp, but the latter should use
-     vcmpgtXX.
-
-     In practice, the second and third arguments are swapped, and the
-     condition (LT vs. EQ, which is recognizable by bit 1 of the first
-     argument) is reversed.  Patch the arguments here before building
-     the resolved CALL_EXPR.  */
-  if (n == 3
-      && desc->code == ALTIVEC_BUILTIN_VEC_VCMPGE_P
-      && desc->overloaded_code != ALTIVEC_BUILTIN_VCMPGEFP_P
-      && desc->overloaded_code != VSX_BUILTIN_XVCMPGEDP_P)
-    {
-      std::swap (args[1], args[2]);
-      std::swap (arg_type[1], arg_type[2]);
-
-      args[0] = fold_build2 (BIT_XOR_EXPR, TREE_TYPE (args[0]), args[0],
-			     build_int_cst (NULL_TREE, 2));
-    }
-
-  switch (n)
-    {
-    case 0:
-      call = build_call_expr (impl_fndecl, 0);
-      break;
-    case 1:
-      call = build_call_expr (impl_fndecl, 1,
-			      fully_fold_convert (arg_type[0], args[0]));
-      break;
-    case 2:
-      call = build_call_expr (impl_fndecl, 2,
-			      fully_fold_convert (arg_type[0], args[0]),
-			      fully_fold_convert (arg_type[1], args[1]));
-      break;
-    case 3:
-      call = build_call_expr (impl_fndecl, 3,
-			      fully_fold_convert (arg_type[0], args[0]),
-			      fully_fold_convert (arg_type[1], args[1]),
-			      fully_fold_convert (arg_type[2], args[2]));
-      break;
-    case 4:
-      call = build_call_expr (impl_fndecl, 4,
-			      fully_fold_convert (arg_type[0], args[0]),
-			      fully_fold_convert (arg_type[1], args[1]),
-			      fully_fold_convert (arg_type[2], args[2]),
-			      fully_fold_convert (arg_type[3], args[3]));
-      break;
-    default:
-      gcc_unreachable ();
-    }
-  return fold_convert (ret_type, call);
-}
-
 /* Implementation of the resolve_overloaded_builtin target hook, to
    support Altivec's overloaded builtins.  */
 
@@ -956,1013 +880,7 @@ tree
 altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
 				    void *passed_arglist)
 {
-  if (new_builtins_are_live)
-    return altivec_resolve_new_overloaded_builtin (loc, fndecl,
-						   passed_arglist);
-
-  vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist);
-  unsigned int nargs = vec_safe_length (arglist);
-  enum rs6000_builtins fcode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  tree fnargs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-  tree types[4], args[4];
-  const struct altivec_builtin_types *desc;
-  unsigned int n;
-
-  if (!rs6000_overloaded_builtin_p (fcode))
-    return NULL_TREE;
-
-  if (TARGET_DEBUG_BUILTIN)
-    fprintf (stderr, "altivec_resolve_overloaded_builtin, code = %4d, %s\n",
-	     (int)fcode, IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- 
-  /* vec_lvsl and vec_lvsr are deprecated for use with LE element order.  */
-  if (fcode == ALTIVEC_BUILTIN_VEC_LVSL && !BYTES_BIG_ENDIAN)
-    warning (OPT_Wdeprecated,
-	     "%<vec_lvsl%> is deprecated for little endian; use "
-	     "assignment for unaligned loads and stores");
-  else if (fcode == ALTIVEC_BUILTIN_VEC_LVSR && !BYTES_BIG_ENDIAN)
-    warning (OPT_Wdeprecated,
-	     "%<vec_lvsr%> is deprecated for little endian; use "
-	     "assignment for unaligned loads and stores");
-
-  if (fcode == ALTIVEC_BUILTIN_VEC_MUL)
-    {
-      /* vec_mul needs to be special cased because there are no instructions
-	 for it for the {un}signed char, {un}signed short, and {un}signed int
-	 types.  */
-      if (nargs != 2)
-	{
-	  error ("builtin %qs only accepts 2 arguments", "vec_mul");
-	  return error_mark_node;
-	}
-
-      tree arg0 = (*arglist)[0];
-      tree arg0_type = TREE_TYPE (arg0);
-      tree arg1 = (*arglist)[1];
-      tree arg1_type = TREE_TYPE (arg1);
-
-      /* Both arguments must be vectors and the types must be compatible.  */
-      if (TREE_CODE (arg0_type) != VECTOR_TYPE)
-	goto bad;
-      if (!lang_hooks.types_compatible_p (arg0_type, arg1_type))
-	goto bad;
-
-      switch (TYPE_MODE (TREE_TYPE (arg0_type)))
-	{
-	  case E_QImode:
-	  case E_HImode:
-	  case E_SImode:
-	  case E_DImode:
-	  case E_TImode:
-	    {
-	      /* For scalar types just use a multiply expression.  */
-	      return fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (arg0), arg0,
-				      fold_convert (TREE_TYPE (arg0), arg1));
-	    }
-	  case E_SFmode:
-	    {
-	      /* For floats use the xvmulsp instruction directly.  */
-	      tree call = rs6000_builtin_decls[VSX_BUILTIN_XVMULSP];
-	      return build_call_expr (call, 2, arg0, arg1);
-	    }
-	  case E_DFmode:
-	    {
-	      /* For doubles use the xvmuldp instruction directly.  */
-	      tree call = rs6000_builtin_decls[VSX_BUILTIN_XVMULDP];
-	      return build_call_expr (call, 2, arg0, arg1);
-	    }
-	  /* Other types are errors.  */
-	  default:
-	    goto bad;
-	}
-    }
-
-  if (fcode == ALTIVEC_BUILTIN_VEC_CMPNE)
-    {
-      /* vec_cmpne needs to be special cased because there are no instructions
-	 for it (prior to power 9).  */
-      if (nargs != 2)
-	{
-	  error ("builtin %qs only accepts 2 arguments", "vec_cmpne");
-	  return error_mark_node;
-	}
-
-      tree arg0 = (*arglist)[0];
-      tree arg0_type = TREE_TYPE (arg0);
-      tree arg1 = (*arglist)[1];
-      tree arg1_type = TREE_TYPE (arg1);
-
-      /* Both arguments must be vectors and the types must be compatible.  */
-      if (TREE_CODE (arg0_type) != VECTOR_TYPE)
-	goto bad;
-      if (!lang_hooks.types_compatible_p (arg0_type, arg1_type))
-	goto bad;
-
-      /* Power9 instructions provide the most efficient implementation of
-	 ALTIVEC_BUILTIN_VEC_CMPNE if the mode is not DImode or TImode
-	 or SFmode or DFmode.  */
-      if (!TARGET_P9_VECTOR
-	  || (TYPE_MODE (TREE_TYPE (arg0_type)) == DImode)
-	  || (TYPE_MODE (TREE_TYPE (arg0_type)) == TImode)
-	  || (TYPE_MODE (TREE_TYPE (arg0_type)) == SFmode)
-	  || (TYPE_MODE (TREE_TYPE (arg0_type)) == DFmode))
-	{
-	  switch (TYPE_MODE (TREE_TYPE (arg0_type)))
-	    {
-	      /* vec_cmpneq (va, vb) == vec_nor (vec_cmpeq (va, vb),
-		 vec_cmpeq (va, vb)).  */
-	      /* Note:  vec_nand also works but opt changes vec_nand's
-		 to vec_nor's anyway.  */
-	    case E_QImode:
-	    case E_HImode:
-	    case E_SImode:
-	    case E_DImode:
-	    case E_TImode:
-	    case E_SFmode:
-	    case E_DFmode:
-	      {
-		/* call = vec_cmpeq (va, vb)
-		   result = vec_nor (call, call).  */
-		vec<tree, va_gc> *params = make_tree_vector ();
-		vec_safe_push (params, arg0);
-		vec_safe_push (params, arg1);
-		tree call = altivec_resolve_overloaded_builtin
-		  (loc, rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_CMPEQ],
-		   params);
-		/* Use save_expr to ensure that operands used more than once
-		   that may have side effects (like calls) are only evaluated
-		   once.  */
-		call = save_expr (call);
-		params = make_tree_vector ();
-		vec_safe_push (params, call);
-		vec_safe_push (params, call);
-		return altivec_resolve_overloaded_builtin
-		  (loc, rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_NOR], params);
-	      }
-	      /* Other types are errors.  */
-	    default:
-	      goto bad;
-	    }
-	}
-      /* else, fall through and process the Power9 alternative below */
-    }
-
-  if (fcode == ALTIVEC_BUILTIN_VEC_ADDE
-      || fcode == ALTIVEC_BUILTIN_VEC_SUBE)
-    {
-      /* vec_adde needs to be special cased because there is no instruction
-	  for the {un}signed int version.  */
-      if (nargs != 3)
-	{
-	  const char *name = fcode == ALTIVEC_BUILTIN_VEC_ADDE ?
-	    "vec_adde": "vec_sube";
-	  error ("builtin %qs only accepts 3 arguments", name);
-	  return error_mark_node;
-	}
-
-      tree arg0 = (*arglist)[0];
-      tree arg0_type = TREE_TYPE (arg0);
-      tree arg1 = (*arglist)[1];
-      tree arg1_type = TREE_TYPE (arg1);
-      tree arg2 = (*arglist)[2];
-      tree arg2_type = TREE_TYPE (arg2);
-
-      /* All 3 arguments must be vectors of (signed or unsigned) (int or
-	 __int128) and the types must be compatible.  */
-      if (TREE_CODE (arg0_type) != VECTOR_TYPE)
-	goto bad;
-      if (!lang_hooks.types_compatible_p (arg0_type, arg1_type)
-	  || !lang_hooks.types_compatible_p (arg1_type, arg2_type))
-	goto bad;
-
-      switch (TYPE_MODE (TREE_TYPE (arg0_type)))
-	{
-	  /* For {un}signed ints,
-	     vec_adde (va, vb, carryv) == vec_add (vec_add (va, vb),
-						   vec_and (carryv, 1)).
-	     vec_sube (va, vb, carryv) == vec_sub (vec_sub (va, vb),
-						   vec_and (carryv, 1)).  */
-	  case E_SImode:
-	    {
-	      tree add_sub_builtin;
-
-	      vec<tree, va_gc> *params = make_tree_vector ();
-	      vec_safe_push (params, arg0);
-	      vec_safe_push (params, arg1);
-
-	      if (fcode == ALTIVEC_BUILTIN_VEC_ADDE)
-		add_sub_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADD];
-	      else
-		add_sub_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_SUB];
-
-	      tree call = altivec_resolve_overloaded_builtin (loc,
-							      add_sub_builtin,
-							      params);
-	      tree const1 = build_int_cstu (TREE_TYPE (arg0_type), 1);
-	      tree ones_vector = build_vector_from_val (arg0_type, const1);
-	      tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, arg0_type,
-					       arg2, ones_vector);
-	      params = make_tree_vector ();
-	      vec_safe_push (params, call);
-	      vec_safe_push (params, and_expr);
-	      return altivec_resolve_overloaded_builtin (loc, add_sub_builtin,
-							 params);
-	    }
-	  /* For {un}signed __int128s use the vaddeuqm instruction
-		directly.  */
-	  case E_TImode:
-	    {
-	       tree bii;
-
-	       if (fcode == ALTIVEC_BUILTIN_VEC_ADDE)
-		 bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VADDEUQM];
-
-	       else
-		 bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VSUBEUQM];
-
-	       return altivec_resolve_overloaded_builtin (loc, bii, arglist);
-	    }
-
-	  /* Types other than {un}signed int and {un}signed __int128
-		are errors.  */
-	  default:
-	    goto bad;
-	}
-    }
-
-  if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC
-      || fcode == ALTIVEC_BUILTIN_VEC_SUBEC)
-    {
-      /* vec_addec and vec_subec needs to be special cased because there is
-	 no instruction for the {un}signed int version.  */
-      if (nargs != 3)
-	{
-	  const char *name = fcode == ALTIVEC_BUILTIN_VEC_ADDEC ?
-	    "vec_addec": "vec_subec";
-	  error ("builtin %qs only accepts 3 arguments", name);
-	  return error_mark_node;
-	}
-
-      tree arg0 = (*arglist)[0];
-      tree arg0_type = TREE_TYPE (arg0);
-      tree arg1 = (*arglist)[1];
-      tree arg1_type = TREE_TYPE (arg1);
-      tree arg2 = (*arglist)[2];
-      tree arg2_type = TREE_TYPE (arg2);
-
-      /* All 3 arguments must be vectors of (signed or unsigned) (int or
-	 __int128) and the types must be compatible.  */
-      if (TREE_CODE (arg0_type) != VECTOR_TYPE)
-	goto bad;
-      if (!lang_hooks.types_compatible_p (arg0_type, arg1_type)
-	  || !lang_hooks.types_compatible_p (arg1_type, arg2_type))
-	goto bad;
-
-      switch (TYPE_MODE (TREE_TYPE (arg0_type)))
-	{
-	  /* For {un}signed ints,
-	      vec_addec (va, vb, carryv) ==
-				vec_or (vec_addc (va, vb),
-					vec_addc (vec_add (va, vb),
-						  vec_and (carryv, 0x1))).  */
-	  case E_SImode:
-	    {
-	    /* Use save_expr to ensure that operands used more than once
-		that may have side effects (like calls) are only evaluated
-		once.  */
-	    tree as_builtin;
-	    tree as_c_builtin;
-
-	    arg0 = save_expr (arg0);
-	    arg1 = save_expr (arg1);
-	    vec<tree, va_gc> *params = make_tree_vector ();
-	    vec_safe_push (params, arg0);
-	    vec_safe_push (params, arg1);
-
-	    if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC)
-	      as_c_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADDC];
-	    else
-	      as_c_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_SUBC];
-
-	    tree call1 = altivec_resolve_overloaded_builtin (loc, as_c_builtin,
-							     params);
-	    params = make_tree_vector ();
-	    vec_safe_push (params, arg0);
-	    vec_safe_push (params, arg1);
-
-
-	    if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC)
-	      as_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADD];
-	    else
-	      as_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_SUB];
-
-	    tree call2 = altivec_resolve_overloaded_builtin (loc, as_builtin,
-							     params);
-	    tree const1 = build_int_cstu (TREE_TYPE (arg0_type), 1);
-	    tree ones_vector = build_vector_from_val (arg0_type, const1);
-	    tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, arg0_type,
-					     arg2, ones_vector);
-	    params = make_tree_vector ();
-	    vec_safe_push (params, call2);
-	    vec_safe_push (params, and_expr);
-	    call2 = altivec_resolve_overloaded_builtin (loc, as_c_builtin,
-							params);
-	    params = make_tree_vector ();
-	    vec_safe_push (params, call1);
-	    vec_safe_push (params, call2);
-	    tree or_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_OR];
-	    return altivec_resolve_overloaded_builtin (loc, or_builtin,
-						       params);
-	    }
-	  /* For {un}signed __int128s use the vaddecuq/vsubbecuq
-	     instructions.  */
-	  case E_TImode:
-	    {
-	       tree bii;
-
-	       if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC)
-		 bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VADDECUQ];
-
-	       else
-		 bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VSUBECUQ];
-
-	       return altivec_resolve_overloaded_builtin (loc, bii, arglist);
-	    }
-	  /* Types other than {un}signed int and {un}signed __int128
-		are errors.  */
-	  default:
-	    goto bad;
-	}
-    }
-
-  /* For now treat vec_splats and vec_promote as the same.  */
-  if (fcode == ALTIVEC_BUILTIN_VEC_SPLATS
-      || fcode == ALTIVEC_BUILTIN_VEC_PROMOTE)
-    {
-      tree type, arg;
-      int size;
-      int i;
-      bool unsigned_p;
-      vec<constructor_elt, va_gc> *vec;
-      const char *name = fcode == ALTIVEC_BUILTIN_VEC_SPLATS ? "vec_splats": "vec_promote";
-
-      if (fcode == ALTIVEC_BUILTIN_VEC_SPLATS && nargs != 1)
-	{
-	  error ("builtin %qs only accepts 1 argument", name);
-	  return error_mark_node;
-	}
-      if (fcode == ALTIVEC_BUILTIN_VEC_PROMOTE && nargs != 2)
-	{
-	  error ("builtin %qs only accepts 2 arguments", name);
-	  return error_mark_node;
-	}
-      /* Ignore promote's element argument.  */
-      if (fcode == ALTIVEC_BUILTIN_VEC_PROMOTE
-	  && !INTEGRAL_TYPE_P (TREE_TYPE ((*arglist)[1])))
-	goto bad;
-
-      arg = (*arglist)[0];
-      type = TREE_TYPE (arg);
-      if (!SCALAR_FLOAT_TYPE_P (type)
-	  && !INTEGRAL_TYPE_P (type))
-	goto bad;
-      unsigned_p = TYPE_UNSIGNED (type);
-      switch (TYPE_MODE (type))
-	{
-	  case E_TImode:
-	    type = (unsigned_p ? unsigned_V1TI_type_node : V1TI_type_node);
-	    size = 1;
-	    break;
-	  case E_DImode:
-	    type = (unsigned_p ? unsigned_V2DI_type_node : V2DI_type_node);
-	    size = 2;
-	    break;
-	  case E_SImode:
-	    type = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
-	    size = 4;
-	    break;
-	  case E_HImode:
-	    type = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
-	    size = 8;
-	    break;
-	  case E_QImode:
-	    type = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
-	    size = 16;
-	    break;
-	  case E_SFmode: type = V4SF_type_node; size = 4; break;
-	  case E_DFmode: type = V2DF_type_node; size = 2; break;
-	  default:
-	    goto bad;
-	}
-      arg = save_expr (fold_convert (TREE_TYPE (type), arg));
-      vec_alloc (vec, size);
-      for(i = 0; i < size; i++)
-	{
-	  constructor_elt elt = {NULL_TREE, arg};
-	  vec->quick_push (elt);
-	}
-	return build_constructor (type, vec);
-    }
-
-  /* For now use pointer tricks to do the extraction, unless we are on VSX
-     extracting a double from a constant offset.  */
-  if (fcode == ALTIVEC_BUILTIN_VEC_EXTRACT)
-    {
-      tree arg1;
-      tree arg1_type;
-      tree arg2;
-      tree arg1_inner_type;
-      tree decl, stmt;
-      tree innerptrtype;
-      machine_mode mode;
-
-      /* No second argument. */
-      if (nargs != 2)
-	{
-	  error ("builtin %qs only accepts 2 arguments", "vec_extract");
-	  return error_mark_node;
-	}
-
-      arg2 = (*arglist)[1];
-      arg1 = (*arglist)[0];
-      arg1_type = TREE_TYPE (arg1);
-
-      if (TREE_CODE (arg1_type) != VECTOR_TYPE)
-	goto bad;
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
-	goto bad;
-
-      /* See if we can optimize vec_extracts with the current VSX instruction
-	 set.  */
-      mode = TYPE_MODE (arg1_type);
-      if (VECTOR_MEM_VSX_P (mode))
-
-	{
-	  tree call = NULL_TREE;
-	  int nunits = GET_MODE_NUNITS (mode);
-
-	  arg2 = fold_for_warn (arg2);
-
-	  /* If the second argument is an integer constant, generate
-	     the built-in code if we can.  We need 64-bit and direct
-	     move to extract the small integer vectors.  */
-	  if (TREE_CODE (arg2) == INTEGER_CST)
-	    {
-	      wide_int selector = wi::to_wide (arg2);
-	      selector = wi::umod_trunc (selector, nunits);
-	      arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector);
-	      switch (mode)
-		{
-		default:
-		  break;
-
-		case E_V1TImode:
-		  call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V1TI];
-		  break;
-
-		case E_V2DFmode:
-		  call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DF];
-		  break;
-
-		case E_V2DImode:
-		  call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DI];
-		  break;
-
-		case E_V4SFmode:
-		  call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SF];
-		  break;
-
-		case E_V4SImode:
-		  if (TARGET_DIRECT_MOVE_64BIT)
-		    call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SI];
-		  break;
-
-		case E_V8HImode:
-		  if (TARGET_DIRECT_MOVE_64BIT)
-		    call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V8HI];
-		  break;
-
-		case E_V16QImode:
-		  if (TARGET_DIRECT_MOVE_64BIT)
-		    call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V16QI];
-		  break;
-		}
-	    }
-
-	  /* If the second argument is variable, we can optimize it if we are
-	     generating 64-bit code on a machine with direct move.  */
-	  else if (TREE_CODE (arg2) != INTEGER_CST && TARGET_DIRECT_MOVE_64BIT)
-	    {
-	      switch (mode)
-		{
-		default:
-		  break;
-
-		case E_V2DFmode:
-		  call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DF];
-		  break;
-
-		case E_V2DImode:
-		  call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DI];
-		  break;
-
-		case E_V4SFmode:
-		  call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SF];
-		  break;
-
-		case E_V4SImode:
-		  call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SI];
-		  break;
-
-		case E_V8HImode:
-		  call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V8HI];
-		  break;
-
-		case E_V16QImode:
-		  call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V16QI];
-		  break;
-		}
-	    }
-
-	  if (call)
-	    {
-	      tree result = build_call_expr (call, 2, arg1, arg2);
-	      /* Coerce the result to vector element type.  May be no-op.  */
-	      arg1_inner_type = TREE_TYPE (arg1_type);
-	      result = fold_convert (arg1_inner_type, result);
-	      return result;
-	    }
-	}
-
-      /* Build *(((arg1_inner_type*)&(vector type){arg1})+arg2). */
-      arg1_inner_type = TREE_TYPE (arg1_type);
-      arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2,
-			      build_int_cst (TREE_TYPE (arg2),
-					     TYPE_VECTOR_SUBPARTS (arg1_type)
-					     - 1), 0);
-      decl = build_decl (loc, VAR_DECL, NULL_TREE, arg1_type);
-      DECL_EXTERNAL (decl) = 0;
-      TREE_PUBLIC (decl) = 0;
-      DECL_CONTEXT (decl) = current_function_decl;
-      TREE_USED (decl) = 1;
-      TREE_TYPE (decl) = arg1_type;
-      TREE_READONLY (decl) = TYPE_READONLY (arg1_type);
-      if (c_dialect_cxx ())
-	{
-	  stmt = build4 (TARGET_EXPR, arg1_type, decl, arg1,
-			 NULL_TREE, NULL_TREE);
-	  SET_EXPR_LOCATION (stmt, loc);
-	}
-      else
-	{
-	  DECL_INITIAL (decl) = arg1;
-	  stmt = build1 (DECL_EXPR, arg1_type, decl);
-	  TREE_ADDRESSABLE (decl) = 1;
-	  SET_EXPR_LOCATION (stmt, loc);
-	  stmt = build1 (COMPOUND_LITERAL_EXPR, arg1_type, stmt);
-	}
-
-      innerptrtype = build_pointer_type (arg1_inner_type);
-
-      stmt = build_unary_op (loc, ADDR_EXPR, stmt, 0);
-      stmt = convert (innerptrtype, stmt);
-      stmt = build_binary_op (loc, PLUS_EXPR, stmt, arg2, 1);
-      stmt = build_indirect_ref (loc, stmt, RO_NULL);
-
-      /* PR83660: We mark this as having side effects so that
-	 downstream in fold_build_cleanup_point_expr () it will get a
-	 CLEANUP_POINT_EXPR.  If it does not we can run into an ICE
-	 later in gimplify_cleanup_point_expr ().  Potentially this
-	 causes missed optimization because the actually is no side
-	 effect.  */
-      if (c_dialect_cxx ())
-	TREE_SIDE_EFFECTS (stmt) = 1;
-
-      return stmt;
-    }
-
-  /* For now use pointer tricks to do the insertion, unless we are on VSX
-     inserting a double to a constant offset..  */
-  if (fcode == ALTIVEC_BUILTIN_VEC_INSERT)
-    {
-      tree arg0;
-      tree arg1;
-      tree arg2;
-      tree arg1_type;
-      tree decl, stmt;
-      machine_mode mode;
-
-      /* No second or third arguments. */
-      if (nargs != 3)
-	{
-	  error ("builtin %qs only accepts 3 arguments", "vec_insert");
-	  return error_mark_node;
-	}
-
-      arg0 = (*arglist)[0];
-      arg1 = (*arglist)[1];
-      arg1_type = TREE_TYPE (arg1);
-      arg2 = fold_for_warn ((*arglist)[2]);
-
-      if (TREE_CODE (arg1_type) != VECTOR_TYPE)
-	goto bad;
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
-	goto bad;
-
-      /* If we can use the VSX xxpermdi instruction, use that for insert.  */
-      mode = TYPE_MODE (arg1_type);
-      if ((mode == V2DFmode || mode == V2DImode) && VECTOR_UNIT_VSX_P (mode)
-	  && TREE_CODE (arg2) == INTEGER_CST)
-	{
-	  wide_int selector = wi::to_wide (arg2);
-	  selector = wi::umod_trunc (selector, 2);
-	  tree call = NULL_TREE;
-
-	  arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector);
-	  if (mode == V2DFmode)
-	    call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V2DF];
-	  else if (mode == V2DImode)
-	    call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V2DI];
-
-	  /* Note, __builtin_vec_insert_<xxx> has vector and scalar types
-	     reversed.  */
-	  if (call)
-	    return build_call_expr (call, 3, arg1, arg0, arg2);
-	}
-      else if (mode == V1TImode && VECTOR_UNIT_VSX_P (mode)
-	       && TREE_CODE (arg2) == INTEGER_CST)
-	{
-	  tree call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V1TI];
-	  wide_int selector = wi::zero(32);
-
-	  arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector);
-	  /* Note, __builtin_vec_insert_<xxx> has vector and scalar types
-	     reversed.  */
-	  return build_call_expr (call, 3, arg1, arg0, arg2);
-	}
-
-      /* Build *(((arg1_inner_type*)&(vector type){arg1})+arg2) = arg0 with
-	 VIEW_CONVERT_EXPR.  i.e.:
-	 D.3192 = v1;
-	 _1 = n & 3;
-	 VIEW_CONVERT_EXPR<int[4]>(D.3192)[_1] = i;
-	 v1 = D.3192;
-	 D.3194 = v1;  */
-      if (TYPE_VECTOR_SUBPARTS (arg1_type) == 1)
-	arg2 = build_int_cst (TREE_TYPE (arg2), 0);
-      else
-	arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2,
-				build_int_cst (TREE_TYPE (arg2),
-					       TYPE_VECTOR_SUBPARTS (arg1_type)
-					       - 1), 0);
-      decl = build_decl (loc, VAR_DECL, NULL_TREE, arg1_type);
-      DECL_EXTERNAL (decl) = 0;
-      TREE_PUBLIC (decl) = 0;
-      DECL_CONTEXT (decl) = current_function_decl;
-      TREE_USED (decl) = 1;
-      TREE_TYPE (decl) = arg1_type;
-      TREE_READONLY (decl) = TYPE_READONLY (arg1_type);
-      TREE_ADDRESSABLE (decl) = 1;
-      if (c_dialect_cxx ())
-	{
-	  stmt = build4 (TARGET_EXPR, arg1_type, decl, arg1,
-			 NULL_TREE, NULL_TREE);
-	  SET_EXPR_LOCATION (stmt, loc);
-	}
-      else
-	{
-	  DECL_INITIAL (decl) = arg1;
-	  stmt = build1 (DECL_EXPR, arg1_type, decl);
-	  SET_EXPR_LOCATION (stmt, loc);
-	  stmt = build1 (COMPOUND_LITERAL_EXPR, arg1_type, stmt);
-	}
-
-      if (TARGET_VSX)
-	{
-	  stmt = build_array_ref (loc, stmt, arg2);
-	  stmt = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg0), stmt,
-			      convert (TREE_TYPE (stmt), arg0));
-	  stmt = build2 (COMPOUND_EXPR, arg1_type, stmt, decl);
-	}
-      else
-	{
-	  tree arg1_inner_type;
-	  tree innerptrtype;
-	  arg1_inner_type = TREE_TYPE (arg1_type);
-	  innerptrtype = build_pointer_type (arg1_inner_type);
-
-	  stmt = build_unary_op (loc, ADDR_EXPR, stmt, 0);
-	  stmt = convert (innerptrtype, stmt);
-	  stmt = build_binary_op (loc, PLUS_EXPR, stmt, arg2, 1);
-	  stmt = build_indirect_ref (loc, stmt, RO_NULL);
-	  stmt = build2 (MODIFY_EXPR, TREE_TYPE (stmt), stmt,
-			 convert (TREE_TYPE (stmt), arg0));
-	  stmt = build2 (COMPOUND_EXPR, arg1_type, stmt, decl);
-	}
-      return stmt;
-    }
-
-  for (n = 0;
-       !VOID_TYPE_P (TREE_VALUE (fnargs)) && n < nargs;
-       fnargs = TREE_CHAIN (fnargs), n++)
-    {
-      tree decl_type = TREE_VALUE (fnargs);
-      tree arg = (*arglist)[n];
-      tree type;
-
-      if (arg == error_mark_node)
-	return error_mark_node;
-
-      if (n >= 4)
-        abort ();
-
-      arg = default_conversion (arg);
-
-      /* The C++ front-end converts float * to const void * using
-	 NOP_EXPR<const void *> (NOP_EXPR<void *> (x)).  */
-      type = TREE_TYPE (arg);
-      if (POINTER_TYPE_P (type)
-	  && TREE_CODE (arg) == NOP_EXPR
-	  && lang_hooks.types_compatible_p (TREE_TYPE (arg),
-					    const_ptr_type_node)
-	  && lang_hooks.types_compatible_p (TREE_TYPE (TREE_OPERAND (arg, 0)),
-					    ptr_type_node))
-	{
-	  arg = TREE_OPERAND (arg, 0);
-          type = TREE_TYPE (arg);
-	}
-
-      /* Remove the const from the pointers to simplify the overload
-	 matching further down.  */
-      if (POINTER_TYPE_P (decl_type)
-	  && POINTER_TYPE_P (type)
-	  && TYPE_QUALS (TREE_TYPE (type)) != 0)
-	{
-          if (TYPE_READONLY (TREE_TYPE (type))
-	      && !TYPE_READONLY (TREE_TYPE (decl_type)))
-	    warning (0, "passing argument %d of %qE discards qualifiers from "
-		        "pointer target type", n + 1, fndecl);
-	  type = build_pointer_type (build_qualified_type (TREE_TYPE (type),
-							   0));
-	  arg = fold_convert (type, arg);
-	}
-
-      /* For P9V_BUILTIN_VEC_LXVL, convert any const * to its non constant
-	 equivalent to simplify the overload matching below.  */
-      if (fcode == P9V_BUILTIN_VEC_LXVL)
-	{
-	  if (POINTER_TYPE_P (type)
-	      && TYPE_READONLY (TREE_TYPE (type)))
-	    {
-	      type = build_pointer_type (build_qualified_type (
-						TREE_TYPE (type),0));
-	      arg = fold_convert (type, arg);
-	    }
-	}
-
-      args[n] = arg;
-      types[n] = type;
-    }
-
-  /* If the number of arguments did not match the prototype, return NULL
-     and the generic code will issue the appropriate error message.  */
-  if (!VOID_TYPE_P (TREE_VALUE (fnargs)) || n < nargs)
-    return NULL;
-
-  if (n == 0)
-    abort ();
-
-  if (fcode == ALTIVEC_BUILTIN_VEC_STEP)
-    {
-      if (TREE_CODE (types[0]) != VECTOR_TYPE)
-	goto bad;
-
-      return build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (types[0]));
-    }
-
-  {
-    bool unsupported_builtin = false;
-    enum rs6000_builtins overloaded_code;
-    tree result = NULL;
-    for (desc = altivec_overloaded_builtins;
-	 desc->code && desc->code != fcode; desc++)
-      continue;
-
-    /* Need to special case __builtin_cmp because the overloaded forms
-       of this function take (unsigned int, unsigned int) or (unsigned
-       long long int, unsigned long long int).  Since C conventions
-       allow the respective argument types to be implicitly coerced into
-       each other, the default handling does not provide adequate
-       discrimination between the desired forms of the function.  */
-    if (fcode == P6_OV_BUILTIN_CMPB)
-      {
-	machine_mode arg1_mode = TYPE_MODE (types[0]);
-	machine_mode arg2_mode = TYPE_MODE (types[1]);
-
-	if (nargs != 2)
-	  {
-	    error ("builtin %qs only accepts 2 arguments", "__builtin_cmpb");
-	    return error_mark_node;
-	  }
-
-	/* If any supplied arguments are wider than 32 bits, resolve to
-	   64-bit variant of built-in function.  */
-	if ((GET_MODE_PRECISION (arg1_mode) > 32)
-	    || (GET_MODE_PRECISION (arg2_mode) > 32))
-	  {
-	    /* Assure all argument and result types are compatible with
-	       the built-in function represented by P6_BUILTIN_CMPB.  */
-	    overloaded_code = P6_BUILTIN_CMPB;
-	  }
-	else
-	  {
-	    /* Assure all argument and result types are compatible with
-	       the built-in function represented by P6_BUILTIN_CMPB_32.  */
-	    overloaded_code = P6_BUILTIN_CMPB_32;
-	  }
-
-	while (desc->code && desc->code == fcode
-	       && desc->overloaded_code != overloaded_code)
-	  desc++;
-
-	if (desc->code && (desc->code == fcode)
-	    && rs6000_builtin_type_compatible (types[0], desc->op1)
-	    && rs6000_builtin_type_compatible (types[1], desc->op2))
-	  {
-	    if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE)
-	      {
-		result = altivec_build_resolved_builtin (args, n, desc);
-		/* overloaded_code is set above */
-		if (!rs6000_builtin_is_supported_p (overloaded_code))
-		  unsupported_builtin = true;
-		else
-		  return result;
-	      }
-	    else
-	      unsupported_builtin = true;
-	  }
-      }
-    else if (fcode == P9V_BUILTIN_VEC_VSIEDP)
-      {
-	machine_mode arg1_mode = TYPE_MODE (types[0]);
-
-	if (nargs != 2)
-	  {
-	    error ("builtin %qs only accepts 2 arguments",
-		   "scalar_insert_exp");
-	    return error_mark_node;
-	  }
-
-	/* If supplied first argument is wider than 64 bits, resolve to
-	   128-bit variant of built-in function.  */
-	if (GET_MODE_PRECISION (arg1_mode) > 64)
-	  {
-	    /* If first argument is of float variety, choose variant
-	       that expects __ieee128 argument.  Otherwise, expect
-	       __int128 argument.  */
-	    if (GET_MODE_CLASS (arg1_mode) == MODE_FLOAT)
-	      overloaded_code = P9V_BUILTIN_VSIEQPF;
-	    else
-	      overloaded_code = P9V_BUILTIN_VSIEQP;
-	  }
-	else
-	  {
-	    /* If first argument is of float variety, choose variant
-	       that expects double argument.  Otherwise, expect
-	       long long int argument.  */
-	    if (GET_MODE_CLASS (arg1_mode) == MODE_FLOAT)
-	      overloaded_code = P9V_BUILTIN_VSIEDPF;
-	    else
-	      overloaded_code = P9V_BUILTIN_VSIEDP;
-	  }
-	while (desc->code && desc->code == fcode
-	       && desc->overloaded_code != overloaded_code)
-	  desc++;
-
-	if (desc->code && (desc->code == fcode)
-	    && rs6000_builtin_type_compatible (types[0], desc->op1)
-	    && rs6000_builtin_type_compatible (types[1], desc->op2))
-	  {
-	    if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE)
-	      {
-		result = altivec_build_resolved_builtin (args, n, desc);
-		/* overloaded_code is set above.  */
-		if (!rs6000_builtin_is_supported_p (overloaded_code))
-		  unsupported_builtin = true;
-		else
-		  return result;
-	      }
-	    else
-	      unsupported_builtin = true;
-	  }
-      }
-    else if ((fcode == P10_BUILTIN_VEC_XXEVAL)
-	    || (fcode == P10V_BUILTIN_VXXPERMX))
-      {
-	signed char op3_type;
-
-	/* Need to special case P10_BUILTIN_VEC_XXEVAL and
-	   P10V_BUILTIN_VXXPERMX because they take 4 arguments and the
-	   existing infrastructure only handles three.  */
-	if (nargs != 4)
-	  {
-	    const char *name = fcode == P10_BUILTIN_VEC_XXEVAL ?
-	      "__builtin_vec_xxeval":"__builtin_vec_xxpermx";
-
-	    error ("builtin %qs requires 4 arguments", name);
-	    return error_mark_node;
-	  }
-
-	for ( ; desc->code == fcode; desc++)
-	  {
-	    if (fcode == P10_BUILTIN_VEC_XXEVAL)
-	      op3_type = desc->op3;
-	    else  /* P10V_BUILTIN_VXXPERMX */
-	      op3_type = RS6000_BTI_V16QI;
-
-	    if (rs6000_builtin_type_compatible (types[0], desc->op1)
-		&& rs6000_builtin_type_compatible (types[1], desc->op2)
-		&& rs6000_builtin_type_compatible (types[2], desc->op3)
-		&& rs6000_builtin_type_compatible (types[2], op3_type)
-		&& rs6000_builtin_type_compatible (types[3],
-						   RS6000_BTI_UINTSI))
-	      {
-		if (rs6000_builtin_decls[desc->overloaded_code] == NULL_TREE)
-		  unsupported_builtin = true;
-		else
-		  {
-		    result = altivec_build_resolved_builtin (args, n, desc);
-		    if (rs6000_builtin_is_supported_p (desc->overloaded_code))
-		      return result;
-		    /* Allow loop to continue in case a different
-		       definition is supported.  */
-		    overloaded_code = desc->overloaded_code;
-		    unsupported_builtin = true;
-		  }
-	      }
-	  }
-      }
-    else
-      {
-	/* For arguments after the last, we have RS6000_BTI_NOT_OPAQUE in
-	   the opX fields.  */
-	for (; desc->code == fcode; desc++)
-	  {
-	    if ((desc->op1 == RS6000_BTI_NOT_OPAQUE
-		 || rs6000_builtin_type_compatible (types[0], desc->op1))
-		&& (desc->op2 == RS6000_BTI_NOT_OPAQUE
-		    || rs6000_builtin_type_compatible (types[1], desc->op2))
-		&& (desc->op3 == RS6000_BTI_NOT_OPAQUE
-		    || rs6000_builtin_type_compatible (types[2], desc->op3)))
-	      {
-		if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE)
-		  {
-		    result = altivec_build_resolved_builtin (args, n, desc);
-		    if (!rs6000_builtin_is_supported_p (desc->overloaded_code))
-		      {
-			/* Allow loop to continue in case a different
-			   definition is supported.  */
-			overloaded_code = desc->overloaded_code;
-			unsupported_builtin = true;
-		      }
-		    else
-		      return result;
-		  }
-		else
-		  unsupported_builtin = true;
-	      }
-	  }
-      }
-
-    if (unsupported_builtin)
-      {
-	const char *name = rs6000_overloaded_builtin_name (fcode);
-	if (result != NULL)
-	  {
-	    const char *internal_name
-	      = rs6000_overloaded_builtin_name (overloaded_code);
-	    /* An error message making reference to the name of the
-	       non-overloaded function has already been issued.  Add
-	       clarification of the previous message.  */
-	    rich_location richloc (line_table, input_location);
-	    inform (&richloc,
-		    "overloaded builtin %qs is implemented by builtin %qs",
-		    name, internal_name);
-	  }
-	else
-	  error ("%qs is not supported in this compiler configuration", name);
-	/* If an error-representing  result tree was returned from
-	   altivec_build_resolved_builtin above, use it.  */
-	return (result != NULL) ? result : error_mark_node;
-      }
-  }
- bad:
-  {
-    const char *name = rs6000_overloaded_builtin_name (fcode);
-    error ("invalid parameter combination for AltiVec intrinsic %qs", name);
-    return error_mark_node;
-  }
+  return altivec_resolve_new_overloaded_builtin (loc, fndecl, passed_arglist);
 }
 
 /* Build a tree for a function call to an Altivec non-overloaded builtin.
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 3a43a768c5c..85aea9b8c2f 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -182,13 +182,6 @@ static const struct
   { "mma",		PPC_FEATURE2_MMA,		1 },
 };
 
-static void altivec_init_builtins (void);
-static tree builtin_function_type (machine_mode, machine_mode,
-				   machine_mode, machine_mode,
-				   enum rs6000_builtins, const char *name);
-static void rs6000_common_init_builtins (void);
-static void htm_init_builtins (void);
-static void mma_init_builtins (void);
 static rtx rs6000_expand_new_builtin (tree, rtx, rtx, machine_mode, int);
 static bool rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi);
 
@@ -9029,89 +9022,6 @@ const char *rs6000_type_string (tree type_node)
   return "unknown";
 }
 
-static void
-def_builtin (const char *name, tree type, enum rs6000_builtins code)
-{
-  tree t;
-  unsigned classify = rs6000_builtin_info[(int)code].attr;
-  const char *attr_string = "";
-
-  /* Don't define the builtin if it doesn't have a type.  See PR92661.  */
-  if (type == NULL_TREE)
-    return;
-
-  gcc_assert (name != NULL);
-  gcc_assert (IN_RANGE ((int)code, 0, (int)RS6000_BUILTIN_COUNT));
-
-  if (rs6000_builtin_decls[(int)code])
-    fatal_error (input_location,
-		 "internal error: builtin function %qs already processed",
-		 name);
-
-  rs6000_builtin_decls[(int)code] = t =
-    add_builtin_function (name, type, (int)code, BUILT_IN_MD, NULL, NULL_TREE);
-
-  /* Set any special attributes.  */
-  if ((classify & RS6000_BTC_CONST) != 0)
-    {
-      /* const function, function only depends on the inputs.  */
-      TREE_READONLY (t) = 1;
-      TREE_NOTHROW (t) = 1;
-      attr_string = "= const";
-    }
-  else if ((classify & RS6000_BTC_PURE) != 0)
-    {
-      /* pure function, function can read global memory, but does not set any
-	 external state.  */
-      DECL_PURE_P (t) = 1;
-      TREE_NOTHROW (t) = 1;
-      attr_string = "= pure";
-    }
-  else if ((classify & RS6000_BTC_FP) != 0)
-    {
-      /* Function is a math function.  If rounding mode is on, then treat the
-	 function as not reading global memory, but it can have arbitrary side
-	 effects.  If it is off, then assume the function is a const function.
-	 This mimics the ATTR_MATHFN_FPROUNDING attribute in
-	 builtin-attribute.def that is used for the math functions. */
-      TREE_NOTHROW (t) = 1;
-      if (flag_rounding_math)
-	{
-	  DECL_PURE_P (t) = 1;
-	  DECL_IS_NOVOPS (t) = 1;
-	  attr_string = "= fp, pure";
-	}
-      else
-	{
-	  TREE_READONLY (t) = 1;
-	  attr_string = "= fp, const";
-	}
-    }
-  else if ((classify & (RS6000_BTC_QUAD | RS6000_BTC_PAIR)) != 0)
-    /* The function uses a register quad and/or pair.  Nothing to do.  */
-    ;
-  else if ((classify & RS6000_BTC_ATTR_MASK) != 0)
-    gcc_unreachable ();
-
-  if (TARGET_DEBUG_BUILTIN)
-    {
-      tree t = TREE_TYPE (type);
-      fprintf (stderr, "%s %s (", rs6000_type_string (t), name);
-      t = TYPE_ARG_TYPES (type);
-      gcc_assert (t);
-
-      while (TREE_VALUE (t) != void_type_node)
-	{
-	  fprintf (stderr, "%s", rs6000_type_string (TREE_VALUE (t)));
-	  t = TREE_CHAIN (t);
-	  gcc_assert (t);
-	  if (TREE_VALUE (t) != void_type_node)
-	    fprintf (stderr, ", ");
-	}
-      fprintf (stderr, "); %s [%4d]\n", attr_string, (int) code);
-    }
-}
-
 static const struct builtin_compatibility bdesc_compat[] =
 {
 #define RS6000_BUILTIN_COMPAT
@@ -9473,8744 +9383,3631 @@ rs6000_overloaded_builtin_name (enum rs6000_builtins fncode)
   return rs6000_builtin_info[(int)fncode].name;
 }
 
-/* Expand an expression EXP that calls a builtin without arguments.  */
 static rtx
-rs6000_expand_zeroop_builtin (enum insn_code icode, rtx target)
+altivec_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target)
 {
-  rtx pat;
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  rtx pat, scratch;
+  tree cr6_form = CALL_EXPR_ARG (exp, 0);
+  tree arg0 = CALL_EXPR_ARG (exp, 1);
+  tree arg1 = CALL_EXPR_ARG (exp, 2);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  machine_mode tmode = SImode;
+  machine_mode mode0 = insn_data[icode].operand[1].mode;
+  machine_mode mode1 = insn_data[icode].operand[2].mode;
+  int cr6_form_int;
 
-  if (icode == CODE_FOR_rs6000_mffsl
-      && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+  if (TREE_CODE (cr6_form) != INTEGER_CST)
     {
-      error ("%<__builtin_mffsl%> not supported with %<-msoft-float%>");
+      error ("argument 1 of %qs must be a constant",
+	     "__builtin_altivec_predicate");
       return const0_rtx;
     }
+  else
+    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
+
+  gcc_assert (mode0 == mode1);
+
+  /* If we have invalid arguments, bail out before generating bad rtl.  */
+  if (arg0 == error_mark_node || arg1 == error_mark_node)
+    return const0_rtx;
 
   if (target == 0
       || GET_MODE (target) != tmode
       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
     target = gen_reg_rtx (tmode);
 
-  pat = GEN_FCN (icode) (target);
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
+
+  /* Note that for many of the relevant operations (e.g. cmpne or
+     cmpeq) with float or double operands, it makes more sense for the
+     mode of the allocated scratch register to select a vector of
+     integer.  But the choice to copy the mode of operand 0 was made
+     long ago and there are no plans to change it.  */
+  scratch = gen_reg_rtx (mode0);
+
+  pat = GEN_FCN (icode) (scratch, op0, op1);
   if (! pat)
     return 0;
   emit_insn (pat);
 
-  return target;
-}
-
-
-static rtx
-rs6000_expand_mtfsf_builtin (enum insn_code icode, tree exp)
-{
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  machine_mode mode0 = insn_data[icode].operand[0].mode;
-  machine_mode mode1 = insn_data[icode].operand[1].mode;
-
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  /* The vec_any* and vec_all* predicates use the same opcodes for two
+     different operations, but the bits in CR6 will be different
+     depending on what information we want.  So we have to play tricks
+     with CR6 to get the right bits out.
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node || arg1 == error_mark_node)
-    return const0_rtx;
+     If you think this is disgusting, look at the specs for the
+     AltiVec predicates.  */
 
-  if (!CONST_INT_P (op0)
-      || INTVAL (op0) > 255
-      || INTVAL (op0) < 0)
+  switch (cr6_form_int)
     {
-      error ("argument 1 must be an 8-bit field value");
-      return const0_rtx;
+    case 0:
+      emit_insn (gen_cr6_test_for_zero (target));
+      break;
+    case 1:
+      emit_insn (gen_cr6_test_for_zero_reverse (target));
+      break;
+    case 2:
+      emit_insn (gen_cr6_test_for_lt (target));
+      break;
+    case 3:
+      emit_insn (gen_cr6_test_for_lt_reverse (target));
+      break;
+    default:
+      error ("argument 1 of %qs is out of range",
+	     "__builtin_altivec_predicate");
+      break;
     }
 
-  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-
-  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
-
-  pat = GEN_FCN (icode) (op0, op1);
-  if (!pat)
-    return const0_rtx;
-  emit_insn (pat);
-
-  return NULL_RTX;
+  return target;
 }
 
-static rtx
-rs6000_expand_mtfsb_builtin (enum insn_code icode, tree exp)
+rtx
+swap_endian_selector_for_mode (machine_mode mode)
 {
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  rtx op0 = expand_normal (arg0);
+  unsigned int swap1[16] = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
+  unsigned int swap2[16] = {7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8};
+  unsigned int swap4[16] = {3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12};
+  unsigned int swap8[16] = {1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14};
 
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  unsigned int *swaparray, i;
+  rtx perm[16];
 
-  if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+  switch (mode)
     {
-      error ("%<__builtin_mtfsb0%> and %<__builtin_mtfsb1%> not supported with "
-	     "%<-msoft-float%>");
-      return const0_rtx;
+    case E_V1TImode:
+      swaparray = swap1;
+      break;
+    case E_V2DFmode:
+    case E_V2DImode:
+      swaparray = swap2;
+      break;
+    case E_V4SFmode:
+    case E_V4SImode:
+      swaparray = swap4;
+      break;
+    case E_V8HImode:
+      swaparray = swap8;
+      break;
+    default:
+      gcc_unreachable ();
     }
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node)
-    return const0_rtx;
+  for (i = 0; i < 16; ++i)
+    perm[i] = GEN_INT (swaparray[i]);
 
-  /* Only allow bit numbers 0 to 31.  */
-  if (!u5bit_cint_operand (op0, VOIDmode))
-    {
-       error ("Argument must be a constant between 0 and 31.");
-       return const0_rtx;
-     }
+  return force_reg (V16QImode, gen_rtx_CONST_VECTOR (V16QImode,
+						     gen_rtvec_v (16, perm)));
+}
 
-  pat = GEN_FCN (icode) (op0);
-  if (!pat)
-    return const0_rtx;
-  emit_insn (pat);
+/* Return the appropriate SPR number associated with the given builtin.  */
+static inline HOST_WIDE_INT
+htm_spr_num (enum rs6000_builtins code)
+{
+  if (code == HTM_BUILTIN_GET_TFHAR
+      || code == HTM_BUILTIN_SET_TFHAR)
+    return TFHAR_SPR;
+  else if (code == HTM_BUILTIN_GET_TFIAR
+	   || code == HTM_BUILTIN_SET_TFIAR)
+    return TFIAR_SPR;
+  else if (code == HTM_BUILTIN_GET_TEXASR
+	   || code == HTM_BUILTIN_SET_TEXASR)
+    return TEXASR_SPR;
+  gcc_assert (code == HTM_BUILTIN_GET_TEXASRU
+	      || code == HTM_BUILTIN_SET_TEXASRU);
+  return TEXASRU_SPR;
+}
 
-  return NULL_RTX;
+/* Return the correct ICODE value depending on whether we are
+   setting or reading the HTM SPRs.  */
+static inline enum insn_code
+rs6000_htm_spr_icode (bool nonvoid)
+{
+  if (nonvoid)
+    return (TARGET_POWERPC64) ? CODE_FOR_htm_mfspr_di : CODE_FOR_htm_mfspr_si;
+  else
+    return (TARGET_POWERPC64) ? CODE_FOR_htm_mtspr_di : CODE_FOR_htm_mtspr_si;
 }
 
+/* Expand vec_init builtin.  */
 static rtx
-rs6000_expand_set_fpscr_rn_builtin (enum insn_code icode, tree exp)
+altivec_expand_vec_init_builtin (tree type, tree exp, rtx target)
 {
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  rtx op0 = expand_normal (arg0);
-  machine_mode mode0 = insn_data[icode].operand[0].mode;
+  machine_mode tmode = TYPE_MODE (type);
+  machine_mode inner_mode = GET_MODE_INNER (tmode);
+  int i, n_elt = GET_MODE_NUNITS (tmode);
 
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  gcc_assert (VECTOR_MODE_P (tmode));
+  gcc_assert (n_elt == call_expr_nargs (exp));
+
+  if (!target || !register_operand (target, tmode))
+    target = gen_reg_rtx (tmode);
 
-  if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+  /* If we have a vector compromised of a single element, such as V1TImode, do
+     the initialization directly.  */
+  if (n_elt == 1 && GET_MODE_SIZE (tmode) == GET_MODE_SIZE (inner_mode))
     {
-      error ("%<__builtin_set_fpscr_rn%> not supported with %<-msoft-float%>");
-      return const0_rtx;
+      rtx x = expand_normal (CALL_EXPR_ARG (exp, 0));
+      emit_move_insn (target, gen_lowpart (tmode, x));
     }
+  else
+    {
+      rtvec v = rtvec_alloc (n_elt);
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node)
-    return const0_rtx;
+      for (i = 0; i < n_elt; ++i)
+	{
+	  rtx x = expand_normal (CALL_EXPR_ARG (exp, i));
+	  RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
+	}
 
-  /* If the argument is a constant, check the range. Argument can only be a
-     2-bit value.  Unfortunately, can't check the range of the value at
-     compile time if the argument is a variable.  The least significant two
-     bits of the argument, regardless of type, are used to set the rounding
-     mode.  All other bits are ignored.  */
-  if (CONST_INT_P (op0) && !const_0_to_3_operand(op0, VOIDmode))
-    {
-      error ("Argument must be a value between 0 and 3.");
-      return const0_rtx;
+      rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v));
     }
 
-  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
+  return target;
+}
 
-  pat = GEN_FCN (icode) (op0);
-  if (!pat)
-    return const0_rtx;
-  emit_insn (pat);
+/* Return the integer constant in ARG.  Constrain it to be in the range
+   of the subparts of VEC_TYPE; issue an error if not.  */
 
-  return NULL_RTX;
-}
-static rtx
-rs6000_expand_set_fpscr_drn_builtin (enum insn_code icode, tree exp)
+static int
+get_element_number (tree vec_type, tree arg)
 {
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  rtx op0 = expand_normal (arg0);
-  machine_mode mode0 = insn_data[icode].operand[0].mode;
-
-  if (TARGET_32BIT)
-    /* Builtin not supported in 32-bit mode.  */
-    fatal_error (input_location,
-		 "%<__builtin_set_fpscr_drn%> is not supported "
-		 "in 32-bit mode");
+  unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1;
 
-  if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+  if (!tree_fits_uhwi_p (arg)
+      || (elt = tree_to_uhwi (arg), elt > max))
     {
-      error ("%<__builtin_set_fpscr_drn%> not supported with %<-msoft-float%>");
-      return const0_rtx;
-    }
-
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
-
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node)
-    return const0_rtx;
-
-  /* If the argument is a constant, check the range. Agrument can only be a
-     3-bit value.  Unfortunately, can't check the range of the value at
-     compile time if the argument is a variable. The least significant two
-     bits of the argument, regardless of type, are used to set the rounding
-     mode.  All other bits are ignored.  */
-  if (CONST_INT_P (op0) && !const_0_to_7_operand(op0, VOIDmode))
-   {
-      error ("Argument must be a value between 0 and 7.");
-      return const0_rtx;
+      error ("selector must be an integer constant in the range [0, %wi]", max);
+      return 0;
     }
 
-  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-
-  pat = GEN_FCN (icode) (op0);
-  if (! pat)
-    return const0_rtx;
-  emit_insn (pat);
-
-  return NULL_RTX;
+  return elt;
 }
 
+/* Expand vec_set builtin.  */
 static rtx
-rs6000_expand_unop_builtin (enum insn_code icode, tree exp, rtx target)
+altivec_expand_vec_set_builtin (tree exp)
 {
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  rtx op0 = expand_normal (arg0);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
-
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
-
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node)
-    return const0_rtx;
-
-  if (icode == CODE_FOR_altivec_vspltisb
-      || icode == CODE_FOR_altivec_vspltish
-      || icode == CODE_FOR_altivec_vspltisw)
-    {
-      /* Only allow 5-bit *signed* literals.  */
-      if (!CONST_INT_P (op0)
-	  || INTVAL (op0) > 15
-	  || INTVAL (op0) < -16)
-	{
-	  error ("argument 1 must be a 5-bit signed literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-
-  pat = GEN_FCN (icode) (target, op0);
-  if (! pat)
-    return 0;
-  emit_insn (pat);
-
-  return target;
-}
+  machine_mode tmode, mode1;
+  tree arg0, arg1, arg2;
+  int elt;
+  rtx op0, op1;
 
-static rtx
-altivec_expand_abs_builtin (enum insn_code icode, tree exp, rtx target)
-{
-  rtx pat, scratch1, scratch2;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  rtx op0 = expand_normal (arg0);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  arg1 = CALL_EXPR_ARG (exp, 1);
+  arg2 = CALL_EXPR_ARG (exp, 2);
 
-  /* If we have invalid arguments, bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node)
-    return const0_rtx;
+  tmode = TYPE_MODE (TREE_TYPE (arg0));
+  mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
+  gcc_assert (VECTOR_MODE_P (tmode));
 
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
+  op0 = expand_expr (arg0, NULL_RTX, tmode, EXPAND_NORMAL);
+  op1 = expand_expr (arg1, NULL_RTX, mode1, EXPAND_NORMAL);
+  elt = get_element_number (TREE_TYPE (arg0), arg2);
 
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
+  if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
+    op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
 
-  scratch1 = gen_reg_rtx (mode0);
-  scratch2 = gen_reg_rtx (mode0);
+  op0 = force_reg (tmode, op0);
+  op1 = force_reg (mode1, op1);
 
-  pat = GEN_FCN (icode) (target, op0, scratch1, scratch2);
-  if (! pat)
-    return 0;
-  emit_insn (pat);
+  rs6000_expand_vector_set (op0, op1, GEN_INT (elt));
 
-  return target;
+  return op0;
 }
 
+/* Expand vec_ext builtin.  */
 static rtx
-rs6000_expand_binop_builtin (enum insn_code icode, tree exp, rtx target)
+altivec_expand_vec_ext_builtin (tree exp, rtx target)
 {
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
-  machine_mode mode1 = insn_data[icode].operand[2].mode;
+  machine_mode tmode, mode0;
+  tree arg0, arg1;
+  rtx op0;
+  rtx op1;
 
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  arg1 = CALL_EXPR_ARG (exp, 1);
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node || arg1 == error_mark_node)
-    return const0_rtx;
+  op0 = expand_normal (arg0);
+  op1 = expand_normal (arg1);
 
-  if (icode == CODE_FOR_unpackv1ti
-	   || icode == CODE_FOR_unpackkf
-	   || icode == CODE_FOR_unpacktf
-	   || icode == CODE_FOR_unpackif
-	   || icode == CODE_FOR_unpacktd
-	   || icode == CODE_FOR_vec_cntmb_v16qi
-	   || icode == CODE_FOR_vec_cntmb_v8hi
-	   || icode == CODE_FOR_vec_cntmb_v4si
-	   || icode == CODE_FOR_vec_cntmb_v2di)
-    {
-      /* Only allow 1-bit unsigned literals. */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || !IN_RANGE (TREE_INT_CST_LOW (arg1), 0, 1))
-	{
-	  error ("argument 2 must be a 1-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_altivec_vspltw)
-    {
-      /* Only allow 2-bit unsigned literals.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg1) & ~3)
-	{
-	  error ("argument 2 must be a 2-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_vgnb)
-    {
-      /* Only allow unsigned literals in range 2..7.  */
-      /* Note that arg1 is second operand.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || (TREE_INT_CST_LOW (arg1) & ~7)
-	  || !IN_RANGE (TREE_INT_CST_LOW (arg1), 2, 7))
-	{
-	  error ("argument 2 must be unsigned literal between "
-		 "2 and 7 inclusive");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_altivec_vsplth)
-    {
-      /* Only allow 3-bit unsigned literals.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg1) & ~7)
-	{
-	  error ("argument 2 must be a 3-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_altivec_vspltb)
-    {
-      /* Only allow 4-bit unsigned literals.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg1) & ~15)
-	{
-	  error ("argument 2 must be a 4-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_altivec_vcfux
-      || icode == CODE_FOR_altivec_vcfsx
-      || icode == CODE_FOR_altivec_vctsxs
-      || icode == CODE_FOR_altivec_vctuxs
-      || icode == CODE_FOR_vsx_xvcvuxddp_scale
-      || icode == CODE_FOR_vsx_xvcvsxddp_scale)
-    {
-      /* Only allow 5-bit unsigned literals.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
-	{
-	  error ("argument 2 must be a 5-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_dfptstsfi_eq_dd
-      || icode == CODE_FOR_dfptstsfi_lt_dd
-      || icode == CODE_FOR_dfptstsfi_gt_dd
-      || icode == CODE_FOR_dfptstsfi_unordered_dd
-      || icode == CODE_FOR_dfptstsfi_eq_td
-      || icode == CODE_FOR_dfptstsfi_lt_td
-      || icode == CODE_FOR_dfptstsfi_gt_td
-      || icode == CODE_FOR_dfptstsfi_unordered_td)
-    {
-      /* Only allow 6-bit unsigned literals.  */
-      STRIP_NOPS (arg0);
-      if (TREE_CODE (arg0) != INTEGER_CST
-	  || !IN_RANGE (TREE_INT_CST_LOW (arg0), 0, 63))
-	{
-	  error ("argument 1 must be a 6-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_xststdcqp_kf
-	   || icode == CODE_FOR_xststdcqp_tf
-	   || icode == CODE_FOR_xststdcdp
-	   || icode == CODE_FOR_xststdcsp
-	   || icode == CODE_FOR_xvtstdcdp
-	   || icode == CODE_FOR_xvtstdcsp)
+  if (TREE_CODE (arg1) == INTEGER_CST)
     {
-      /* Only allow 7-bit unsigned literals. */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || !IN_RANGE (TREE_INT_CST_LOW (arg1), 0, 127))
-	{
-	  error ("argument 2 must be a 7-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
+      unsigned HOST_WIDE_INT elt;
+      unsigned HOST_WIDE_INT size = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
+      unsigned int truncated_selector;
+      /* Even if !tree_fits_uhwi_p (arg1)), TREE_INT_CST_LOW (arg0)
+	 returns low-order bits of INTEGER_CST for modulo indexing.  */
+      elt = TREE_INT_CST_LOW (arg1);
+      truncated_selector = elt % size;
+      op1 = GEN_INT (truncated_selector);
     }
 
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
+  tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
+  mode0 = TYPE_MODE (TREE_TYPE (arg0));
+  gcc_assert (VECTOR_MODE_P (mode0));
 
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
+  op0 = force_reg (mode0, op0);
 
-  pat = GEN_FCN (icode) (target, op0, op1);
-  if (! pat)
-    return 0;
-  emit_insn (pat);
+  if (optimize || !target || !register_operand (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  rs6000_expand_vector_extract (target, op0, op1);
 
   return target;
 }
 
-static rtx
-altivec_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target)
+/* Check whether a builtin function is supported in this target
+   configuration.  */
+bool
+rs6000_builtin_is_supported_p (enum rs6000_builtins fncode)
 {
-  rtx pat, scratch;
-  tree cr6_form = CALL_EXPR_ARG (exp, 0);
-  tree arg0 = CALL_EXPR_ARG (exp, 1);
-  tree arg1 = CALL_EXPR_ARG (exp, 2);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  machine_mode tmode = SImode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
-  machine_mode mode1 = insn_data[icode].operand[2].mode;
-  int cr6_form_int;
-
-  if (TREE_CODE (cr6_form) != INTEGER_CST)
-    {
-      error ("argument 1 of %qs must be a constant",
-	     "__builtin_altivec_predicate");
-      return const0_rtx;
-    }
+  HOST_WIDE_INT fnmask = rs6000_builtin_info[fncode].mask;
+  if ((fnmask & rs6000_builtin_mask) != fnmask)
+    return false;
   else
-    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
-
-  gcc_assert (mode0 == mode1);
-
-  /* If we have invalid arguments, bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node || arg1 == error_mark_node)
-    return const0_rtx;
-
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
-
-  /* Note that for many of the relevant operations (e.g. cmpne or
-     cmpeq) with float or double operands, it makes more sense for the
-     mode of the allocated scratch register to select a vector of
-     integer.  But the choice to copy the mode of operand 0 was made
-     long ago and there are no plans to change it.  */
-  scratch = gen_reg_rtx (mode0);
-
-  pat = GEN_FCN (icode) (scratch, op0, op1);
-  if (! pat)
-    return 0;
-  emit_insn (pat);
+    return true;
+}
 
-  /* The vec_any* and vec_all* predicates use the same opcodes for two
-     different operations, but the bits in CR6 will be different
-     depending on what information we want.  So we have to play tricks
-     with CR6 to get the right bits out.
+/* Raise an error message for a builtin function that is called without the
+   appropriate target options being set.  */
 
-     If you think this is disgusting, look at the specs for the
-     AltiVec predicates.  */
+void
+rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode)
+{
+  size_t j = (size_t) fncode;
+  const char *name = rs6000_builtin_info_x[j].bifname;
 
-  switch (cr6_form_int)
+  switch (rs6000_builtin_info_x[j].enable)
     {
-    case 0:
-      emit_insn (gen_cr6_test_for_zero (target));
+    case ENB_P5:
+      error ("%qs requires the %qs option", name, "-mcpu=power5");
       break;
-    case 1:
-      emit_insn (gen_cr6_test_for_zero_reverse (target));
+    case ENB_P6:
+      error ("%qs requires the %qs option", name, "-mcpu=power6");
       break;
-    case 2:
-      emit_insn (gen_cr6_test_for_lt (target));
+    case ENB_P6_64:
+      error ("%qs requires the %qs option and either the %qs or %qs option",
+	     name, "-mcpu=power6", "-m64", "-mpowerpc64");
       break;
-    case 3:
-      emit_insn (gen_cr6_test_for_lt_reverse (target));
+    case ENB_ALTIVEC:
+      error ("%qs requires the %qs option", name, "-maltivec");
       break;
-    default:
-      error ("argument 1 of %qs is out of range",
-	     "__builtin_altivec_predicate");
+    case ENB_CELL:
+      error ("%qs requires the %qs option", name, "-mcpu=cell");
       break;
-    }
-
-  return target;
-}
-
-rtx
-swap_endian_selector_for_mode (machine_mode mode)
-{
-  unsigned int swap1[16] = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
-  unsigned int swap2[16] = {7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8};
-  unsigned int swap4[16] = {3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12};
-  unsigned int swap8[16] = {1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14};
-
-  unsigned int *swaparray, i;
-  rtx perm[16];
-
-  switch (mode)
-    {
-    case E_V1TImode:
-      swaparray = swap1;
+    case ENB_VSX:
+      error ("%qs requires the %qs option", name, "-mvsx");
       break;
-    case E_V2DFmode:
-    case E_V2DImode:
-      swaparray = swap2;
+    case ENB_P7:
+      error ("%qs requires the %qs option", name, "-mcpu=power7");
       break;
-    case E_V4SFmode:
-    case E_V4SImode:
-      swaparray = swap4;
+    case ENB_P7_64:
+      error ("%qs requires the %qs option and either the %qs or %qs option",
+	     name, "-mcpu=power7", "-m64", "-mpowerpc64");
       break;
-    case E_V8HImode:
-      swaparray = swap8;
+    case ENB_P8:
+      error ("%qs requires the %qs option", name, "-mcpu=power8");
+      break;
+    case ENB_P8V:
+      error ("%qs requires the %qs and %qs options", name, "-mcpu=power8",
+	     "-mvsx");
+      break;
+    case ENB_P9:
+      error ("%qs requires the %qs option", name, "-mcpu=power9");
+      break;
+    case ENB_P9_64:
+      error ("%qs requires the %qs option and either the %qs or %qs option",
+	     name, "-mcpu=power9", "-m64", "-mpowerpc64");
+      break;
+    case ENB_P9V:
+      error ("%qs requires the %qs and %qs options", name, "-mcpu=power9",
+	     "-mvsx");
+      break;
+    case ENB_IEEE128_HW:
+      error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name);
+      break;
+    case ENB_DFP:
+      error ("%qs requires the %qs option", name, "-mhard-dfp");
+      break;
+    case ENB_CRYPTO:
+      error ("%qs requires the %qs option", name, "-mcrypto");
+      break;
+    case ENB_HTM:
+      error ("%qs requires the %qs option", name, "-mhtm");
+      break;
+    case ENB_P10:
+      error ("%qs requires the %qs option", name, "-mcpu=power10");
+      break;
+    case ENB_P10_64:
+      error ("%qs requires the %qs option and either the %qs or %qs option",
+	     name, "-mcpu=power10", "-m64", "-mpowerpc64");
+      break;
+    case ENB_MMA:
+      error ("%qs requires the %qs option", name, "-mmma");
       break;
     default:
+    case ENB_ALWAYS:
       gcc_unreachable ();
     }
+}
 
-  for (i = 0; i < 16; ++i)
-    perm[i] = GEN_INT (swaparray[i]);
+/* Target hook for early folding of built-ins, shamelessly stolen
+   from ia64.c.  */
 
-  return force_reg (V16QImode, gen_rtx_CONST_VECTOR (V16QImode,
-						     gen_rtvec_v (16, perm)));
+tree
+rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED,
+		     int n_args ATTRIBUTE_UNUSED,
+		     tree *args ATTRIBUTE_UNUSED,
+		     bool ignore ATTRIBUTE_UNUSED)
+{
+#ifdef SUBTARGET_FOLD_BUILTIN
+  return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
+#else
+  return NULL_TREE;
+#endif
 }
 
-/* For the load and sign extend rightmost elements; load and zero extend
- rightmost element builtins.  */
-static rtx
-altivec_expand_lxvr_builtin (enum insn_code icode, tree exp, rtx target, bool blk, bool sign_extend)
+/* Helper function to handle the gimple folding of a vector compare
+   operation.  This sets up true/false vectors, and uses the
+   VEC_COND_EXPR operation.
+   CODE indicates which comparison is to be made. (EQ, GT, ...).
+   TYPE indicates the type of the result.
+   Code is inserted before GSI.  */
+static tree
+fold_build_vec_cmp (tree_code code, tree type, tree arg0, tree arg1,
+		    gimple_stmt_iterator *gsi)
 {
-  rtx pat, addr;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode smode = insn_data[icode].operand[1].mode;
-  machine_mode mode0 = Pmode;
-  machine_mode mode1 = Pmode;
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
-
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node || arg1 == error_mark_node)
-    return const0_rtx;
-
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
+  tree cmp_type = truth_type_for (type);
+  tree zero_vec = build_zero_cst (type);
+  tree minus_one_vec = build_minus_one_cst (type);
+  tree temp = create_tmp_reg_or_ssa_name (cmp_type);
+  gimple *g = gimple_build_assign (temp, code, arg0, arg1);
+  gsi_insert_before (gsi, g, GSI_SAME_STMT);
+  return fold_build3 (VEC_COND_EXPR, type, temp, minus_one_vec, zero_vec);
+}
 
-  op1 = copy_to_mode_reg (mode1, op1);
+/* Helper function to handle the in-between steps for the
+   vector compare built-ins.  */
+static void
+fold_compare_helper (gimple_stmt_iterator *gsi, tree_code code, gimple *stmt)
+{
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  tree lhs = gimple_call_lhs (stmt);
+  tree cmp = fold_build_vec_cmp (code, TREE_TYPE (lhs), arg0, arg1, gsi);
+  gimple *g = gimple_build_assign (lhs, cmp);
+  gimple_set_location (g, gimple_location (stmt));
+  gsi_replace (gsi, g, true);
+}
 
-  if (op0 == const0_rtx)
-    addr = gen_rtx_MEM (blk ? BLKmode : tmode, op1);
+/* Helper function to map V2DF and V4SF types to their
+ integral equivalents (V2DI and V4SI).  */
+tree map_to_integral_tree_type (tree input_tree_type)
+{
+  if (INTEGRAL_TYPE_P (TREE_TYPE (input_tree_type)))
+    return input_tree_type;
   else
     {
-      op0 = copy_to_mode_reg (mode0, op0);
-      addr = gen_rtx_MEM (blk ? BLKmode : smode,
-			  gen_rtx_PLUS (Pmode, op1, op0));
-    }
-
-  if (sign_extend)
-    {
-      rtx discratch = gen_reg_rtx (V2DImode);
-      rtx tiscratch = gen_reg_rtx (TImode);
-
-      /* Emit the lxvr*x insn.  */
-      pat = GEN_FCN (icode) (tiscratch, addr);
-      if (!pat)
-	return 0;
-      emit_insn (pat);
-
-      /* Emit a sign extension from V16QI,V8HI,V4SI to V2DI.  */
-      rtx temp1, temp2;
-      if (icode == CODE_FOR_vsx_lxvrbx)
-	{
-	  temp1  = simplify_gen_subreg (V16QImode, tiscratch, TImode, 0);
-	  emit_insn (gen_vsx_sign_extend_qi_v2di (discratch, temp1));
-	}
-      else if (icode == CODE_FOR_vsx_lxvrhx)
-	{
-	  temp1  = simplify_gen_subreg (V8HImode, tiscratch, TImode, 0);
-	  emit_insn (gen_vsx_sign_extend_hi_v2di (discratch, temp1));
-	}
-      else if (icode == CODE_FOR_vsx_lxvrwx)
-	{
-	  temp1  = simplify_gen_subreg (V4SImode, tiscratch, TImode, 0);
-	  emit_insn (gen_vsx_sign_extend_si_v2di (discratch, temp1));
-	}
-      else if (icode == CODE_FOR_vsx_lxvrdx)
-	discratch = simplify_gen_subreg (V2DImode, tiscratch, TImode, 0);
+      if (types_compatible_p (TREE_TYPE (input_tree_type),
+			      TREE_TYPE (V2DF_type_node)))
+	return V2DI_type_node;
+      else if (types_compatible_p (TREE_TYPE (input_tree_type),
+				   TREE_TYPE (V4SF_type_node)))
+	return V4SI_type_node;
       else
 	gcc_unreachable ();
-
-      /* Emit the sign extension from V2DI (double) to TI (quad).  */
-      temp2 = simplify_gen_subreg (TImode, discratch, V2DImode, 0);
-      emit_insn (gen_extendditi2_vector (target, temp2));
-
-      return target;
-    }
-  else
-    {
-      /* Zero extend.  */
-      pat = GEN_FCN (icode) (target, addr);
-      if (!pat)
-	return 0;
-      emit_insn (pat);
-      return target;
     }
-  return 0;
 }
 
-static rtx
-altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target, bool blk)
+/* Helper function to handle the vector merge[hl] built-ins.  The
+   implementation difference between h and l versions for this code are in
+   the values used when building of the permute vector for high word versus
+   low word merge.  The variance is keyed off the use_high parameter.  */
+static void
+fold_mergehl_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_high)
 {
-  rtx pat, addr;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = Pmode;
-  machine_mode mode1 = Pmode;
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
-
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node || arg1 == error_mark_node)
-    return const0_rtx;
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  tree lhs = gimple_call_lhs (stmt);
+  tree lhs_type = TREE_TYPE (lhs);
+  int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type);
+  int midpoint = n_elts / 2;
+  int offset = 0;
 
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
+  if (use_high == 1)
+    offset = midpoint;
 
-  op1 = copy_to_mode_reg (mode1, op1);
+  /* The permute_type will match the lhs for integral types.  For double and
+     float types, the permute type needs to map to the V2 or V4 type that
+     matches size.  */
+  tree permute_type;
+  permute_type = map_to_integral_tree_type (lhs_type);
+  tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1);
 
-  /* For LVX, express the RTL accurately by ANDing the address with -16.
-     LVXL and LVE*X expand to use UNSPECs to hide their special behavior,
-     so the raw address is fine.  */
-  if (icode == CODE_FOR_altivec_lvx_v1ti
-      || icode == CODE_FOR_altivec_lvx_v2df
-      || icode == CODE_FOR_altivec_lvx_v2di
-      || icode == CODE_FOR_altivec_lvx_v4sf
-      || icode == CODE_FOR_altivec_lvx_v4si
-      || icode == CODE_FOR_altivec_lvx_v8hi
-      || icode == CODE_FOR_altivec_lvx_v16qi)
+  for (int i = 0; i < midpoint; i++)
     {
-      rtx rawaddr;
-      if (op0 == const0_rtx)
-	rawaddr = op1;
-      else
-	{
-	  op0 = copy_to_mode_reg (mode0, op0);
-	  rawaddr = gen_rtx_PLUS (Pmode, op1, op0);
-	}
-      addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16));
-      addr = gen_rtx_MEM (blk ? BLKmode : tmode, addr);
-
-      emit_insn (gen_rtx_SET (target, addr));
+      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
+				     offset + i));
+      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
+				     offset + n_elts + i));
     }
-  else
-    {
-      if (op0 == const0_rtx)
-	addr = gen_rtx_MEM (blk ? BLKmode : tmode, op1);
-      else
-	{
-	  op0 = copy_to_mode_reg (mode0, op0);
-	  addr = gen_rtx_MEM (blk ? BLKmode : tmode,
-			      gen_rtx_PLUS (Pmode, op1, op0));
-	}
 
-      pat = GEN_FCN (icode) (target, addr);
-      if (! pat)
-	return 0;
-      emit_insn (pat);
-    }
+  tree permute = elts.build ();
 
-  return target;
+  gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute);
+  gimple_set_location (g, gimple_location (stmt));
+  gsi_replace (gsi, g, true);
 }
 
-static rtx
-altivec_expand_stxvl_builtin (enum insn_code icode, tree exp)
+/* Helper function to handle the vector merge[eo] built-ins.  */
+static void
+fold_mergeeo_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_odd)
 {
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  tree arg2 = CALL_EXPR_ARG (exp, 2);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  rtx op2 = expand_normal (arg2);
-  machine_mode mode0 = insn_data[icode].operand[0].mode;
-  machine_mode mode1 = insn_data[icode].operand[1].mode;
-  machine_mode mode2 = insn_data[icode].operand[2].mode;
+  tree arg0 = gimple_call_arg (stmt, 0);
+  tree arg1 = gimple_call_arg (stmt, 1);
+  tree lhs = gimple_call_lhs (stmt);
+  tree lhs_type = TREE_TYPE (lhs);
+  int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type);
 
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return NULL_RTX;
+  /* The permute_type will match the lhs for integral types.  For double and
+     float types, the permute type needs to map to the V2 or V4 type that
+     matches size.  */
+  tree permute_type;
+  permute_type = map_to_integral_tree_type (lhs_type);
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node
-      || arg1 == error_mark_node
-      || arg2 == error_mark_node)
-    return NULL_RTX;
+  tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1);
 
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
-  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
-    op2 = copy_to_mode_reg (mode2, op2);
+ /* Build the permute vector.  */
+  for (int i = 0; i < n_elts / 2; i++)
+    {
+      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
+				     2*i + use_odd));
+      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
+				     2*i + use_odd + n_elts));
+    }
 
-  pat = GEN_FCN (icode) (op0, op1, op2);
-  if (pat)
-    emit_insn (pat);
+  tree permute = elts.build ();
 
-  return NULL_RTX;
+  gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute);
+  gimple_set_location (g, gimple_location (stmt));
+  gsi_replace (gsi, g, true);
 }
 
-static rtx
-altivec_expand_stv_builtin (enum insn_code icode, tree exp)
-{
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  tree arg2 = CALL_EXPR_ARG (exp, 2);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  rtx op2 = expand_normal (arg2);
-  rtx pat, addr, rawaddr, truncrtx;
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode smode = insn_data[icode].operand[1].mode;
-  machine_mode mode1 = Pmode;
-  machine_mode mode2 = Pmode;
-
-  /* Invalid arguments.  Bail before doing anything stoopid!  */
-  if (arg0 == error_mark_node
-      || arg1 == error_mark_node
-      || arg2 == error_mark_node)
-    return const0_rtx;
-
-  op2 = copy_to_mode_reg (mode2, op2);
+/* Expand the MMA built-ins early, so that we can convert the pass-by-reference
+   __vector_quad arguments into pass-by-value arguments, leading to more
+   efficient code generation.  */
 
-  /* For STVX, express the RTL accurately by ANDing the address with -16.
-     STVXL and STVE*X expand to use UNSPECs to hide their special behavior,
-     so the raw address is fine.  */
-  if (icode == CODE_FOR_altivec_stvx_v2df
-      || icode == CODE_FOR_altivec_stvx_v2di
-      || icode == CODE_FOR_altivec_stvx_v4sf
-      || icode == CODE_FOR_altivec_stvx_v4si
-      || icode == CODE_FOR_altivec_stvx_v8hi
-      || icode == CODE_FOR_altivec_stvx_v16qi)
-    {
-      if (op1 == const0_rtx)
-	rawaddr = op2;
-      else
-	{
-	  op1 = copy_to_mode_reg (mode1, op1);
-	  rawaddr = gen_rtx_PLUS (Pmode, op2, op1);
-	}
+bool
+rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree fndecl = gimple_call_fndecl (stmt);
+  enum rs6000_builtins fncode
+    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned attr = rs6000_builtin_info[fncode].attr;
 
-      addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16));
-      addr = gen_rtx_MEM (tmode, addr);
+  if ((attr & RS6000_BTC_GIMPLE) == 0)
+    return false;
 
-      op0 = copy_to_mode_reg (tmode, op0);
+  unsigned nopnds = (attr & RS6000_BTC_OPND_MASK);
+  gimple_seq new_seq = NULL;
+  gimple *new_call;
+  tree new_decl;
 
-      emit_insn (gen_rtx_SET (addr, op0));
-    }
-  else if (icode == CODE_FOR_vsx_stxvrbx
-	   || icode == CODE_FOR_vsx_stxvrhx
-	   || icode == CODE_FOR_vsx_stxvrwx
-	   || icode == CODE_FOR_vsx_stxvrdx)
+  if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC
+      || fncode == VSX_BUILTIN_DISASSEMBLE_PAIR)
     {
-      truncrtx = gen_rtx_TRUNCATE (tmode, op0);
-      op0 = copy_to_mode_reg (E_TImode, truncrtx);
+      /* This is an MMA disassemble built-in function.  */
+      push_gimplify_context (true);
+      unsigned nvec = (fncode == MMA_BUILTIN_DISASSEMBLE_ACC) ? 4 : 2;
+      tree dst_ptr = gimple_call_arg (stmt, 0);
+      tree src_ptr = gimple_call_arg (stmt, 1);
+      tree src_type = TREE_TYPE (src_ptr);
+      tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type));
+      gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq);
 
-      if (op1 == const0_rtx)
-	addr = gen_rtx_MEM (Pmode, op2);
-      else
+      /* If we are not disassembling an accumulator/pair or our destination is
+	 another accumulator/pair, then just copy the entire thing as is.  */
+      if ((fncode == MMA_BUILTIN_DISASSEMBLE_ACC
+	   && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node)
+	  || (fncode == VSX_BUILTIN_DISASSEMBLE_PAIR
+	      && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node))
 	{
-	  op1 = copy_to_mode_reg (mode1, op1);
-	  addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op2, op1));
+	  tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR,
+						   src_type, dst_ptr));
+	  gimplify_assign (dst, src, &new_seq);
+	  pop_gimplify_context (NULL);
+	  gsi_replace_with_seq (gsi, new_seq, true);
+	  return true;
 	}
-      pat = GEN_FCN (icode) (addr, op0);
-      if (pat)
-	emit_insn (pat);
-    }
-  else
-    {
-      if (! (*insn_data[icode].operand[1].predicate) (op0, smode))
-	op0 = copy_to_mode_reg (smode, op0);
 
-      if (op1 == const0_rtx)
-	addr = gen_rtx_MEM (tmode, op2);
-      else
+      /* If we're disassembling an accumulator into a different type, we need
+	 to emit a xxmfacc instruction now, since we cannot do it later.  */
+      if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC)
 	{
-	  op1 = copy_to_mode_reg (mode1, op1);
-	  addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op2, op1));
+	  new_decl = rs6000_builtin_decls[MMA_BUILTIN_XXMFACC_INTERNAL];
+	  new_call = gimple_build_call (new_decl, 1, src);
+	  src = create_tmp_reg_or_ssa_name (vector_quad_type_node);
+	  gimple_call_set_lhs (new_call, src);
+	  gimple_seq_add_stmt (&new_seq, new_call);
 	}
 
-      pat = GEN_FCN (icode) (addr, op0);
-      if (pat)
-	emit_insn (pat);
+      /* Copy the accumulator/pair vector by vector.  */
+      new_decl = rs6000_builtin_decls[fncode + 1];
+      tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node,
+						   ptr_mode, true);
+      tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr);
+      for (unsigned i = 0; i < nvec; i++)
+	{
+	  unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i;
+	  tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base,
+			     build_int_cst (dst_type, index * 16));
+	  tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node);
+	  new_call = gimple_build_call (new_decl, 2, src,
+					build_int_cstu (uint16_type_node, i));
+	  gimple_call_set_lhs (new_call, dstssa);
+	  gimple_seq_add_stmt (&new_seq, new_call);
+	  gimplify_assign (dst, dstssa, &new_seq);
+	}
+      pop_gimplify_context (NULL);
+      gsi_replace_with_seq (gsi, new_seq, true);
+      return true;
     }
-
-  return NULL_RTX;
-}
-
-/* Expand the MMA built-in in EXP.
-   Store true in *EXPANDEDP if we found a built-in to expand.  */
-
-static rtx
-mma_expand_builtin (tree exp, rtx target, bool *expandedp)
-{
-  unsigned i;
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  enum rs6000_builtins fcode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  const struct builtin_description *d = bdesc_mma;
-
-  /* Expand the MMA built-in.  */
-  for (i = 0; i < ARRAY_SIZE (bdesc_mma); i++, d++)
-    if (d->code == fcode)
-      break;
-
-  if (i >= ARRAY_SIZE (bdesc_mma))
+  else if (fncode == VSX_BUILTIN_LXVP)
     {
-      *expandedp = false;
-      return NULL_RTX;
+      push_gimplify_context (true);
+      tree offset = gimple_call_arg (stmt, 0);
+      tree ptr = gimple_call_arg (stmt, 1);
+      tree lhs = gimple_call_lhs (stmt);
+      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
+	ptr = build1 (VIEW_CONVERT_EXPR,
+		      build_pointer_type (vector_pair_type_node), ptr);
+      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
+					       TREE_TYPE (ptr), ptr, offset));
+      gimplify_assign (lhs, mem, &new_seq);
+      pop_gimplify_context (NULL);
+      gsi_replace_with_seq (gsi, new_seq, true);
+      return true;
+    }
+  else if (fncode == VSX_BUILTIN_STXVP)
+    {
+      push_gimplify_context (true);
+      tree src = gimple_call_arg (stmt, 0);
+      tree offset = gimple_call_arg (stmt, 1);
+      tree ptr = gimple_call_arg (stmt, 2);
+      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
+	ptr = build1 (VIEW_CONVERT_EXPR,
+		      build_pointer_type (vector_pair_type_node), ptr);
+      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
+					       TREE_TYPE (ptr), ptr, offset));
+      gimplify_assign (mem, src, &new_seq);
+      pop_gimplify_context (NULL);
+      gsi_replace_with_seq (gsi, new_seq, true);
+      return true;
     }
 
-  *expandedp = true;
-
-  tree arg;
-  call_expr_arg_iterator iter;
-  enum insn_code icode = d->icode;
-  const struct insn_operand_data *insn_op;
-  rtx op[MAX_MMA_OPERANDS];
-  unsigned nopnds = 0;
-  unsigned attr = rs6000_builtin_info[fcode].attr;
-  bool void_func = (attr & RS6000_BTC_VOID);
-  machine_mode tmode = VOIDmode;
+  /* Convert this built-in into an internal version that uses pass-by-value
+     arguments.  The internal built-in follows immediately after this one.  */
+  new_decl = rs6000_builtin_decls[fncode + 1];
+  tree lhs, op[MAX_MMA_OPERANDS];
+  tree acc = gimple_call_arg (stmt, 0);
+  push_gimplify_context (true);
 
-  if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+  if ((attr & RS6000_BTC_QUAD) != 0)
     {
-      tmode = insn_data[icode].operand[0].mode;
-      if (!target
-	  || GET_MODE (target) != tmode
-	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))
-	target = gen_reg_rtx (tmode);
-      op[nopnds++] = target;
+      /* This built-in has a pass-by-reference accumulator input, so load it
+	 into a temporary accumulator for use as a pass-by-value input.  */
+      op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node);
+      for (unsigned i = 1; i < nopnds; i++)
+	op[i] = gimple_call_arg (stmt, i);
+      gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq);
     }
   else
-    target = const0_rtx;
-
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
     {
-      if (arg == error_mark_node)
-	return const0_rtx;
-
-      rtx opnd;
-      insn_op = &insn_data[icode].operand[nopnds];
-      if (TREE_CODE (arg) == ADDR_EXPR
-	  && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0))))
-	opnd = DECL_RTL (TREE_OPERAND (arg, 0));
-      else
-	opnd = expand_normal (arg);
-
-      if (!(*insn_op->predicate) (opnd, insn_op->mode))
-	{
-	  if (!strcmp (insn_op->constraint, "n"))
-	    {
-	      if (!CONST_INT_P (opnd))
-		error ("argument %d must be an unsigned literal", nopnds);
-	      else
-		error ("argument %d is an unsigned literal that is "
-		       "out of range", nopnds);
-	      return const0_rtx;
-	    }
-	  opnd = copy_to_mode_reg (insn_op->mode, opnd);
-	}
-
-      /* Some MMA instructions have INOUT accumulator operands, so force
-	 their target register to be the same as their input register.  */
-      if (!void_func
-	  && nopnds == 1
-	  && !strcmp (insn_op->constraint, "0")
-	  && insn_op->mode == tmode
-	  && REG_P (opnd)
-	  && (*insn_data[icode].operand[0].predicate) (opnd, tmode))
-	target = op[0] = opnd;
-
-      op[nopnds++] = opnd;
+      /* This built-in does not use its pass-by-reference accumulator argument
+	 as an input argument, so remove it from the input list.  */
+      nopnds--;
+      for (unsigned i = 0; i < nopnds; i++)
+	op[i] = gimple_call_arg (stmt, i + 1);
     }
 
-  unsigned attr_args = attr & RS6000_BTC_OPND_MASK;
-  if (attr & RS6000_BTC_QUAD
-      || fcode == VSX_BUILTIN_DISASSEMBLE_PAIR_INTERNAL)
-    attr_args++;
-
-  gcc_assert (nopnds == attr_args);
-
-  rtx pat;
   switch (nopnds)
     {
+    case 0:
+      new_call = gimple_build_call (new_decl, 0);
+      break;
     case 1:
-      pat = GEN_FCN (icode) (op[0]);
+      new_call = gimple_build_call (new_decl, 1, op[0]);
       break;
     case 2:
-      pat = GEN_FCN (icode) (op[0], op[1]);
+      new_call = gimple_build_call (new_decl, 2, op[0], op[1]);
       break;
     case 3:
-      /* The ASSEMBLE builtin source operands are reversed in little-endian
-	 mode, so reorder them.  */
-      if (fcode == VSX_BUILTIN_ASSEMBLE_PAIR_INTERNAL && !WORDS_BIG_ENDIAN)
-	std::swap (op[1], op[2]);
-      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+      new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]);
       break;
     case 4:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+      new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]);
       break;
     case 5:
-      /* The ASSEMBLE builtin source operands are reversed in little-endian
-	 mode, so reorder them.  */
-      if (fcode == MMA_BUILTIN_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN)
-	{
-	  std::swap (op[1], op[4]);
-	  std::swap (op[2], op[3]);
-	}
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
+      new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3],
+				    op[4]);
       break;
     case 6:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
+      new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3],
+				    op[4], op[5]);
       break;
     case 7:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]);
+      new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3],
+				    op[4], op[5], op[6]);
       break;
     default:
       gcc_unreachable ();
     }
-  if (!pat)
-    return NULL_RTX;
-  emit_insn (pat);
 
-  return target;
+  if (fncode == VSX_BUILTIN_BUILD_PAIR || fncode == VSX_BUILTIN_ASSEMBLE_PAIR)
+    lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node);
+  else
+    lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node);
+  gimple_call_set_lhs (new_call, lhs);
+  gimple_seq_add_stmt (&new_seq, new_call);
+  gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq);
+  pop_gimplify_context (NULL);
+  gsi_replace_with_seq (gsi, new_seq, true);
+
+  return true;
 }
 
-/* Return the appropriate SPR number associated with the given builtin.  */
-static inline HOST_WIDE_INT
-htm_spr_num (enum rs6000_builtins code)
-{
-  if (code == HTM_BUILTIN_GET_TFHAR
-      || code == HTM_BUILTIN_SET_TFHAR)
-    return TFHAR_SPR;
-  else if (code == HTM_BUILTIN_GET_TFIAR
-	   || code == HTM_BUILTIN_SET_TFIAR)
-    return TFIAR_SPR;
-  else if (code == HTM_BUILTIN_GET_TEXASR
-	   || code == HTM_BUILTIN_SET_TEXASR)
-    return TEXASR_SPR;
-  gcc_assert (code == HTM_BUILTIN_GET_TEXASRU
-	      || code == HTM_BUILTIN_SET_TEXASRU);
-  return TEXASRU_SPR;
-}
+/* Fold a machine-dependent built-in in GIMPLE.  (For folding into
+   a constant, use rs6000_fold_builtin.)  */
 
-/* Return the correct ICODE value depending on whether we are
-   setting or reading the HTM SPRs.  */
-static inline enum insn_code
-rs6000_htm_spr_icode (bool nonvoid)
+bool
+rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
 {
-  if (nonvoid)
-    return (TARGET_POWERPC64) ? CODE_FOR_htm_mfspr_di : CODE_FOR_htm_mfspr_si;
-  else
-    return (TARGET_POWERPC64) ? CODE_FOR_htm_mtspr_di : CODE_FOR_htm_mtspr_si;
+  return rs6000_gimple_fold_new_builtin (gsi);
 }
 
-/* Expand the HTM builtin in EXP and store the result in TARGET.
-   Store true in *EXPANDEDP if we found a builtin to expand.  */
-static rtx
-htm_expand_builtin (tree exp, rtx target, bool * expandedp)
+/*  Helper function to sort out which built-ins may be valid without having
+    a LHS.  */
+static bool
+rs6000_new_builtin_valid_without_lhs (enum rs6000_gen_builtins fn_code,
+				      tree fndecl)
 {
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
-  enum rs6000_builtins fcode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  const struct builtin_description *d;
-  size_t i;
-
-  *expandedp = true;
+  if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node)
+    return true;
 
-  if (!TARGET_POWERPC64
-      && (fcode == HTM_BUILTIN_TABORTDC
-	  || fcode == HTM_BUILTIN_TABORTDCI))
+  switch (fn_code)
     {
-      size_t uns_fcode = (size_t)fcode;
-      const char *name = rs6000_builtin_info[uns_fcode].name;
-      error ("builtin %qs is only valid in 64-bit mode", name);
-      return const0_rtx;
+    case RS6000_BIF_STVX_V16QI:
+    case RS6000_BIF_STVX_V8HI:
+    case RS6000_BIF_STVX_V4SI:
+    case RS6000_BIF_STVX_V4SF:
+    case RS6000_BIF_STVX_V2DI:
+    case RS6000_BIF_STVX_V2DF:
+    case RS6000_BIF_STXVW4X_V16QI:
+    case RS6000_BIF_STXVW4X_V8HI:
+    case RS6000_BIF_STXVW4X_V4SF:
+    case RS6000_BIF_STXVW4X_V4SI:
+    case RS6000_BIF_STXVD2X_V2DF:
+    case RS6000_BIF_STXVD2X_V2DI:
+      return true;
+    default:
+      return false;
     }
-
-  /* Expand the HTM builtins.  */
-  d = bdesc_htm;
-  for (i = 0; i < ARRAY_SIZE (bdesc_htm); i++, d++)
-    if (d->code == fcode)
-      {
-	rtx op[MAX_HTM_OPERANDS], pat;
-	int nopnds = 0;
-	tree arg;
-	call_expr_arg_iterator iter;
-	unsigned attr = rs6000_builtin_info[fcode].attr;
-	enum insn_code icode = d->icode;
-	const struct insn_operand_data *insn_op;
-	bool uses_spr = (attr & RS6000_BTC_SPR);
-	rtx cr = NULL_RTX;
-
-	if (uses_spr)
-	  icode = rs6000_htm_spr_icode (nonvoid);
-	insn_op = &insn_data[icode].operand[0];
-
-	if (nonvoid)
-	  {
-	    machine_mode tmode = (uses_spr) ? insn_op->mode : E_SImode;
-	    if (!target
-		|| GET_MODE (target) != tmode
-		|| (uses_spr && !(*insn_op->predicate) (target, tmode)))
-	      target = gen_reg_rtx (tmode);
-	    if (uses_spr)
-	      op[nopnds++] = target;
-	  }
-
-	FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
-	{
-	  if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS)
-	    return const0_rtx;
-
-	  insn_op = &insn_data[icode].operand[nopnds];
-
-	  op[nopnds] = expand_normal (arg);
-
-	  if (!(*insn_op->predicate) (op[nopnds], insn_op->mode))
-	    {
-	      if (!strcmp (insn_op->constraint, "n"))
-		{
-		  int arg_num = (nonvoid) ? nopnds : nopnds + 1;
-		  if (!CONST_INT_P (op[nopnds]))
-		    error ("argument %d must be an unsigned literal", arg_num);
-		  else
-		    error ("argument %d is an unsigned literal that is "
-			   "out of range", arg_num);
-		  return const0_rtx;
-		}
-	      op[nopnds] = copy_to_mode_reg (insn_op->mode, op[nopnds]);
-	    }
-
-	  nopnds++;
-	}
-
-	/* Handle the builtins for extended mnemonics.  These accept
-	   no arguments, but map to builtins that take arguments.  */
-	switch (fcode)
-	  {
-	  case HTM_BUILTIN_TENDALL:  /* Alias for: tend. 1  */
-	  case HTM_BUILTIN_TRESUME:  /* Alias for: tsr. 1  */
-	    op[nopnds++] = GEN_INT (1);
-	    if (flag_checking)
-	      attr |= RS6000_BTC_UNARY;
-	    break;
-	  case HTM_BUILTIN_TSUSPEND: /* Alias for: tsr. 0  */
-	    op[nopnds++] = GEN_INT (0);
-	    if (flag_checking)
-	      attr |= RS6000_BTC_UNARY;
-	    break;
-	  default:
-	    break;
-	  }
-
-	/* If this builtin accesses SPRs, then pass in the appropriate
-	   SPR number and SPR regno as the last two operands.  */
-	if (uses_spr)
-	  {
-	    machine_mode mode = (TARGET_POWERPC64) ? DImode : SImode;
-	    op[nopnds++] = gen_rtx_CONST_INT (mode, htm_spr_num (fcode));
-	  }
-	/* If this builtin accesses a CR, then pass in a scratch
-	   CR as the last operand.  */
-	else if (attr & RS6000_BTC_CR)
-	  { cr = gen_reg_rtx (CCmode);
-	    op[nopnds++] = cr;
-	  }
-
-	if (flag_checking)
-	  {
-	    int expected_nopnds = 0;
-	    if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_UNARY)
-	      expected_nopnds = 1;
-	    else if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_BINARY)
-	      expected_nopnds = 2;
-	    else if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_TERNARY)
-	      expected_nopnds = 3;
-	    else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_QUATERNARY)
-	      expected_nopnds = 4;
-	    if (!(attr & RS6000_BTC_VOID))
-	      expected_nopnds += 1;
-	    if (uses_spr)
-	      expected_nopnds += 1;
-
-	    gcc_assert (nopnds == expected_nopnds
-			&& nopnds <= MAX_HTM_OPERANDS);
-	  }
-
-	switch (nopnds)
-	  {
-	  case 1:
-	    pat = GEN_FCN (icode) (op[0]);
-	    break;
-	  case 2:
-	    pat = GEN_FCN (icode) (op[0], op[1]);
-	    break;
-	  case 3:
-	    pat = GEN_FCN (icode) (op[0], op[1], op[2]);
-	    break;
-	  case 4:
-	    pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
-	    break;
-	  default:
-	    gcc_unreachable ();
-	  }
-	if (!pat)
-	  return NULL_RTX;
-	emit_insn (pat);
-
-	if (attr & RS6000_BTC_CR)
-	  {
-	    if (fcode == HTM_BUILTIN_TBEGIN)
-	      {
-		/* Emit code to set TARGET to true or false depending on
-		   whether the tbegin. instruction successfully or failed
-		   to start a transaction.  We do this by placing the 1's
-		   complement of CR's EQ bit into TARGET.  */
-		rtx scratch = gen_reg_rtx (SImode);
-		emit_insn (gen_rtx_SET (scratch,
-					gen_rtx_EQ (SImode, cr,
-						     const0_rtx)));
-		emit_insn (gen_rtx_SET (target,
-					gen_rtx_XOR (SImode, scratch,
-						     GEN_INT (1))));
-	      }
-	    else
-	      {
-		/* Emit code to copy the 4-bit condition register field
-		   CR into the least significant end of register TARGET.  */
-		rtx scratch1 = gen_reg_rtx (SImode);
-		rtx scratch2 = gen_reg_rtx (SImode);
-		rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0);
-		emit_insn (gen_movcc (subreg, cr));
-		emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28)));
-		emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf)));
-	      }
-	  }
-
-	if (nonvoid)
-	  return target;
-	return const0_rtx;
-      }
-
-  *expandedp = false;
-  return NULL_RTX;
 }
 
-/* Expand the CPU builtin in FCODE and store the result in TARGET.  */
+/* Check whether a builtin function is supported in this target
+   configuration.  */
+bool
+rs6000_new_builtin_is_supported (enum rs6000_gen_builtins fncode)
+{
+  switch (rs6000_builtin_info_x[(size_t) fncode].enable)
+    {
+    case ENB_ALWAYS:
+      return true;
+    case ENB_P5:
+      return TARGET_POPCNTB;
+    case ENB_P6:
+      return TARGET_CMPB;
+    case ENB_P6_64:
+      return TARGET_CMPB && TARGET_POWERPC64;
+    case ENB_P7:
+      return TARGET_POPCNTD;
+    case ENB_P7_64:
+      return TARGET_POPCNTD && TARGET_POWERPC64;
+    case ENB_P8:
+      return TARGET_DIRECT_MOVE;
+    case ENB_P8V:
+      return TARGET_P8_VECTOR;
+    case ENB_P9:
+      return TARGET_MODULO;
+    case ENB_P9_64:
+      return TARGET_MODULO && TARGET_POWERPC64;
+    case ENB_P9V:
+      return TARGET_P9_VECTOR;
+    case ENB_P10:
+      return TARGET_POWER10;
+    case ENB_P10_64:
+      return TARGET_POWER10 && TARGET_POWERPC64;
+    case ENB_ALTIVEC:
+      return TARGET_ALTIVEC;
+    case ENB_VSX:
+      return TARGET_VSX;
+    case ENB_CELL:
+      return TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL;
+    case ENB_IEEE128_HW:
+      return TARGET_FLOAT128_HW;
+    case ENB_DFP:
+      return TARGET_DFP;
+    case ENB_CRYPTO:
+      return TARGET_CRYPTO;
+    case ENB_HTM:
+      return TARGET_HTM;
+    case ENB_MMA:
+      return TARGET_MMA;
+    default:
+      gcc_unreachable ();
+    }
+  gcc_unreachable ();
+}
 
-static rtx
-cpu_expand_builtin (enum rs6000_builtins fcode, tree exp ATTRIBUTE_UNUSED,
-		    rtx target)
+/* Expand the MMA built-ins early, so that we can convert the pass-by-reference
+   __vector_quad arguments into pass-by-value arguments, leading to more
+   efficient code generation.  */
+static bool
+rs6000_gimple_fold_new_mma_builtin (gimple_stmt_iterator *gsi,
+				    rs6000_gen_builtins fn_code)
 {
-  /* __builtin_cpu_init () is a nop, so expand to nothing.  */
-  if (fcode == RS6000_BUILTIN_CPU_INIT)
-    return const0_rtx;
+  gimple *stmt = gsi_stmt (*gsi);
+  size_t fncode = (size_t) fn_code;
 
-  if (target == 0 || GET_MODE (target) != SImode)
-    target = gen_reg_rtx (SImode);
+  if (!bif_is_mma (rs6000_builtin_info_x[fncode]))
+    return false;
 
-#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
-  tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
-  /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back
-     to a STRING_CST.  */
-  if (TREE_CODE (arg) == ARRAY_REF
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST
-      && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST
-      && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0)
-    arg = TREE_OPERAND (arg, 0);
+  /* Each call that can be gimple-expanded has an associated built-in
+     function that it will expand into.  If this one doesn't, we have
+     already expanded it!  Exceptions: lxvp and stxvp.  */
+  if (rs6000_builtin_info_x[fncode].assoc_bif == RS6000_BIF_NONE
+      && fncode != RS6000_BIF_LXVP
+      && fncode != RS6000_BIF_STXVP)
+    return false;
 
-  if (TREE_CODE (arg) != STRING_CST)
-    {
-      error ("builtin %qs only accepts a string argument",
-	     rs6000_builtin_info[(size_t) fcode].name);
-      return const0_rtx;
-    }
+  bifdata *bd = &rs6000_builtin_info_x[fncode];
+  unsigned nopnds = bd->nargs;
+  gimple_seq new_seq = NULL;
+  gimple *new_call;
+  tree new_decl;
+
+  /* Compatibility built-ins; we used to call these
+     __builtin_mma_{dis,}assemble_pair, but now we call them
+     __builtin_vsx_{dis,}assemble_pair.  Handle the old versions.  */
+  if (fncode == RS6000_BIF_ASSEMBLE_PAIR)
+    fncode = RS6000_BIF_ASSEMBLE_PAIR_V;
+  else if (fncode == RS6000_BIF_DISASSEMBLE_PAIR)
+    fncode = RS6000_BIF_DISASSEMBLE_PAIR_V;
 
-  if (fcode == RS6000_BUILTIN_CPU_IS)
+  if (fncode == RS6000_BIF_DISASSEMBLE_ACC
+      || fncode == RS6000_BIF_DISASSEMBLE_PAIR_V)
     {
-      const char *cpu = TREE_STRING_POINTER (arg);
-      rtx cpuid = NULL_RTX;
-      for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++)
-	if (strcmp (cpu, cpu_is_info[i].cpu) == 0)
-	  {
-	    /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM.  */
-	    cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM);
-	    break;
-	  }
-      if (cpuid == NULL_RTX)
+      /* This is an MMA disassemble built-in function.  */
+      push_gimplify_context (true);
+      unsigned nvec = (fncode == RS6000_BIF_DISASSEMBLE_ACC) ? 4 : 2;
+      tree dst_ptr = gimple_call_arg (stmt, 0);
+      tree src_ptr = gimple_call_arg (stmt, 1);
+      tree src_type = TREE_TYPE (src_ptr);
+      tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type));
+      gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq);
+
+      /* If we are not disassembling an accumulator/pair or our destination is
+	 another accumulator/pair, then just copy the entire thing as is.  */
+      if ((fncode == RS6000_BIF_DISASSEMBLE_ACC
+	   && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node)
+	  || (fncode == RS6000_BIF_DISASSEMBLE_PAIR_V
+	      && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node))
 	{
-	  /* Invalid CPU argument.  */
-	  error ("cpu %qs is an invalid argument to builtin %qs",
-		 cpu, rs6000_builtin_info[(size_t) fcode].name);
-	  return const0_rtx;
+	  tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR,
+						   src_type, dst_ptr));
+	  gimplify_assign (dst, src, &new_seq);
+	  pop_gimplify_context (NULL);
+	  gsi_replace_with_seq (gsi, new_seq, true);
+	  return true;
 	}
 
-      rtx platform = gen_reg_rtx (SImode);
-      rtx tcbmem = gen_const_mem (SImode,
-				  gen_rtx_PLUS (Pmode,
-						gen_rtx_REG (Pmode, TLS_REGNUM),
-						GEN_INT (TCB_PLATFORM_OFFSET)));
-      emit_move_insn (platform, tcbmem);
-      emit_insn (gen_eqsi3 (target, platform, cpuid));
-    }
-  else if (fcode == RS6000_BUILTIN_CPU_SUPPORTS)
-    {
-      const char *hwcap = TREE_STRING_POINTER (arg);
-      rtx mask = NULL_RTX;
-      int hwcap_offset;
-      for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++)
-	if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0)
-	  {
-	    mask = GEN_INT (cpu_supports_info[i].mask);
-	    hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id);
-	    break;
-	  }
-      if (mask == NULL_RTX)
+      /* If we're disassembling an accumulator into a different type, we need
+	 to emit a xxmfacc instruction now, since we cannot do it later.  */
+      if (fncode == RS6000_BIF_DISASSEMBLE_ACC)
 	{
-	  /* Invalid HWCAP argument.  */
-	  error ("%s %qs is an invalid argument to builtin %qs",
-		 "hwcap", hwcap, rs6000_builtin_info[(size_t) fcode].name);
-	  return const0_rtx;
+	  new_decl = rs6000_builtin_decls_x[RS6000_BIF_XXMFACC_INTERNAL];
+	  new_call = gimple_build_call (new_decl, 1, src);
+	  src = create_tmp_reg_or_ssa_name (vector_quad_type_node);
+	  gimple_call_set_lhs (new_call, src);
+	  gimple_seq_add_stmt (&new_seq, new_call);
 	}
 
-      rtx tcb_hwcap = gen_reg_rtx (SImode);
-      rtx tcbmem = gen_const_mem (SImode,
-				  gen_rtx_PLUS (Pmode,
-						gen_rtx_REG (Pmode, TLS_REGNUM),
-						GEN_INT (hwcap_offset)));
-      emit_move_insn (tcb_hwcap, tcbmem);
-      rtx scratch1 = gen_reg_rtx (SImode);
-      emit_insn (gen_rtx_SET (scratch1, gen_rtx_AND (SImode, tcb_hwcap, mask)));
-      rtx scratch2 = gen_reg_rtx (SImode);
-      emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx));
-      emit_insn (gen_rtx_SET (target, gen_rtx_XOR (SImode, scratch2, const1_rtx)));
+      /* Copy the accumulator/pair vector by vector.  */
+      new_decl
+	= rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif];
+      tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node,
+						   ptr_mode, true);
+      tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr);
+      for (unsigned i = 0; i < nvec; i++)
+	{
+	  unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i;
+	  tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base,
+			     build_int_cst (dst_type, index * 16));
+	  tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node);
+	  new_call = gimple_build_call (new_decl, 2, src,
+					build_int_cstu (uint16_type_node, i));
+	  gimple_call_set_lhs (new_call, dstssa);
+	  gimple_seq_add_stmt (&new_seq, new_call);
+	  gimplify_assign (dst, dstssa, &new_seq);
+	}
+      pop_gimplify_context (NULL);
+      gsi_replace_with_seq (gsi, new_seq, true);
+      return true;
     }
-  else
-    gcc_unreachable ();
-
-  /* Record that we have expanded a CPU builtin, so that we can later
-     emit a reference to the special symbol exported by LIBC to ensure we
-     do not link against an old LIBC that doesn't support this feature.  */
-  cpu_builtin_p = true;
-
-#else
-  warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware "
-	   "capability bits", rs6000_builtin_info[(size_t) fcode].name);
-  
-  /* For old LIBCs, always return FALSE.  */
-  emit_move_insn (target, GEN_INT (0));
-#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */
-
-  return target;
-}
-
-static rtx
-rs6000_expand_quaternop_builtin (enum insn_code icode, tree exp, rtx target)
-{
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  tree arg2 = CALL_EXPR_ARG (exp, 2);
-  tree arg3 = CALL_EXPR_ARG (exp, 3);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  rtx op2 = expand_normal (arg2);
-  rtx op3 = expand_normal (arg3);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
-  machine_mode mode1 = insn_data[icode].operand[2].mode;
-  machine_mode mode2 = insn_data[icode].operand[3].mode;
-  machine_mode mode3 = insn_data[icode].operand[4].mode;
 
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  /* TODO: Do some factoring on these two chunks.  */
+  if (fncode == RS6000_BIF_LXVP)
+    {
+      push_gimplify_context (true);
+      tree offset = gimple_call_arg (stmt, 0);
+      tree ptr = gimple_call_arg (stmt, 1);
+      tree lhs = gimple_call_lhs (stmt);
+      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
+	ptr = build1 (VIEW_CONVERT_EXPR,
+		      build_pointer_type (vector_pair_type_node), ptr);
+      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
+					       TREE_TYPE (ptr), ptr, offset));
+      gimplify_assign (lhs, mem, &new_seq);
+      pop_gimplify_context (NULL);
+      gsi_replace_with_seq (gsi, new_seq, true);
+      return true;
+    }
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node
-      || arg1 == error_mark_node
-      || arg2 == error_mark_node
-      || arg3 == error_mark_node)
-    return const0_rtx;
+  if (fncode == RS6000_BIF_STXVP)
+    {
+      push_gimplify_context (true);
+      tree src = gimple_call_arg (stmt, 0);
+      tree offset = gimple_call_arg (stmt, 1);
+      tree ptr = gimple_call_arg (stmt, 2);
+      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
+	ptr = build1 (VIEW_CONVERT_EXPR,
+		      build_pointer_type (vector_pair_type_node), ptr);
+      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
+					       TREE_TYPE (ptr), ptr, offset));
+      gimplify_assign (mem, src, &new_seq);
+      pop_gimplify_context (NULL);
+      gsi_replace_with_seq (gsi, new_seq, true);
+      return true;
+    }
 
-  /* Check and prepare argument depending on the instruction code.
+  /* Convert this built-in into an internal version that uses pass-by-value
+     arguments.  The internal built-in is found in the assoc_bif field.  */
+  new_decl = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif];
+  tree lhs, op[MAX_MMA_OPERANDS];
+  tree acc = gimple_call_arg (stmt, 0);
+  push_gimplify_context (true);
 
-     Note that a switch statement instead of the sequence of tests
-     would be incorrect as many of the CODE_FOR values could be
-     CODE_FOR_nothing and that would yield multiple alternatives
-     with identical values.  We'd never reach here at runtime in
-     this case.  */
-  if (icode == CODE_FOR_xxeval)
+  if (bif_is_quad (*bd))
     {
-      /* Only allow 8-bit unsigned literals.  */
-      STRIP_NOPS (arg3);
-      if (TREE_CODE (arg3) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg3) & ~0xff)
-	{
-	  error ("argument 4 must be an 8-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
+      /* This built-in has a pass-by-reference accumulator input, so load it
+	 into a temporary accumulator for use as a pass-by-value input.  */
+      op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node);
+      for (unsigned i = 1; i < nopnds; i++)
+	op[i] = gimple_call_arg (stmt, i);
+      gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq);
+    }
+  else
+    {
+      /* This built-in does not use its pass-by-reference accumulator argument
+	 as an input argument, so remove it from the input list.  */
+      nopnds--;
+      for (unsigned i = 0; i < nopnds; i++)
+	op[i] = gimple_call_arg (stmt, i + 1);
     }
 
-  else if (icode == CODE_FOR_xxpermx)
+  switch (nopnds)
     {
-      /* Only allow 3-bit unsigned literals.  */
-      STRIP_NOPS (arg3);
-      if (TREE_CODE (arg3) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg3) & ~0x7)
-	{
-	  error ("argument 4 must be a 3-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
+    case 0:
+      new_call = gimple_build_call (new_decl, 0);
+      break;
+    case 1:
+      new_call = gimple_build_call (new_decl, 1, op[0]);
+      break;
+    case 2:
+      new_call = gimple_build_call (new_decl, 2, op[0], op[1]);
+      break;
+    case 3:
+      new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]);
+      break;
+    case 4:
+      new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]);
+      break;
+    case 5:
+      new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3],
+				    op[4]);
+      break;
+    case 6:
+      new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3],
+				    op[4], op[5]);
+      break;
+    case 7:
+      new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3],
+				    op[4], op[5], op[6]);
+      break;
+    default:
+      gcc_unreachable ();
     }
 
-  else if (icode == CODE_FOR_vreplace_elt_v4si
-	   || icode == CODE_FOR_vreplace_elt_v4sf)
-   {
-     /* Check whether the 3rd argument is an integer constant in the range
-	0 to 3 inclusive.  */
-     STRIP_NOPS (arg2);
-     if (TREE_CODE (arg2) != INTEGER_CST
-	 || !IN_RANGE (TREE_INT_CST_LOW (arg2), 0, 3))
-	{
-	  error ("argument 3 must be in the range 0 to 3");
-	  return CONST0_RTX (tmode);
-	}
-   }
-
-  else if (icode == CODE_FOR_vreplace_un_v4si
-	   || icode == CODE_FOR_vreplace_un_v4sf)
-   {
-     /* Check whether the 3rd argument is an integer constant in the range
-	0 to 12 inclusive.  */
-     STRIP_NOPS (arg2);
-     if (TREE_CODE (arg2) != INTEGER_CST
-	 || !IN_RANGE(TREE_INT_CST_LOW (arg2), 0, 12))
-	{
-	  error ("argument 3 must be in the range 0 to 12");
-	  return CONST0_RTX (tmode);
-	}
-   }
-
-  else if (icode == CODE_FOR_vsldb_v16qi
-	   || icode == CODE_FOR_vsldb_v8hi
-	   || icode == CODE_FOR_vsldb_v4si
-	   || icode == CODE_FOR_vsldb_v2di
-	   || icode == CODE_FOR_vsrdb_v16qi
-	   || icode == CODE_FOR_vsrdb_v8hi
-	   || icode == CODE_FOR_vsrdb_v4si
-	   || icode == CODE_FOR_vsrdb_v2di)
-   {
-     /* Check whether the 3rd argument is an integer constant in the range
-	0 to 7 inclusive.  */
-     STRIP_NOPS (arg2);
-     if (TREE_CODE (arg2) != INTEGER_CST
-	 || !IN_RANGE (TREE_INT_CST_LOW (arg2), 0, 7))
-	{
-	  error ("argument 3 must be a constant in the range 0 to 7");
-	  return CONST0_RTX (tmode);
-	}
-   }
+  if (fncode == RS6000_BIF_BUILD_PAIR || fncode == RS6000_BIF_ASSEMBLE_PAIR_V)
+    lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node);
+  else
+    lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node);
+  gimple_call_set_lhs (new_call, lhs);
+  gimple_seq_add_stmt (&new_seq, new_call);
+  gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq);
+  pop_gimplify_context (NULL);
+  gsi_replace_with_seq (gsi, new_seq, true);
 
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
+  return true;
+}
 
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
-  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
-    op2 = copy_to_mode_reg (mode2, op2);
-  if (! (*insn_data[icode].operand[4].predicate) (op3, mode3))
-    op3 = copy_to_mode_reg (mode3, op3);
+/* Fold a machine-dependent built-in in GIMPLE.  (For folding into
+   a constant, use rs6000_fold_builtin.)  */
+static bool
+rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree fndecl = gimple_call_fndecl (stmt);
+  gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD);
+  enum rs6000_gen_builtins fn_code
+    = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
+  tree arg0, arg1, lhs, temp;
+  enum tree_code bcode;
+  gimple *g;
 
-  pat = GEN_FCN (icode) (target, op0, op1, op2, op3);
-  if (! pat)
-    return 0;
-  emit_insn (pat);
+  size_t uns_fncode = (size_t) fn_code;
+  enum insn_code icode = rs6000_builtin_info_x[uns_fncode].icode;
+  const char *fn_name1 = rs6000_builtin_info_x[uns_fncode].bifname;
+  const char *fn_name2 = (icode != CODE_FOR_nothing)
+			  ? get_insn_name ((int) icode)
+			  : "nothing";
 
-  return target;
-}
+  if (TARGET_DEBUG_BUILTIN)
+      fprintf (stderr, "rs6000_gimple_fold_new_builtin %d %s %s\n",
+	       fn_code, fn_name1, fn_name2);
 
-static rtx
-rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
-{
-  rtx pat;
-  tree arg0 = CALL_EXPR_ARG (exp, 0);
-  tree arg1 = CALL_EXPR_ARG (exp, 1);
-  tree arg2 = CALL_EXPR_ARG (exp, 2);
-  rtx op0 = expand_normal (arg0);
-  rtx op1 = expand_normal (arg1);
-  rtx op2 = expand_normal (arg2);
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
-  machine_mode mode1 = insn_data[icode].operand[2].mode;
-  machine_mode mode2 = insn_data[icode].operand[3].mode;
+  if (!rs6000_fold_gimple)
+    return false;
 
-  if (icode == CODE_FOR_nothing)
-    /* Builtin not supported on this processor.  */
-    return 0;
+  /* Prevent gimple folding for code that does not have a LHS, unless it is
+     allowed per the rs6000_new_builtin_valid_without_lhs helper function.  */
+  if (!gimple_call_lhs (stmt)
+      && !rs6000_new_builtin_valid_without_lhs (fn_code, fndecl))
+    return false;
 
-  /* If we got invalid arguments bail out before generating bad rtl.  */
-  if (arg0 == error_mark_node
-      || arg1 == error_mark_node
-      || arg2 == error_mark_node)
-    return const0_rtx;
+  /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it.  */
+  if (!rs6000_new_builtin_is_supported (fn_code))
+    return false;
 
-  /* Check and prepare argument depending on the instruction code.
-
-     Note that a switch statement instead of the sequence of tests
-     would be incorrect as many of the CODE_FOR values could be
-     CODE_FOR_nothing and that would yield multiple alternatives
-     with identical values.  We'd never reach here at runtime in
-     this case.  */
-  if (icode == CODE_FOR_altivec_vsldoi_v4sf
-      || icode == CODE_FOR_altivec_vsldoi_v2df
-      || icode == CODE_FOR_altivec_vsldoi_v4si
-      || icode == CODE_FOR_altivec_vsldoi_v8hi
-      || icode == CODE_FOR_altivec_vsldoi_v16qi)
-    {
-      /* Only allow 4-bit unsigned literals.  */
-      STRIP_NOPS (arg2);
-      if (TREE_CODE (arg2) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg2) & ~0xf)
-	{
-	  error ("argument 3 must be a 4-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_vsx_xxpermdi_v2df
-           || icode == CODE_FOR_vsx_xxpermdi_v2di
-           || icode == CODE_FOR_vsx_xxpermdi_v2df_be
-           || icode == CODE_FOR_vsx_xxpermdi_v2di_be
-           || icode == CODE_FOR_vsx_xxpermdi_v1ti
-           || icode == CODE_FOR_vsx_xxpermdi_v4sf
-           || icode == CODE_FOR_vsx_xxpermdi_v4si
-           || icode == CODE_FOR_vsx_xxpermdi_v8hi
-           || icode == CODE_FOR_vsx_xxpermdi_v16qi
-           || icode == CODE_FOR_vsx_xxsldwi_v16qi
-           || icode == CODE_FOR_vsx_xxsldwi_v8hi
-           || icode == CODE_FOR_vsx_xxsldwi_v4si
-           || icode == CODE_FOR_vsx_xxsldwi_v4sf
-           || icode == CODE_FOR_vsx_xxsldwi_v2di
-           || icode == CODE_FOR_vsx_xxsldwi_v2df)
+  if (rs6000_gimple_fold_new_mma_builtin (gsi, fn_code))
+    return true;
+
+  switch (fn_code)
     {
-      /* Only allow 2-bit unsigned literals.  */
-      STRIP_NOPS (arg2);
-      if (TREE_CODE (arg2) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg2) & ~0x3)
+    /* Flavors of vec_add.  We deliberately don't expand
+       RS6000_BIF_VADDUQM as it gets lowered from V1TImode to
+       TImode, resulting in much poorer code generation.  */
+    case RS6000_BIF_VADDUBM:
+    case RS6000_BIF_VADDUHM:
+    case RS6000_BIF_VADDUWM:
+    case RS6000_BIF_VADDUDM:
+    case RS6000_BIF_VADDFP:
+    case RS6000_BIF_XVADDDP:
+    case RS6000_BIF_XVADDSP:
+      bcode = PLUS_EXPR;
+    do_binary:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs)))
+	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs))))
 	{
-	  error ("argument 3 must be a 2-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_vsx_set_v2df
-           || icode == CODE_FOR_vsx_set_v2di
-	   || icode == CODE_FOR_bcdadd_v16qi
-	   || icode == CODE_FOR_bcdadd_v1ti
-	   || icode == CODE_FOR_bcdadd_lt_v16qi
-	   || icode == CODE_FOR_bcdadd_lt_v1ti
-	   || icode == CODE_FOR_bcdadd_eq_v16qi
-	   || icode == CODE_FOR_bcdadd_eq_v1ti
-	   || icode == CODE_FOR_bcdadd_gt_v16qi
-	   || icode == CODE_FOR_bcdadd_gt_v1ti
-	   || icode == CODE_FOR_bcdsub_v16qi
-	   || icode == CODE_FOR_bcdsub_v1ti
-	   || icode == CODE_FOR_bcdsub_lt_v16qi
-	   || icode == CODE_FOR_bcdsub_lt_v1ti
-	   || icode == CODE_FOR_bcdsub_eq_v16qi
-	   || icode == CODE_FOR_bcdsub_eq_v1ti
-	   || icode == CODE_FOR_bcdsub_gt_v16qi
-	   || icode == CODE_FOR_bcdsub_gt_v1ti)
-    {
-      /* Only allow 1-bit unsigned literals.  */
-      STRIP_NOPS (arg2);
-      if (TREE_CODE (arg2) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg2) & ~0x1)
-	{
-	  error ("argument 3 must be a 1-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_dfp_ddedpd_dd
-           || icode == CODE_FOR_dfp_ddedpd_td)
-    {
-      /* Only allow 2-bit unsigned literals where the value is 0 or 2.  */
-      STRIP_NOPS (arg0);
-      if (TREE_CODE (arg0) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg2) & ~0x3)
-	{
-	  error ("argument 1 must be 0 or 2");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_dfp_denbcd_dd
-	   || icode == CODE_FOR_dfp_denbcd_td
-	   || icode == CODE_FOR_dfp_denbcd_v16qi)
-    {
-      /* Only allow 1-bit unsigned literals.  */
-      STRIP_NOPS (arg0);
-      if (TREE_CODE (arg0) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg0) & ~0x1)
-	{
-	  error ("argument 1 must be a 1-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_dfp_dscli_dd
-           || icode == CODE_FOR_dfp_dscli_td
-	   || icode == CODE_FOR_dfp_dscri_dd
-	   || icode == CODE_FOR_dfp_dscri_td)
-    {
-      /* Only allow 6-bit unsigned literals.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg1) & ~0x3f)
-	{
-	  error ("argument 2 must be a 6-bit unsigned literal");
-	  return CONST0_RTX (tmode);
-	}
-    }
-  else if (icode == CODE_FOR_crypto_vshasigmaw
-	   || icode == CODE_FOR_crypto_vshasigmad)
-    {
-      /* Check whether the 2nd and 3rd arguments are integer constants and in
-	 range and prepare arguments.  */
-      STRIP_NOPS (arg1);
-      if (TREE_CODE (arg1) != INTEGER_CST || wi::geu_p (wi::to_wide (arg1), 2))
-	{
-	  error ("argument 2 must be 0 or 1");
-	  return CONST0_RTX (tmode);
-	}
-
-      STRIP_NOPS (arg2);
-      if (TREE_CODE (arg2) != INTEGER_CST
-	  || wi::geu_p (wi::to_wide (arg2), 16))
-	{
-	  error ("argument 3 must be in the range [0, 15]");
-	  return CONST0_RTX (tmode);
-	}
-    }
-
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
-  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
-    op2 = copy_to_mode_reg (mode2, op2);
-
-  pat = GEN_FCN (icode) (target, op0, op1, op2);
-  if (! pat)
-    return 0;
-  emit_insn (pat);
-
-  return target;
-}
-
-
-/* Expand the dst builtins.  */
-static rtx
-altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
-			    bool *expandedp)
-{
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  enum rs6000_builtins fcode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  tree arg0, arg1, arg2;
-  machine_mode mode0, mode1;
-  rtx pat, op0, op1, op2;
-  const struct builtin_description *d;
-  size_t i;
-
-  *expandedp = false;
-
-  /* Handle DST variants.  */
-  d = bdesc_dst;
-  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
-    if (d->code == fcode)
-      {
-	arg0 = CALL_EXPR_ARG (exp, 0);
-	arg1 = CALL_EXPR_ARG (exp, 1);
-	arg2 = CALL_EXPR_ARG (exp, 2);
-	op0 = expand_normal (arg0);
-	op1 = expand_normal (arg1);
-	op2 = expand_normal (arg2);
-	mode0 = insn_data[d->icode].operand[0].mode;
-	mode1 = insn_data[d->icode].operand[1].mode;
-
-	/* Invalid arguments, bail out before generating bad rtl.  */
-	if (arg0 == error_mark_node
-	    || arg1 == error_mark_node
-	    || arg2 == error_mark_node)
-	  return const0_rtx;
-
-	*expandedp = true;
-	STRIP_NOPS (arg2);
-	if (TREE_CODE (arg2) != INTEGER_CST
-	    || TREE_INT_CST_LOW (arg2) & ~0x3)
-	  {
-	    error ("argument to %qs must be a 2-bit unsigned literal", d->name);
-	    return const0_rtx;
-	  }
-
-	if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
-	  op0 = copy_to_mode_reg (Pmode, op0);
-	if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
-	  op1 = copy_to_mode_reg (mode1, op1);
-
-	pat = GEN_FCN (d->icode) (op0, op1, op2);
-	if (pat != 0)
-	  emit_insn (pat);
-
-	return NULL_RTX;
-      }
-
-  return NULL_RTX;
-}
-
-/* Expand vec_init builtin.  */
-static rtx
-altivec_expand_vec_init_builtin (tree type, tree exp, rtx target)
-{
-  machine_mode tmode = TYPE_MODE (type);
-  machine_mode inner_mode = GET_MODE_INNER (tmode);
-  int i, n_elt = GET_MODE_NUNITS (tmode);
-
-  gcc_assert (VECTOR_MODE_P (tmode));
-  gcc_assert (n_elt == call_expr_nargs (exp));
-
-  if (!target || !register_operand (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  /* If we have a vector compromised of a single element, such as V1TImode, do
-     the initialization directly.  */
-  if (n_elt == 1 && GET_MODE_SIZE (tmode) == GET_MODE_SIZE (inner_mode))
-    {
-      rtx x = expand_normal (CALL_EXPR_ARG (exp, 0));
-      emit_move_insn (target, gen_lowpart (tmode, x));
-    }
-  else
-    {
-      rtvec v = rtvec_alloc (n_elt);
-
-      for (i = 0; i < n_elt; ++i)
-	{
-	  rtx x = expand_normal (CALL_EXPR_ARG (exp, i));
-	  RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
+	  /* Ensure the binary operation is performed in a type
+	     that wraps if it is integral type.  */
+	  gimple_seq stmts = NULL;
+	  tree type = unsigned_type_for (TREE_TYPE (lhs));
+	  tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+				     type, arg0);
+	  tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+				     type, arg1);
+	  tree res = gimple_build (&stmts, gimple_location (stmt), bcode,
+				   type, uarg0, uarg1);
+	  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	  g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR,
+				   build1 (VIEW_CONVERT_EXPR,
+					   TREE_TYPE (lhs), res));
+	  gsi_replace (gsi, g, true);
+	  return true;
 	}
-
-      rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v));
-    }
-
-  return target;
-}
-
-/* Return the integer constant in ARG.  Constrain it to be in the range
-   of the subparts of VEC_TYPE; issue an error if not.  */
-
-static int
-get_element_number (tree vec_type, tree arg)
-{
-  unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1;
-
-  if (!tree_fits_uhwi_p (arg)
-      || (elt = tree_to_uhwi (arg), elt > max))
-    {
-      error ("selector must be an integer constant in the range [0, %wi]", max);
-      return 0;
-    }
-
-  return elt;
-}
-
-/* Expand vec_set builtin.  */
-static rtx
-altivec_expand_vec_set_builtin (tree exp)
-{
-  machine_mode tmode, mode1;
-  tree arg0, arg1, arg2;
-  int elt;
-  rtx op0, op1;
-
-  arg0 = CALL_EXPR_ARG (exp, 0);
-  arg1 = CALL_EXPR_ARG (exp, 1);
-  arg2 = CALL_EXPR_ARG (exp, 2);
-
-  tmode = TYPE_MODE (TREE_TYPE (arg0));
-  mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
-  gcc_assert (VECTOR_MODE_P (tmode));
-
-  op0 = expand_expr (arg0, NULL_RTX, tmode, EXPAND_NORMAL);
-  op1 = expand_expr (arg1, NULL_RTX, mode1, EXPAND_NORMAL);
-  elt = get_element_number (TREE_TYPE (arg0), arg2);
-
-  if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
-    op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
-
-  op0 = force_reg (tmode, op0);
-  op1 = force_reg (mode1, op1);
-
-  rs6000_expand_vector_set (op0, op1, GEN_INT (elt));
-
-  return op0;
-}
-
-/* Expand vec_ext builtin.  */
-static rtx
-altivec_expand_vec_ext_builtin (tree exp, rtx target)
-{
-  machine_mode tmode, mode0;
-  tree arg0, arg1;
-  rtx op0;
-  rtx op1;
-
-  arg0 = CALL_EXPR_ARG (exp, 0);
-  arg1 = CALL_EXPR_ARG (exp, 1);
-
-  op0 = expand_normal (arg0);
-  op1 = expand_normal (arg1);
-
-  if (TREE_CODE (arg1) == INTEGER_CST)
-    {
-      unsigned HOST_WIDE_INT elt;
-      unsigned HOST_WIDE_INT size = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
-      unsigned int truncated_selector;
-      /* Even if !tree_fits_uhwi_p (arg1)), TREE_INT_CST_LOW (arg0)
-	 returns low-order bits of INTEGER_CST for modulo indexing.  */
-      elt = TREE_INT_CST_LOW (arg1);
-      truncated_selector = elt % size;
-      op1 = GEN_INT (truncated_selector);
-    }
-
-  tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
-  mode0 = TYPE_MODE (TREE_TYPE (arg0));
-  gcc_assert (VECTOR_MODE_P (mode0));
-
-  op0 = force_reg (mode0, op0);
-
-  if (optimize || !target || !register_operand (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  rs6000_expand_vector_extract (target, op0, op1);
-
-  return target;
-}
-
-/* Expand vec_sel builtin.  */
-static rtx
-altivec_expand_vec_sel_builtin (enum insn_code icode, tree exp, rtx target)
-{
-  rtx op0, op1, op2, pat;
-  tree arg0, arg1, arg2;
-
-  arg0 = CALL_EXPR_ARG (exp, 0);
-  op0 = expand_normal (arg0);
-  arg1 = CALL_EXPR_ARG (exp, 1);
-  op1 = expand_normal (arg1);
-  arg2 = CALL_EXPR_ARG (exp, 2);
-  op2 = expand_normal (arg2);
-
-  machine_mode tmode = insn_data[icode].operand[0].mode;
-  machine_mode mode0 = insn_data[icode].operand[1].mode;
-  machine_mode mode1 = insn_data[icode].operand[2].mode;
-  machine_mode mode2 = insn_data[icode].operand[3].mode;
-
-  if (target == 0 || GET_MODE (target) != tmode
-      || !(*insn_data[icode].operand[0].predicate) (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  if (!(*insn_data[icode].operand[1].predicate) (op0, mode0))
-    op0 = copy_to_mode_reg (mode0, op0);
-  if (!(*insn_data[icode].operand[2].predicate) (op1, mode1))
-    op1 = copy_to_mode_reg (mode1, op1);
-  if (!(*insn_data[icode].operand[3].predicate) (op2, mode2))
-    op2 = copy_to_mode_reg (mode2, op2);
-
-  pat = GEN_FCN (icode) (target, op0, op1, op2, op2);
-  if (pat)
-    emit_insn (pat);
-  else
-    return NULL_RTX;
-
-  return target;
-}
-
-/* Expand the builtin in EXP and store the result in TARGET.  Store
-   true in *EXPANDEDP if we found a builtin to expand.  */
-static rtx
-altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
-{
-  const struct builtin_description *d;
-  size_t i;
-  enum insn_code icode;
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  tree arg0, arg1, arg2;
-  rtx op0, pat;
-  machine_mode tmode, mode0;
-  enum rs6000_builtins fcode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-
-  if (rs6000_overloaded_builtin_p (fcode))
-    {
-      *expandedp = true;
-      error ("unresolved overload for Altivec builtin %qF", fndecl);
-
-      /* Given it is invalid, just generate a normal call.  */
-      return expand_call (exp, target, false);
-    }
-
-  target = altivec_expand_dst_builtin (exp, target, expandedp);
-  if (*expandedp)
-    return target;
-
-  *expandedp = true;
-
-  switch (fcode)
-    {
-    case ALTIVEC_BUILTIN_STVX_V2DF:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v2df, exp);
-    case ALTIVEC_BUILTIN_STVX_V2DI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v2di, exp);
-    case ALTIVEC_BUILTIN_STVX_V4SF:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v4sf, exp);
-    case ALTIVEC_BUILTIN_STVX:
-    case ALTIVEC_BUILTIN_STVX_V4SI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v4si, exp);
-    case ALTIVEC_BUILTIN_STVX_V8HI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v8hi, exp);
-    case ALTIVEC_BUILTIN_STVX_V16QI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v16qi, exp);
-    case ALTIVEC_BUILTIN_STVEBX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, exp);
-    case ALTIVEC_BUILTIN_STVEHX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, exp);
-    case ALTIVEC_BUILTIN_STVEWX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, exp);
-
-    case P10_BUILTIN_TR_STXVRBX:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrbx, exp);
-    case P10_BUILTIN_TR_STXVRHX:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrhx, exp);
-    case P10_BUILTIN_TR_STXVRWX:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrwx, exp);
-    case P10_BUILTIN_TR_STXVRDX:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrdx, exp);
-
-    case ALTIVEC_BUILTIN_STVXL_V2DF:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v2df, exp);
-    case ALTIVEC_BUILTIN_STVXL_V2DI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v2di, exp);
-    case ALTIVEC_BUILTIN_STVXL_V4SF:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v4sf, exp);
-    case ALTIVEC_BUILTIN_STVXL:
-    case ALTIVEC_BUILTIN_STVXL_V4SI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v4si, exp);
-    case ALTIVEC_BUILTIN_STVXL_V8HI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v8hi, exp);
-    case ALTIVEC_BUILTIN_STVXL_V16QI:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v16qi, exp);
-
-    case ALTIVEC_BUILTIN_STVLX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvlx, exp);
-    case ALTIVEC_BUILTIN_STVLXL:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvlxl, exp);
-    case ALTIVEC_BUILTIN_STVRX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvrx, exp);
-    case ALTIVEC_BUILTIN_STVRXL:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvrxl, exp);
-
-    case P9V_BUILTIN_STXVL:
-      return altivec_expand_stxvl_builtin (CODE_FOR_stxvl, exp);
-
-    case P9V_BUILTIN_XST_LEN_R:
-      return altivec_expand_stxvl_builtin (CODE_FOR_xst_len_r, exp);
-
-    case VSX_BUILTIN_STXVD2X_V1TI:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v1ti, exp);
-    case VSX_BUILTIN_STXVD2X_V2DF:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v2df, exp);
-    case VSX_BUILTIN_STXVD2X_V2DI:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v2di, exp);
-    case VSX_BUILTIN_STXVW4X_V4SF:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v4sf, exp);
-    case VSX_BUILTIN_STXVW4X_V4SI:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v4si, exp);
-    case VSX_BUILTIN_STXVW4X_V8HI:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v8hi, exp);
-    case VSX_BUILTIN_STXVW4X_V16QI:
-      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v16qi, exp);
-
-    /* For the following on big endian, it's ok to use any appropriate
-       unaligned-supporting store, so use a generic expander.  For
-       little-endian, the exact element-reversing instruction must
-       be used.  */
-   case VSX_BUILTIN_ST_ELEMREV_V1TI:
-     {
-        enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
-			       : CODE_FOR_vsx_st_elemrev_v1ti);
-        return altivec_expand_stv_builtin (code, exp);
-      }
-    case VSX_BUILTIN_ST_ELEMREV_V2DF:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
-			       : CODE_FOR_vsx_st_elemrev_v2df);
-	return altivec_expand_stv_builtin (code, exp);
-      }
-    case VSX_BUILTIN_ST_ELEMREV_V2DI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
-			       : CODE_FOR_vsx_st_elemrev_v2di);
-	return altivec_expand_stv_builtin (code, exp);
-      }
-    case VSX_BUILTIN_ST_ELEMREV_V4SF:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
-			       : CODE_FOR_vsx_st_elemrev_v4sf);
-	return altivec_expand_stv_builtin (code, exp);
-      }
-    case VSX_BUILTIN_ST_ELEMREV_V4SI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
-			       : CODE_FOR_vsx_st_elemrev_v4si);
-	return altivec_expand_stv_builtin (code, exp);
-      }
-    case VSX_BUILTIN_ST_ELEMREV_V8HI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
-			       : CODE_FOR_vsx_st_elemrev_v8hi);
-	return altivec_expand_stv_builtin (code, exp);
-      }
-    case VSX_BUILTIN_ST_ELEMREV_V16QI:
+      g = gimple_build_assign (lhs, bcode, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_sub.  We deliberately don't expand
+       RS6000_BIF_VSUBUQM. */
+    case RS6000_BIF_VSUBUBM:
+    case RS6000_BIF_VSUBUHM:
+    case RS6000_BIF_VSUBUWM:
+    case RS6000_BIF_VSUBUDM:
+    case RS6000_BIF_VSUBFP:
+    case RS6000_BIF_XVSUBDP:
+    case RS6000_BIF_XVSUBSP:
+      bcode = MINUS_EXPR;
+      goto do_binary;
+    case RS6000_BIF_XVMULSP:
+    case RS6000_BIF_XVMULDP:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Even element flavors of vec_mul (signed). */
+    case RS6000_BIF_VMULESB:
+    case RS6000_BIF_VMULESH:
+    case RS6000_BIF_VMULESW:
+    /* Even element flavors of vec_mul (unsigned).  */
+    case RS6000_BIF_VMULEUB:
+    case RS6000_BIF_VMULEUH:
+    case RS6000_BIF_VMULEUW:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Odd element flavors of vec_mul (signed).  */
+    case RS6000_BIF_VMULOSB:
+    case RS6000_BIF_VMULOSH:
+    case RS6000_BIF_VMULOSW:
+    /* Odd element flavors of vec_mul (unsigned). */
+    case RS6000_BIF_VMULOUB:
+    case RS6000_BIF_VMULOUH:
+    case RS6000_BIF_VMULOUW:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_div (Integer).  */
+    case RS6000_BIF_DIV_V2DI:
+    case RS6000_BIF_UDIV_V2DI:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_div (Float).  */
+    case RS6000_BIF_XVDIVSP:
+    case RS6000_BIF_XVDIVDP:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_and.  */
+    case RS6000_BIF_VAND_V16QI_UNS:
+    case RS6000_BIF_VAND_V16QI:
+    case RS6000_BIF_VAND_V8HI_UNS:
+    case RS6000_BIF_VAND_V8HI:
+    case RS6000_BIF_VAND_V4SI_UNS:
+    case RS6000_BIF_VAND_V4SI:
+    case RS6000_BIF_VAND_V2DI_UNS:
+    case RS6000_BIF_VAND_V2DI:
+    case RS6000_BIF_VAND_V4SF:
+    case RS6000_BIF_VAND_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_andc.  */
+    case RS6000_BIF_VANDC_V16QI_UNS:
+    case RS6000_BIF_VANDC_V16QI:
+    case RS6000_BIF_VANDC_V8HI_UNS:
+    case RS6000_BIF_VANDC_V8HI:
+    case RS6000_BIF_VANDC_V4SI_UNS:
+    case RS6000_BIF_VANDC_V4SI:
+    case RS6000_BIF_VANDC_V2DI_UNS:
+    case RS6000_BIF_VANDC_V2DI:
+    case RS6000_BIF_VANDC_V4SF:
+    case RS6000_BIF_VANDC_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+      g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_nand.  */
+    case RS6000_BIF_NAND_V16QI_UNS:
+    case RS6000_BIF_NAND_V16QI:
+    case RS6000_BIF_NAND_V8HI_UNS:
+    case RS6000_BIF_NAND_V8HI:
+    case RS6000_BIF_NAND_V4SI_UNS:
+    case RS6000_BIF_NAND_V4SI:
+    case RS6000_BIF_NAND_V2DI_UNS:
+    case RS6000_BIF_NAND_V2DI:
+    case RS6000_BIF_NAND_V4SF:
+    case RS6000_BIF_NAND_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+      g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_or.  */
+    case RS6000_BIF_VOR_V16QI_UNS:
+    case RS6000_BIF_VOR_V16QI:
+    case RS6000_BIF_VOR_V8HI_UNS:
+    case RS6000_BIF_VOR_V8HI:
+    case RS6000_BIF_VOR_V4SI_UNS:
+    case RS6000_BIF_VOR_V4SI:
+    case RS6000_BIF_VOR_V2DI_UNS:
+    case RS6000_BIF_VOR_V2DI:
+    case RS6000_BIF_VOR_V4SF:
+    case RS6000_BIF_VOR_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* flavors of vec_orc.  */
+    case RS6000_BIF_ORC_V16QI_UNS:
+    case RS6000_BIF_ORC_V16QI:
+    case RS6000_BIF_ORC_V8HI_UNS:
+    case RS6000_BIF_ORC_V8HI:
+    case RS6000_BIF_ORC_V4SI_UNS:
+    case RS6000_BIF_ORC_V4SI:
+    case RS6000_BIF_ORC_V2DI_UNS:
+    case RS6000_BIF_ORC_V2DI:
+    case RS6000_BIF_ORC_V4SF:
+    case RS6000_BIF_ORC_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+      g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_xor.  */
+    case RS6000_BIF_VXOR_V16QI_UNS:
+    case RS6000_BIF_VXOR_V16QI:
+    case RS6000_BIF_VXOR_V8HI_UNS:
+    case RS6000_BIF_VXOR_V8HI:
+    case RS6000_BIF_VXOR_V4SI_UNS:
+    case RS6000_BIF_VXOR_V4SI:
+    case RS6000_BIF_VXOR_V2DI_UNS:
+    case RS6000_BIF_VXOR_V2DI:
+    case RS6000_BIF_VXOR_V4SF:
+    case RS6000_BIF_VXOR_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* Flavors of vec_nor.  */
+    case RS6000_BIF_VNOR_V16QI_UNS:
+    case RS6000_BIF_VNOR_V16QI:
+    case RS6000_BIF_VNOR_V8HI_UNS:
+    case RS6000_BIF_VNOR_V8HI:
+    case RS6000_BIF_VNOR_V4SI_UNS:
+    case RS6000_BIF_VNOR_V4SI:
+    case RS6000_BIF_VNOR_V2DI_UNS:
+    case RS6000_BIF_VNOR_V2DI:
+    case RS6000_BIF_VNOR_V4SF:
+    case RS6000_BIF_VNOR_V2DF:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+      g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* flavors of vec_abs.  */
+    case RS6000_BIF_ABS_V16QI:
+    case RS6000_BIF_ABS_V8HI:
+    case RS6000_BIF_ABS_V4SI:
+    case RS6000_BIF_ABS_V4SF:
+    case RS6000_BIF_ABS_V2DI:
+    case RS6000_BIF_XVABSDP:
+    case RS6000_BIF_XVABSSP:
+      arg0 = gimple_call_arg (stmt, 0);
+      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0)))
+	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0))))
+	return false;
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, ABS_EXPR, arg0);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* flavors of vec_min.  */
+    case RS6000_BIF_XVMINDP:
+    case RS6000_BIF_XVMINSP:
+    case RS6000_BIF_VMINFP:
       {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
-			       : CODE_FOR_vsx_st_elemrev_v16qi);
-	return altivec_expand_stv_builtin (code, exp);
+	lhs = gimple_call_lhs (stmt);
+	tree type = TREE_TYPE (lhs);
+	if (HONOR_NANS (type))
+	  return false;
+	gcc_fallthrough ();
       }
-
-    case ALTIVEC_BUILTIN_MFVSCR:
-      icode = CODE_FOR_altivec_mfvscr;
-      tmode = insn_data[icode].operand[0].mode;
-
-      if (target == 0
-	  || GET_MODE (target) != tmode
-	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-	target = gen_reg_rtx (tmode);
-
-      pat = GEN_FCN (icode) (target);
-      if (! pat)
-	return 0;
-      emit_insn (pat);
-      return target;
-
-    case ALTIVEC_BUILTIN_MTVSCR:
-      icode = CODE_FOR_altivec_mtvscr;
-      arg0 = CALL_EXPR_ARG (exp, 0);
-      op0 = expand_normal (arg0);
-      mode0 = insn_data[icode].operand[0].mode;
-
-      /* If we got invalid arguments bail out before generating bad rtl.  */
-      if (arg0 == error_mark_node)
-	return const0_rtx;
-
-      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-	op0 = copy_to_mode_reg (mode0, op0);
-
-      pat = GEN_FCN (icode) (op0);
-      if (pat)
-	emit_insn (pat);
-      return NULL_RTX;
-
-    case ALTIVEC_BUILTIN_VSEL_2DF:
-      return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv2df, exp,
-					     target);
-    case ALTIVEC_BUILTIN_VSEL_2DI:
-    case ALTIVEC_BUILTIN_VSEL_2DI_UNS:
-      return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv2di, exp,
-					     target);
-    case ALTIVEC_BUILTIN_VSEL_4SF:
-      return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv4sf, exp,
-					     target);
-    case ALTIVEC_BUILTIN_VSEL_4SI:
-    case ALTIVEC_BUILTIN_VSEL_4SI_UNS:
-      return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv4si, exp,
-					     target);
-    case ALTIVEC_BUILTIN_VSEL_8HI:
-    case ALTIVEC_BUILTIN_VSEL_8HI_UNS:
-      return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv8hi, exp,
-					     target);
-    case ALTIVEC_BUILTIN_VSEL_16QI:
-    case ALTIVEC_BUILTIN_VSEL_16QI_UNS:
-      return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv16qi, exp,
-					     target);
-
-    case ALTIVEC_BUILTIN_DSSALL:
-      emit_insn (gen_altivec_dssall ());
-      return NULL_RTX;
-
-    case ALTIVEC_BUILTIN_DSS:
-      icode = CODE_FOR_altivec_dss;
-      arg0 = CALL_EXPR_ARG (exp, 0);
-      STRIP_NOPS (arg0);
-      op0 = expand_normal (arg0);
-      mode0 = insn_data[icode].operand[0].mode;
-
-      /* If we got invalid arguments bail out before generating bad rtl.  */
-      if (arg0 == error_mark_node)
-	return const0_rtx;
-
-      if (TREE_CODE (arg0) != INTEGER_CST
-	  || TREE_INT_CST_LOW (arg0) & ~0x3)
-	{
-	  error ("argument to %qs must be a 2-bit unsigned literal", "dss");
-	  return const0_rtx;
-	}
-
-      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-	op0 = copy_to_mode_reg (mode0, op0);
-
-      emit_insn (gen_altivec_dss (op0));
-      return NULL_RTX;
-
-    case ALTIVEC_BUILTIN_VEC_INIT_V4SI:
-    case ALTIVEC_BUILTIN_VEC_INIT_V8HI:
-    case ALTIVEC_BUILTIN_VEC_INIT_V16QI:
-    case ALTIVEC_BUILTIN_VEC_INIT_V4SF:
-    case VSX_BUILTIN_VEC_INIT_V2DF:
-    case VSX_BUILTIN_VEC_INIT_V2DI:
-    case VSX_BUILTIN_VEC_INIT_V1TI:
-      return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
-
-    case ALTIVEC_BUILTIN_VEC_SET_V4SI:
-    case ALTIVEC_BUILTIN_VEC_SET_V8HI:
-    case ALTIVEC_BUILTIN_VEC_SET_V16QI:
-    case ALTIVEC_BUILTIN_VEC_SET_V4SF:
-    case VSX_BUILTIN_VEC_SET_V2DF:
-    case VSX_BUILTIN_VEC_SET_V2DI:
-    case VSX_BUILTIN_VEC_SET_V1TI:
-      return altivec_expand_vec_set_builtin (exp);
-
-    case ALTIVEC_BUILTIN_VEC_EXT_V4SI:
-    case ALTIVEC_BUILTIN_VEC_EXT_V8HI:
-    case ALTIVEC_BUILTIN_VEC_EXT_V16QI:
-    case ALTIVEC_BUILTIN_VEC_EXT_V4SF:
-    case VSX_BUILTIN_VEC_EXT_V2DF:
-    case VSX_BUILTIN_VEC_EXT_V2DI:
-    case VSX_BUILTIN_VEC_EXT_V1TI:
-      return altivec_expand_vec_ext_builtin (exp, target);
-
-    case P9V_BUILTIN_VEC_EXTRACT4B:
-      arg1 = CALL_EXPR_ARG (exp, 1);
-      STRIP_NOPS (arg1);
-
-      /* Generate a normal call if it is invalid.  */
-      if (arg1 == error_mark_node)
-	return expand_call (exp, target, false);
-
-      if (TREE_CODE (arg1) != INTEGER_CST || TREE_INT_CST_LOW (arg1) > 12)
-	{
-	  error ("second argument to %qs must be [0, 12]", "vec_vextract4b");
-	  return expand_call (exp, target, false);
-	}
-      break;
-
-    case P9V_BUILTIN_VEC_INSERT4B:
-      arg2 = CALL_EXPR_ARG (exp, 2);
-      STRIP_NOPS (arg2);
-
-      /* Generate a normal call if it is invalid.  */
-      if (arg2 == error_mark_node)
-	return expand_call (exp, target, false);
-
-      if (TREE_CODE (arg2) != INTEGER_CST || TREE_INT_CST_LOW (arg2) > 12)
-	{
-	  error ("third argument to %qs must be [0, 12]", "vec_vinsert4b");
-	  return expand_call (exp, target, false);
-	}
-      break;
-
-    case P10_BUILTIN_VEC_XXGENPCVM:
-      arg1 = CALL_EXPR_ARG (exp, 1);
-      STRIP_NOPS (arg1);
-
-      /* Generate a normal call if it is invalid.  */
-      if (arg1 == error_mark_node)
-	return expand_call (exp, target, false);
-
-      if (TREE_CODE (arg1) != INTEGER_CST
-	  || !IN_RANGE (TREE_INT_CST_LOW (arg1), 0, 3))
-	{
-	  size_t uns_fcode = (size_t) fcode;
-	  const char *name = rs6000_builtin_info[uns_fcode].name;
-	  error ("Second argument of %qs must be in the range [0, 3].", name);
-	  return expand_call (exp, target, false);
-	}
-      break;
-
-    default:
-      break;
-      /* Fall through.  */
-    }
-
-  /* Expand abs* operations.  */
-  d = bdesc_abs;
-  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
-    if (d->code == fcode)
-      return altivec_expand_abs_builtin (d->icode, exp, target);
-
-  /* Expand the AltiVec predicates.  */
-  d = bdesc_altivec_preds;
-  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, d++)
-    if (d->code == fcode)
-      return altivec_expand_predicate_builtin (d->icode, exp, target);
-
-  /* LV* are funky.  We initialized them differently.  */
-  switch (fcode)
-    {
-    case ALTIVEC_BUILTIN_LVSL:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVSR:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVEBX:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVEHX:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVEWX:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
-					exp, target, false);
-    case P10_BUILTIN_SE_LXVRBX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrbx,
-					exp, target, false, true);
-    case P10_BUILTIN_SE_LXVRHX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrhx,
-					exp, target, false, true);
-    case P10_BUILTIN_SE_LXVRWX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrwx,
-					exp, target, false, true);
-    case P10_BUILTIN_SE_LXVRDX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrdx,
-					exp, target, false, true);
-    case P10_BUILTIN_ZE_LXVRBX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrbx,
-					exp, target, false, false);
-    case P10_BUILTIN_ZE_LXVRHX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrhx,
-					exp, target, false, false);
-    case P10_BUILTIN_ZE_LXVRWX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrwx,
-					exp, target, false, false);
-    case P10_BUILTIN_ZE_LXVRDX:
-      return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrdx,
-					exp, target, false, false);
-    case ALTIVEC_BUILTIN_LVXL_V2DF:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v2df,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVXL_V2DI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v2di,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVXL_V4SF:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v4sf,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVXL:
-    case ALTIVEC_BUILTIN_LVXL_V4SI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v4si,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVXL_V8HI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v8hi,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVXL_V16QI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v16qi,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX_V1TI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v1ti,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX_V2DF:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v2df,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX_V2DI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v2di,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX_V4SF:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v4sf,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX:
-    case ALTIVEC_BUILTIN_LVX_V4SI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v4si,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX_V8HI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v8hi,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVX_V16QI:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v16qi,
-					exp, target, false);
-    case ALTIVEC_BUILTIN_LVLX:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvlx,
-					exp, target, true);
-    case ALTIVEC_BUILTIN_LVLXL:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvlxl,
-					exp, target, true);
-    case ALTIVEC_BUILTIN_LVRX:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvrx,
-					exp, target, true);
-    case ALTIVEC_BUILTIN_LVRXL:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvrxl,
-					exp, target, true);
-    case VSX_BUILTIN_LXVD2X_V1TI:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v1ti,
-					exp, target, false);
-    case VSX_BUILTIN_LXVD2X_V2DF:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v2df,
-					exp, target, false);
-    case VSX_BUILTIN_LXVD2X_V2DI:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v2di,
-					exp, target, false);
-    case VSX_BUILTIN_LXVW4X_V4SF:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v4sf,
-					exp, target, false);
-    case VSX_BUILTIN_LXVW4X_V4SI:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v4si,
-					exp, target, false);
-    case VSX_BUILTIN_LXVW4X_V8HI:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v8hi,
-					exp, target, false);
-    case VSX_BUILTIN_LXVW4X_V16QI:
-      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v16qi,
-					exp, target, false);
-    /* For the following on big endian, it's ok to use any appropriate
-       unaligned-supporting load, so use a generic expander.  For
-       little-endian, the exact element-reversing instruction must
-       be used.  */
-    case VSX_BUILTIN_LD_ELEMREV_V2DF:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
-			       : CODE_FOR_vsx_ld_elemrev_v2df);
-	return altivec_expand_lv_builtin (code, exp, target, false);
-      }
-    case VSX_BUILTIN_LD_ELEMREV_V1TI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
-			       : CODE_FOR_vsx_ld_elemrev_v1ti);
-	return altivec_expand_lv_builtin (code, exp, target, false);
-      }
-    case VSX_BUILTIN_LD_ELEMREV_V2DI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
-			       : CODE_FOR_vsx_ld_elemrev_v2di);
-	return altivec_expand_lv_builtin (code, exp, target, false);
-      }
-    case VSX_BUILTIN_LD_ELEMREV_V4SF:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
-			       : CODE_FOR_vsx_ld_elemrev_v4sf);
-	return altivec_expand_lv_builtin (code, exp, target, false);
-      }
-    case VSX_BUILTIN_LD_ELEMREV_V4SI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
-			       : CODE_FOR_vsx_ld_elemrev_v4si);
-	return altivec_expand_lv_builtin (code, exp, target, false);
-      }
-    case VSX_BUILTIN_LD_ELEMREV_V8HI:
-      {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
-			       : CODE_FOR_vsx_ld_elemrev_v8hi);
-	return altivec_expand_lv_builtin (code, exp, target, false);
-      }
-    case VSX_BUILTIN_LD_ELEMREV_V16QI:
+    case RS6000_BIF_VMINSD:
+    case RS6000_BIF_VMINUD:
+    case RS6000_BIF_VMINSB:
+    case RS6000_BIF_VMINSH:
+    case RS6000_BIF_VMINSW:
+    case RS6000_BIF_VMINUB:
+    case RS6000_BIF_VMINUH:
+    case RS6000_BIF_VMINUW:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+    /* flavors of vec_max.  */
+    case RS6000_BIF_XVMAXDP:
+    case RS6000_BIF_XVMAXSP:
+    case RS6000_BIF_VMAXFP:
       {
-	enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
-			       : CODE_FOR_vsx_ld_elemrev_v16qi);
-	return altivec_expand_lv_builtin (code, exp, target, false);
+	lhs = gimple_call_lhs (stmt);
+	tree type = TREE_TYPE (lhs);
+	if (HONOR_NANS (type))
+	  return false;
+	gcc_fallthrough ();
       }
-      break;
-    default:
-      break;
-      /* Fall through.  */
-    }
-
-  *expandedp = false;
-  return NULL_RTX;
-}
-
-/* Check whether a builtin function is supported in this target
-   configuration.  */
-bool
-rs6000_builtin_is_supported_p (enum rs6000_builtins fncode)
-{
-  HOST_WIDE_INT fnmask = rs6000_builtin_info[fncode].mask;
-  if ((fnmask & rs6000_builtin_mask) != fnmask)
-    return false;
-  else
-    return true;
-}
-
-/* Raise an error message for a builtin function that is called without the
-   appropriate target options being set.  */
-
-static void
-rs6000_invalid_builtin (enum rs6000_builtins fncode)
-{
-  size_t uns_fncode = (size_t) fncode;
-  const char *name = rs6000_builtin_info[uns_fncode].name;
-  HOST_WIDE_INT fnmask = rs6000_builtin_info[uns_fncode].mask;
-
-  gcc_assert (name != NULL);
-  if ((fnmask & RS6000_BTM_CELL) != 0)
-    error ("%qs is only valid for the cell processor", name);
-  else if ((fnmask & RS6000_BTM_VSX) != 0)
-    error ("%qs requires the %qs option", name, "-mvsx");
-  else if ((fnmask & RS6000_BTM_HTM) != 0)
-    error ("%qs requires the %qs option", name, "-mhtm");
-  else if ((fnmask & RS6000_BTM_ALTIVEC) != 0)
-    error ("%qs requires the %qs option", name, "-maltivec");
-  else if ((fnmask & (RS6000_BTM_DFP | RS6000_BTM_P8_VECTOR))
-	   == (RS6000_BTM_DFP | RS6000_BTM_P8_VECTOR))
-    error ("%qs requires the %qs and %qs options", name, "-mhard-dfp",
-	   "-mpower8-vector");
-  else if ((fnmask & RS6000_BTM_DFP) != 0)
-    error ("%qs requires the %qs option", name, "-mhard-dfp");
-  else if ((fnmask & RS6000_BTM_P8_VECTOR) != 0)
-    error ("%qs requires the %qs option", name, "-mpower8-vector");
-  else if ((fnmask & (RS6000_BTM_P9_VECTOR | RS6000_BTM_64BIT))
-	   == (RS6000_BTM_P9_VECTOR | RS6000_BTM_64BIT))
-    error ("%qs requires the %qs and %qs options", name, "-mcpu=power9",
-	   "-m64");
-  else if ((fnmask & RS6000_BTM_P9_VECTOR) != 0)
-    error ("%qs requires the %qs option", name, "-mcpu=power9");
-  else if ((fnmask & (RS6000_BTM_P9_MISC | RS6000_BTM_64BIT))
-	   == (RS6000_BTM_P9_MISC | RS6000_BTM_64BIT))
-    error ("%qs requires the %qs and %qs options", name, "-mcpu=power9",
-	   "-m64");
-  else if ((fnmask & RS6000_BTM_P9_MISC) == RS6000_BTM_P9_MISC)
-    error ("%qs requires the %qs option", name, "-mcpu=power9");
-  else if ((fnmask & RS6000_BTM_P10) != 0)
-    error ("%qs requires the %qs option", name, "-mcpu=power10");
-  else if ((fnmask & RS6000_BTM_MMA) != 0)
-    error ("%qs requires the %qs option", name, "-mmma");
-  else if ((fnmask & RS6000_BTM_LDBL128) == RS6000_BTM_LDBL128)
-    {
-      if (!TARGET_HARD_FLOAT)
-	error ("%qs requires the %qs option", name, "-mhard-float");
-      else
-	error ("%qs requires the %qs option", name,
-	       TARGET_IEEEQUAD ? "-mabi=ibmlongdouble" : "-mlong-double-128");
-    }
-  else if ((fnmask & RS6000_BTM_HARD_FLOAT) != 0)
-    error ("%qs requires the %qs option", name, "-mhard-float");
-  else if ((fnmask & RS6000_BTM_FLOAT128_HW) != 0)
-    error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name);
-  else if ((fnmask & RS6000_BTM_FLOAT128) != 0)
-    error ("%qs requires the %qs option", name, "%<-mfloat128%>");
-  else if ((fnmask & (RS6000_BTM_POPCNTD | RS6000_BTM_POWERPC64))
-	   == (RS6000_BTM_POPCNTD | RS6000_BTM_POWERPC64))
-    error ("%qs requires the %qs (or newer), and %qs or %qs options",
-	   name, "-mcpu=power7", "-m64", "-mpowerpc64");
-  else
-    error ("%qs is not supported with the current options", name);
-}
-
-/* Raise an error message for a builtin function that is called without the
-   appropriate target options being set.  */
-
-void
-rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode)
-{
-  size_t j = (size_t) fncode;
-  const char *name = rs6000_builtin_info_x[j].bifname;
-
-  switch (rs6000_builtin_info_x[j].enable)
-    {
-    case ENB_P5:
-      error ("%qs requires the %qs option", name, "-mcpu=power5");
-      break;
-    case ENB_P6:
-      error ("%qs requires the %qs option", name, "-mcpu=power6");
-      break;
-    case ENB_P6_64:
-      error ("%qs requires the %qs option and either the %qs or %qs option",
-	     name, "-mcpu=power6", "-m64", "-mpowerpc64");
-      break;
-    case ENB_ALTIVEC:
-      error ("%qs requires the %qs option", name, "-maltivec");
-      break;
-    case ENB_CELL:
-      error ("%qs requires the %qs option", name, "-mcpu=cell");
-      break;
-    case ENB_VSX:
-      error ("%qs requires the %qs option", name, "-mvsx");
-      break;
-    case ENB_P7:
-      error ("%qs requires the %qs option", name, "-mcpu=power7");
-      break;
-    case ENB_P7_64:
-      error ("%qs requires the %qs option and either the %qs or %qs option",
-	     name, "-mcpu=power7", "-m64", "-mpowerpc64");
-      break;
-    case ENB_P8:
-      error ("%qs requires the %qs option", name, "-mcpu=power8");
-      break;
-    case ENB_P8V:
-      error ("%qs requires the %qs and %qs options", name, "-mcpu=power8",
-	     "-mvsx");
-      break;
-    case ENB_P9:
-      error ("%qs requires the %qs option", name, "-mcpu=power9");
-      break;
-    case ENB_P9_64:
-      error ("%qs requires the %qs option and either the %qs or %qs option",
-	     name, "-mcpu=power9", "-m64", "-mpowerpc64");
-      break;
-    case ENB_P9V:
-      error ("%qs requires the %qs and %qs options", name, "-mcpu=power9",
-	     "-mvsx");
-      break;
-    case ENB_IEEE128_HW:
-      error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name);
-      break;
-    case ENB_DFP:
-      error ("%qs requires the %qs option", name, "-mhard-dfp");
-      break;
-    case ENB_CRYPTO:
-      error ("%qs requires the %qs option", name, "-mcrypto");
-      break;
-    case ENB_HTM:
-      error ("%qs requires the %qs option", name, "-mhtm");
-      break;
-    case ENB_P10:
-      error ("%qs requires the %qs option", name, "-mcpu=power10");
-      break;
-    case ENB_P10_64:
-      error ("%qs requires the %qs option and either the %qs or %qs option",
-	     name, "-mcpu=power10", "-m64", "-mpowerpc64");
-      break;
-    case ENB_MMA:
-      error ("%qs requires the %qs option", name, "-mmma");
-      break;
-    default:
-    case ENB_ALWAYS:
-      gcc_unreachable ();
-    }
-}
-
-/* Target hook for early folding of built-ins, shamelessly stolen
-   from ia64.c.  */
-
-tree
-rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED,
-		     int n_args ATTRIBUTE_UNUSED,
-		     tree *args ATTRIBUTE_UNUSED,
-		     bool ignore ATTRIBUTE_UNUSED)
-{
-#ifdef SUBTARGET_FOLD_BUILTIN
-  return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
-#else
-  return NULL_TREE;
-#endif
-}
-
-/*  Helper function to sort out which built-ins may be valid without having
-    a LHS.  */
-static bool
-rs6000_builtin_valid_without_lhs (enum rs6000_builtins fn_code)
-{
-  /* Check for built-ins explicitly marked as a void function.  */
-  if (rs6000_builtin_info[fn_code].attr & RS6000_BTC_VOID)
-    return true;
-
-  switch (fn_code)
-    {
-    case ALTIVEC_BUILTIN_STVX_V16QI:
-    case ALTIVEC_BUILTIN_STVX_V8HI:
-    case ALTIVEC_BUILTIN_STVX_V4SI:
-    case ALTIVEC_BUILTIN_STVX_V4SF:
-    case ALTIVEC_BUILTIN_STVX_V2DI:
-    case ALTIVEC_BUILTIN_STVX_V2DF:
-    case VSX_BUILTIN_STXVW4X_V16QI:
-    case VSX_BUILTIN_STXVW4X_V8HI:
-    case VSX_BUILTIN_STXVW4X_V4SF:
-    case VSX_BUILTIN_STXVW4X_V4SI:
-    case VSX_BUILTIN_STXVD2X_V2DF:
-    case VSX_BUILTIN_STXVD2X_V2DI:
+    case RS6000_BIF_VMAXSD:
+    case RS6000_BIF_VMAXUD:
+    case RS6000_BIF_VMAXSB:
+    case RS6000_BIF_VMAXSH:
+    case RS6000_BIF_VMAXSW:
+    case RS6000_BIF_VMAXUB:
+    case RS6000_BIF_VMAXUH:
+    case RS6000_BIF_VMAXUW:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
       return true;
-    default:
-      return false;
-    }
-}
-
-/* Helper function to handle the gimple folding of a vector compare
-   operation.  This sets up true/false vectors, and uses the
-   VEC_COND_EXPR operation.
-   CODE indicates which comparison is to be made. (EQ, GT, ...).
-   TYPE indicates the type of the result.
-   Code is inserted before GSI.  */
-static tree
-fold_build_vec_cmp (tree_code code, tree type, tree arg0, tree arg1,
-		    gimple_stmt_iterator *gsi)
-{
-  tree cmp_type = truth_type_for (type);
-  tree zero_vec = build_zero_cst (type);
-  tree minus_one_vec = build_minus_one_cst (type);
-  tree temp = create_tmp_reg_or_ssa_name (cmp_type);
-  gimple *g = gimple_build_assign (temp, code, arg0, arg1);
-  gsi_insert_before (gsi, g, GSI_SAME_STMT);
-  return fold_build3 (VEC_COND_EXPR, type, temp, minus_one_vec, zero_vec);
-}
-
-/* Helper function to handle the in-between steps for the
-   vector compare built-ins.  */
-static void
-fold_compare_helper (gimple_stmt_iterator *gsi, tree_code code, gimple *stmt)
-{
-  tree arg0 = gimple_call_arg (stmt, 0);
-  tree arg1 = gimple_call_arg (stmt, 1);
-  tree lhs = gimple_call_lhs (stmt);
-  tree cmp = fold_build_vec_cmp (code, TREE_TYPE (lhs), arg0, arg1, gsi);
-  gimple *g = gimple_build_assign (lhs, cmp);
-  gimple_set_location (g, gimple_location (stmt));
-  gsi_replace (gsi, g, true);
-}
-
-/* Helper function to map V2DF and V4SF types to their
- integral equivalents (V2DI and V4SI).  */
-tree map_to_integral_tree_type (tree input_tree_type)
-{
-  if (INTEGRAL_TYPE_P (TREE_TYPE (input_tree_type)))
-    return input_tree_type;
-  else
-    {
-      if (types_compatible_p (TREE_TYPE (input_tree_type),
-			      TREE_TYPE (V2DF_type_node)))
-	return V2DI_type_node;
-      else if (types_compatible_p (TREE_TYPE (input_tree_type),
-				   TREE_TYPE (V4SF_type_node)))
-	return V4SI_type_node;
-      else
-	gcc_unreachable ();
-    }
-}
-
-/* Helper function to handle the vector merge[hl] built-ins.  The
-   implementation difference between h and l versions for this code are in
-   the values used when building of the permute vector for high word versus
-   low word merge.  The variance is keyed off the use_high parameter.  */
-static void
-fold_mergehl_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_high)
-{
-  tree arg0 = gimple_call_arg (stmt, 0);
-  tree arg1 = gimple_call_arg (stmt, 1);
-  tree lhs = gimple_call_lhs (stmt);
-  tree lhs_type = TREE_TYPE (lhs);
-  int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type);
-  int midpoint = n_elts / 2;
-  int offset = 0;
-
-  if (use_high == 1)
-    offset = midpoint;
-
-  /* The permute_type will match the lhs for integral types.  For double and
-     float types, the permute type needs to map to the V2 or V4 type that
-     matches size.  */
-  tree permute_type;
-  permute_type = map_to_integral_tree_type (lhs_type);
-  tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1);
-
-  for (int i = 0; i < midpoint; i++)
-    {
-      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
-				     offset + i));
-      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
-				     offset + n_elts + i));
-    }
-
-  tree permute = elts.build ();
-
-  gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute);
-  gimple_set_location (g, gimple_location (stmt));
-  gsi_replace (gsi, g, true);
-}
-
-/* Helper function to handle the vector merge[eo] built-ins.  */
-static void
-fold_mergeeo_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_odd)
-{
-  tree arg0 = gimple_call_arg (stmt, 0);
-  tree arg1 = gimple_call_arg (stmt, 1);
-  tree lhs = gimple_call_lhs (stmt);
-  tree lhs_type = TREE_TYPE (lhs);
-  int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type);
-
-  /* The permute_type will match the lhs for integral types.  For double and
-     float types, the permute type needs to map to the V2 or V4 type that
-     matches size.  */
-  tree permute_type;
-  permute_type = map_to_integral_tree_type (lhs_type);
-
-  tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1);
-
- /* Build the permute vector.  */
-  for (int i = 0; i < n_elts / 2; i++)
-    {
-      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
-				     2*i + use_odd));
-      elts.safe_push (build_int_cst (TREE_TYPE (permute_type),
-				     2*i + use_odd + n_elts));
-    }
-
-  tree permute = elts.build ();
-
-  gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute);
-  gimple_set_location (g, gimple_location (stmt));
-  gsi_replace (gsi, g, true);
-}
-
-/* Expand the MMA built-ins early, so that we can convert the pass-by-reference
-   __vector_quad arguments into pass-by-value arguments, leading to more
-   efficient code generation.  */
-
-bool
-rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi)
-{
-  gimple *stmt = gsi_stmt (*gsi);
-  tree fndecl = gimple_call_fndecl (stmt);
-  enum rs6000_builtins fncode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  unsigned attr = rs6000_builtin_info[fncode].attr;
-
-  if ((attr & RS6000_BTC_GIMPLE) == 0)
-    return false;
-
-  unsigned nopnds = (attr & RS6000_BTC_OPND_MASK);
-  gimple_seq new_seq = NULL;
-  gimple *new_call;
-  tree new_decl;
-
-  if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC
-      || fncode == VSX_BUILTIN_DISASSEMBLE_PAIR)
-    {
-      /* This is an MMA disassemble built-in function.  */
-      push_gimplify_context (true);
-      unsigned nvec = (fncode == MMA_BUILTIN_DISASSEMBLE_ACC) ? 4 : 2;
-      tree dst_ptr = gimple_call_arg (stmt, 0);
-      tree src_ptr = gimple_call_arg (stmt, 1);
-      tree src_type = TREE_TYPE (src_ptr);
-      tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type));
-      gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq);
-
-      /* If we are not disassembling an accumulator/pair or our destination is
-	 another accumulator/pair, then just copy the entire thing as is.  */
-      if ((fncode == MMA_BUILTIN_DISASSEMBLE_ACC
-	   && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node)
-	  || (fncode == VSX_BUILTIN_DISASSEMBLE_PAIR
-	      && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node))
-	{
-	  tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR,
-						   src_type, dst_ptr));
-	  gimplify_assign (dst, src, &new_seq);
-	  pop_gimplify_context (NULL);
-	  gsi_replace_with_seq (gsi, new_seq, true);
-	  return true;
-	}
-
-      /* If we're disassembling an accumulator into a different type, we need
-	 to emit a xxmfacc instruction now, since we cannot do it later.  */
-      if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC)
-	{
-	  new_decl = rs6000_builtin_decls[MMA_BUILTIN_XXMFACC_INTERNAL];
-	  new_call = gimple_build_call (new_decl, 1, src);
-	  src = create_tmp_reg_or_ssa_name (vector_quad_type_node);
-	  gimple_call_set_lhs (new_call, src);
-	  gimple_seq_add_stmt (&new_seq, new_call);
-	}
-
-      /* Copy the accumulator/pair vector by vector.  */
-      new_decl = rs6000_builtin_decls[fncode + 1];
-      tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node,
-						   ptr_mode, true);
-      tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr);
-      for (unsigned i = 0; i < nvec; i++)
-	{
-	  unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i;
-	  tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base,
-			     build_int_cst (dst_type, index * 16));
-	  tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node);
-	  new_call = gimple_build_call (new_decl, 2, src,
-					build_int_cstu (uint16_type_node, i));
-	  gimple_call_set_lhs (new_call, dstssa);
-	  gimple_seq_add_stmt (&new_seq, new_call);
-	  gimplify_assign (dst, dstssa, &new_seq);
-	}
-      pop_gimplify_context (NULL);
-      gsi_replace_with_seq (gsi, new_seq, true);
-      return true;
-    }
-  else if (fncode == VSX_BUILTIN_LXVP)
-    {
-      push_gimplify_context (true);
-      tree offset = gimple_call_arg (stmt, 0);
-      tree ptr = gimple_call_arg (stmt, 1);
-      tree lhs = gimple_call_lhs (stmt);
-      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
-	ptr = build1 (VIEW_CONVERT_EXPR,
-		      build_pointer_type (vector_pair_type_node), ptr);
-      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
-					       TREE_TYPE (ptr), ptr, offset));
-      gimplify_assign (lhs, mem, &new_seq);
-      pop_gimplify_context (NULL);
-      gsi_replace_with_seq (gsi, new_seq, true);
-      return true;
-    }
-  else if (fncode == VSX_BUILTIN_STXVP)
-    {
-      push_gimplify_context (true);
-      tree src = gimple_call_arg (stmt, 0);
-      tree offset = gimple_call_arg (stmt, 1);
-      tree ptr = gimple_call_arg (stmt, 2);
-      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
-	ptr = build1 (VIEW_CONVERT_EXPR,
-		      build_pointer_type (vector_pair_type_node), ptr);
-      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
-					       TREE_TYPE (ptr), ptr, offset));
-      gimplify_assign (mem, src, &new_seq);
-      pop_gimplify_context (NULL);
-      gsi_replace_with_seq (gsi, new_seq, true);
+    /* Flavors of vec_eqv.  */
+    case RS6000_BIF_EQV_V16QI:
+    case RS6000_BIF_EQV_V8HI:
+    case RS6000_BIF_EQV_V4SI:
+    case RS6000_BIF_EQV_V4SF:
+    case RS6000_BIF_EQV_V2DF:
+    case RS6000_BIF_EQV_V2DI:
+      arg0 = gimple_call_arg (stmt, 0);
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
+      g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
       return true;
-    }
-
-  /* Convert this built-in into an internal version that uses pass-by-value
-     arguments.  The internal built-in follows immediately after this one.  */
-  new_decl = rs6000_builtin_decls[fncode + 1];
-  tree lhs, op[MAX_MMA_OPERANDS];
-  tree acc = gimple_call_arg (stmt, 0);
-  push_gimplify_context (true);
-
-  if ((attr & RS6000_BTC_QUAD) != 0)
-    {
-      /* This built-in has a pass-by-reference accumulator input, so load it
-	 into a temporary accumulator for use as a pass-by-value input.  */
-      op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node);
-      for (unsigned i = 1; i < nopnds; i++)
-	op[i] = gimple_call_arg (stmt, i);
-      gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq);
-    }
-  else
-    {
-      /* This built-in does not use its pass-by-reference accumulator argument
-	 as an input argument, so remove it from the input list.  */
-      nopnds--;
-      for (unsigned i = 0; i < nopnds; i++)
-	op[i] = gimple_call_arg (stmt, i + 1);
-    }
-
-  switch (nopnds)
-    {
-    case 0:
-      new_call = gimple_build_call (new_decl, 0);
-      break;
-    case 1:
-      new_call = gimple_build_call (new_decl, 1, op[0]);
-      break;
-    case 2:
-      new_call = gimple_build_call (new_decl, 2, op[0], op[1]);
-      break;
-    case 3:
-      new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]);
-      break;
-    case 4:
-      new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]);
-      break;
-    case 5:
-      new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3],
-				    op[4]);
-      break;
-    case 6:
-      new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3],
-				    op[4], op[5]);
-      break;
-    case 7:
-      new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3],
-				    op[4], op[5], op[6]);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  if (fncode == VSX_BUILTIN_BUILD_PAIR || fncode == VSX_BUILTIN_ASSEMBLE_PAIR)
-    lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node);
-  else
-    lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node);
-  gimple_call_set_lhs (new_call, lhs);
-  gimple_seq_add_stmt (&new_seq, new_call);
-  gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq);
-  pop_gimplify_context (NULL);
-  gsi_replace_with_seq (gsi, new_seq, true);
-
-  return true;
-}
-
-/* Fold a machine-dependent built-in in GIMPLE.  (For folding into
-   a constant, use rs6000_fold_builtin.)  */
-
-bool
-rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
-{
-  if (new_builtins_are_live)
-    return rs6000_gimple_fold_new_builtin (gsi);
-
-  gimple *stmt = gsi_stmt (*gsi);
-  tree fndecl = gimple_call_fndecl (stmt);
-  gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD);
-  enum rs6000_builtins fn_code
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  tree arg0, arg1, lhs, temp;
-  enum tree_code bcode;
-  gimple *g;
-
-  size_t uns_fncode = (size_t) fn_code;
-  enum insn_code icode = rs6000_builtin_info[uns_fncode].icode;
-  const char *fn_name1 = rs6000_builtin_info[uns_fncode].name;
-  const char *fn_name2 = (icode != CODE_FOR_nothing)
-			  ? get_insn_name ((int) icode)
-			  : "nothing";
-
-  if (TARGET_DEBUG_BUILTIN)
-      fprintf (stderr, "rs6000_gimple_fold_builtin %d %s %s\n",
-	       fn_code, fn_name1, fn_name2);
-
-  if (!rs6000_fold_gimple)
-    return false;
-
-  /* Prevent gimple folding for code that does not have a LHS, unless it is
-     allowed per the rs6000_builtin_valid_without_lhs helper function.  */
-  if (!gimple_call_lhs (stmt) && !rs6000_builtin_valid_without_lhs (fn_code))
-    return false;
-
-  /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it.  */
-  if (!rs6000_builtin_is_supported_p (fn_code))
-    return false;
-
-  if (rs6000_gimple_fold_mma_builtin (gsi))
-    return true;
-
-  switch (fn_code)
-    {
-    /* Flavors of vec_add.  We deliberately don't expand
-       P8V_BUILTIN_VADDUQM as it gets lowered from V1TImode to
-       TImode, resulting in much poorer code generation.  */
-    case ALTIVEC_BUILTIN_VADDUBM:
-    case ALTIVEC_BUILTIN_VADDUHM:
-    case ALTIVEC_BUILTIN_VADDUWM:
-    case P8V_BUILTIN_VADDUDM:
-    case ALTIVEC_BUILTIN_VADDFP:
-    case VSX_BUILTIN_XVADDDP:
-      bcode = PLUS_EXPR;
-    do_binary:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs)))
-	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs))))
-	{
-	  /* Ensure the binary operation is performed in a type
-	     that wraps if it is integral type.  */
-	  gimple_seq stmts = NULL;
-	  tree type = unsigned_type_for (TREE_TYPE (lhs));
-	  tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-				     type, arg0);
-	  tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-				     type, arg1);
-	  tree res = gimple_build (&stmts, gimple_location (stmt), bcode,
-				   type, uarg0, uarg1);
-	  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	  g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR,
-				   build1 (VIEW_CONVERT_EXPR,
-					   TREE_TYPE (lhs), res));
-	  gsi_replace (gsi, g, true);
-	  return true;
-	}
-      g = gimple_build_assign (lhs, bcode, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_sub.  We deliberately don't expand
-       P8V_BUILTIN_VSUBUQM. */
-    case ALTIVEC_BUILTIN_VSUBUBM:
-    case ALTIVEC_BUILTIN_VSUBUHM:
-    case ALTIVEC_BUILTIN_VSUBUWM:
-    case P8V_BUILTIN_VSUBUDM:
-    case ALTIVEC_BUILTIN_VSUBFP:
-    case VSX_BUILTIN_XVSUBDP:
-      bcode = MINUS_EXPR;
-      goto do_binary;
-    case VSX_BUILTIN_XVMULSP:
-    case VSX_BUILTIN_XVMULDP:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Even element flavors of vec_mul (signed). */
-    case ALTIVEC_BUILTIN_VMULESB:
-    case ALTIVEC_BUILTIN_VMULESH:
-    case P8V_BUILTIN_VMULESW:
-    /* Even element flavors of vec_mul (unsigned).  */
-    case ALTIVEC_BUILTIN_VMULEUB:
-    case ALTIVEC_BUILTIN_VMULEUH:
-    case P8V_BUILTIN_VMULEUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Odd element flavors of vec_mul (signed).  */
-    case ALTIVEC_BUILTIN_VMULOSB:
-    case ALTIVEC_BUILTIN_VMULOSH:
-    case P8V_BUILTIN_VMULOSW:
-    /* Odd element flavors of vec_mul (unsigned). */
-    case ALTIVEC_BUILTIN_VMULOUB:
-    case ALTIVEC_BUILTIN_VMULOUH:
-    case P8V_BUILTIN_VMULOUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_div (Integer).  */
-    case VSX_BUILTIN_DIV_V2DI:
-    case VSX_BUILTIN_UDIV_V2DI:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_div (Float).  */
-    case VSX_BUILTIN_XVDIVSP:
-    case VSX_BUILTIN_XVDIVDP:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_and.  */
-    case ALTIVEC_BUILTIN_VAND_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V16QI:
-    case ALTIVEC_BUILTIN_VAND_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V8HI:
-    case ALTIVEC_BUILTIN_VAND_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V4SI:
-    case ALTIVEC_BUILTIN_VAND_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V2DI:
-    case ALTIVEC_BUILTIN_VAND_V4SF:
-    case ALTIVEC_BUILTIN_VAND_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_andc.  */
-    case ALTIVEC_BUILTIN_VANDC_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V16QI:
-    case ALTIVEC_BUILTIN_VANDC_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V8HI:
-    case ALTIVEC_BUILTIN_VANDC_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V4SI:
-    case ALTIVEC_BUILTIN_VANDC_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V2DI:
-    case ALTIVEC_BUILTIN_VANDC_V4SF:
-    case ALTIVEC_BUILTIN_VANDC_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_nand.  */
-    case P8V_BUILTIN_VEC_NAND:
-    case P8V_BUILTIN_NAND_V16QI_UNS:
-    case P8V_BUILTIN_NAND_V16QI:
-    case P8V_BUILTIN_NAND_V8HI_UNS:
-    case P8V_BUILTIN_NAND_V8HI:
-    case P8V_BUILTIN_NAND_V4SI_UNS:
-    case P8V_BUILTIN_NAND_V4SI:
-    case P8V_BUILTIN_NAND_V2DI_UNS:
-    case P8V_BUILTIN_NAND_V2DI:
-    case P8V_BUILTIN_NAND_V4SF:
-    case P8V_BUILTIN_NAND_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_or.  */
-    case ALTIVEC_BUILTIN_VOR_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V16QI:
-    case ALTIVEC_BUILTIN_VOR_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V8HI:
-    case ALTIVEC_BUILTIN_VOR_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V4SI:
-    case ALTIVEC_BUILTIN_VOR_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V2DI:
-    case ALTIVEC_BUILTIN_VOR_V4SF:
-    case ALTIVEC_BUILTIN_VOR_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_orc.  */
-    case P8V_BUILTIN_ORC_V16QI_UNS:
-    case P8V_BUILTIN_ORC_V16QI:
-    case P8V_BUILTIN_ORC_V8HI_UNS:
-    case P8V_BUILTIN_ORC_V8HI:
-    case P8V_BUILTIN_ORC_V4SI_UNS:
-    case P8V_BUILTIN_ORC_V4SI:
-    case P8V_BUILTIN_ORC_V2DI_UNS:
-    case P8V_BUILTIN_ORC_V2DI:
-    case P8V_BUILTIN_ORC_V4SF:
-    case P8V_BUILTIN_ORC_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_xor.  */
-    case ALTIVEC_BUILTIN_VXOR_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V16QI:
-    case ALTIVEC_BUILTIN_VXOR_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V8HI:
-    case ALTIVEC_BUILTIN_VXOR_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V4SI:
-    case ALTIVEC_BUILTIN_VXOR_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V2DI:
-    case ALTIVEC_BUILTIN_VXOR_V4SF:
-    case ALTIVEC_BUILTIN_VXOR_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_nor.  */
-    case ALTIVEC_BUILTIN_VNOR_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V16QI:
-    case ALTIVEC_BUILTIN_VNOR_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V8HI:
-    case ALTIVEC_BUILTIN_VNOR_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V4SI:
-    case ALTIVEC_BUILTIN_VNOR_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V2DI:
-    case ALTIVEC_BUILTIN_VNOR_V4SF:
-    case ALTIVEC_BUILTIN_VNOR_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_abs.  */
-    case ALTIVEC_BUILTIN_ABS_V16QI:
-    case ALTIVEC_BUILTIN_ABS_V8HI:
-    case ALTIVEC_BUILTIN_ABS_V4SI:
-    case ALTIVEC_BUILTIN_ABS_V4SF:
-    case P8V_BUILTIN_ABS_V2DI:
-    case VSX_BUILTIN_XVABSDP:
-      arg0 = gimple_call_arg (stmt, 0);
-      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0)))
-	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0))))
-	return false;
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, ABS_EXPR, arg0);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_min.  */
-    case VSX_BUILTIN_XVMINDP:
-    case ALTIVEC_BUILTIN_VMINFP:
-      {
-	lhs = gimple_call_lhs (stmt);
-	tree type = TREE_TYPE (lhs);
-	if (HONOR_NANS (type))
-	  return false;
-	gcc_fallthrough ();
-      }
-    case P8V_BUILTIN_VMINSD:
-    case P8V_BUILTIN_VMINUD:
-    case ALTIVEC_BUILTIN_VMINSB:
-    case ALTIVEC_BUILTIN_VMINSH:
-    case ALTIVEC_BUILTIN_VMINSW:
-    case ALTIVEC_BUILTIN_VMINUB:
-    case ALTIVEC_BUILTIN_VMINUH:
-    case ALTIVEC_BUILTIN_VMINUW:
+    /* Flavors of vec_rotate_left.  */
+    case RS6000_BIF_VRLB:
+    case RS6000_BIF_VRLH:
+    case RS6000_BIF_VRLW:
+    case RS6000_BIF_VRLD:
       arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_max.  */
-    case VSX_BUILTIN_XVMAXDP:
-    case ALTIVEC_BUILTIN_VMAXFP:
-      {
-	lhs = gimple_call_lhs (stmt);
-	tree type = TREE_TYPE (lhs);
-	if (HONOR_NANS (type))
-	  return false;
-	gcc_fallthrough ();
-      }
-    case P8V_BUILTIN_VMAXSD:
-    case P8V_BUILTIN_VMAXUD:
-    case ALTIVEC_BUILTIN_VMAXSB:
-    case ALTIVEC_BUILTIN_VMAXSH:
-    case ALTIVEC_BUILTIN_VMAXSW:
-    case ALTIVEC_BUILTIN_VMAXUB:
-    case ALTIVEC_BUILTIN_VMAXUH:
-    case ALTIVEC_BUILTIN_VMAXUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_eqv.  */
-    case P8V_BUILTIN_EQV_V16QI:
-    case P8V_BUILTIN_EQV_V8HI:
-    case P8V_BUILTIN_EQV_V4SI:
-    case P8V_BUILTIN_EQV_V4SF:
-    case P8V_BUILTIN_EQV_V2DF:
-    case P8V_BUILTIN_EQV_V2DI:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_rotate_left.  */
-    case ALTIVEC_BUILTIN_VRLB:
-    case ALTIVEC_BUILTIN_VRLH:
-    case ALTIVEC_BUILTIN_VRLW:
-    case P8V_BUILTIN_VRLD:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-  /* Flavors of vector shift right algebraic.
-     vec_sra{b,h,w} -> vsra{b,h,w}.  */
-    case ALTIVEC_BUILTIN_VSRAB:
-    case ALTIVEC_BUILTIN_VSRAH:
-    case ALTIVEC_BUILTIN_VSRAW:
-    case P8V_BUILTIN_VSRAD:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	lhs = gimple_call_lhs (stmt);
-	tree arg1_type = TREE_TYPE (arg1);
-	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
-	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
-	location_t loc = gimple_location (stmt);
-	/* Force arg1 into the range valid matching the arg0 type.  */
-	/* Build a vector consisting of the max valid bit-size values.  */
-	int n_elts = VECTOR_CST_NELTS (arg1);
-	tree element_size = build_int_cst (unsigned_element_type,
-					   128 / n_elts);
-	tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
-	for (int i = 0; i < n_elts; i++)
-	  elts.safe_push (element_size);
-	tree modulo_tree = elts.build ();
-	/* Modulo the provided shift value against that vector.  */
-	gimple_seq stmts = NULL;
-	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-					   unsigned_arg1_type, arg1);
-	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
-				      unsigned_arg1_type, unsigned_arg1,
-				      modulo_tree);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	/* And finally, do the shift.  */
-	g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-   /* Flavors of vector shift left.
-      builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}.  */
-    case ALTIVEC_BUILTIN_VSLB:
-    case ALTIVEC_BUILTIN_VSLH:
-    case ALTIVEC_BUILTIN_VSLW:
-    case P8V_BUILTIN_VSLD:
-      {
-	location_t loc;
-	gimple_seq stmts = NULL;
-	arg0 = gimple_call_arg (stmt, 0);
-	tree arg0_type = TREE_TYPE (arg0);
-	if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type))
-	    && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type)))
-	  return false;
-	arg1 = gimple_call_arg (stmt, 1);
-	tree arg1_type = TREE_TYPE (arg1);
-	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
-	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
-	loc = gimple_location (stmt);
-	lhs = gimple_call_lhs (stmt);
-	/* Force arg1 into the range valid matching the arg0 type.  */
-	/* Build a vector consisting of the max valid bit-size values.  */
-	int n_elts = VECTOR_CST_NELTS (arg1);
-	int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type))
-				* BITS_PER_UNIT;
-	tree element_size = build_int_cst (unsigned_element_type,
-					   tree_size_in_bits / n_elts);
-	tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1);
-	for (int i = 0; i < n_elts; i++)
-	  elts.safe_push (element_size);
-	tree modulo_tree = elts.build ();
-	/* Modulo the provided shift value against that vector.  */
-	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-					   unsigned_arg1_type, arg1);
-	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
-				      unsigned_arg1_type, unsigned_arg1,
-				      modulo_tree);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	/* And finally, do the shift.  */
-	g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* Flavors of vector shift right.  */
-    case ALTIVEC_BUILTIN_VSRB:
-    case ALTIVEC_BUILTIN_VSRH:
-    case ALTIVEC_BUILTIN_VSRW:
-    case P8V_BUILTIN_VSRD:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	lhs = gimple_call_lhs (stmt);
-	tree arg1_type = TREE_TYPE (arg1);
-	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
-	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
-	location_t loc = gimple_location (stmt);
-	gimple_seq stmts = NULL;
-	/* Convert arg0 to unsigned.  */
-	tree arg0_unsigned
-	  = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-			  unsigned_type_for (TREE_TYPE (arg0)), arg0);
-	/* Force arg1 into the range valid matching the arg0 type.  */
-	/* Build a vector consisting of the max valid bit-size values.  */
-	int n_elts = VECTOR_CST_NELTS (arg1);
-	tree element_size = build_int_cst (unsigned_element_type,
-					   128 / n_elts);
-	tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
-	for (int i = 0; i < n_elts; i++)
-	  elts.safe_push (element_size);
-	tree modulo_tree = elts.build ();
-	/* Modulo the provided shift value against that vector.  */
-	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-					   unsigned_arg1_type, arg1);
-	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
-				      unsigned_arg1_type, unsigned_arg1,
-				      modulo_tree);
-	/* Do the shift.  */
-	tree res
-	  = gimple_build (&stmts, RSHIFT_EXPR,
-			  TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1);
-	/* Convert result back to the lhs type.  */
-	res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	replace_call_with_value (gsi, res);
-	return true;
-      }
-    /* Vector loads.  */
-    case ALTIVEC_BUILTIN_LVX_V16QI:
-    case ALTIVEC_BUILTIN_LVX_V8HI:
-    case ALTIVEC_BUILTIN_LVX_V4SI:
-    case ALTIVEC_BUILTIN_LVX_V4SF:
-    case ALTIVEC_BUILTIN_LVX_V2DI:
-    case ALTIVEC_BUILTIN_LVX_V2DF:
-    case ALTIVEC_BUILTIN_LVX_V1TI:
-      {
-	arg0 = gimple_call_arg (stmt, 0);  // offset
-	arg1 = gimple_call_arg (stmt, 1);  // address
-	lhs = gimple_call_lhs (stmt);
-	location_t loc = gimple_location (stmt);
-	/* Since arg1 may be cast to a different type, just use ptr_type_node
-	   here instead of trying to enforce TBAA on pointer types.  */
-	tree arg1_type = ptr_type_node;
-	tree lhs_type = TREE_TYPE (lhs);
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg0.  The resulting type will match
-	   the type of arg1.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg1_type, arg1, temp_offset);
-	/* Mask off any lower bits from the address.  */
-	tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
-					  arg1_type, temp_addr,
-					  build_int_cst (arg1_type, -16));
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (aligned_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (aligned_addr));
-	    gimple *g = gimple_build_assign (t, aligned_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    aligned_addr = t;
-	  }
-	/* Use the build2 helper to set up the mem_ref.  The MEM_REF could also
-	   take an offset, but since we've already incorporated the offset
-	   above, here we just pass in a zero.  */
-	gimple *g
-	  = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr,
-					      build_int_cst (arg1_type, 0)));
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* Vector stores.  */
-    case ALTIVEC_BUILTIN_STVX_V16QI:
-    case ALTIVEC_BUILTIN_STVX_V8HI:
-    case ALTIVEC_BUILTIN_STVX_V4SI:
-    case ALTIVEC_BUILTIN_STVX_V4SF:
-    case ALTIVEC_BUILTIN_STVX_V2DI:
-    case ALTIVEC_BUILTIN_STVX_V2DF:
-      {
-	arg0 = gimple_call_arg (stmt, 0); /* Value to be stored.  */
-	arg1 = gimple_call_arg (stmt, 1); /* Offset.  */
-	tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address.  */
-	location_t loc = gimple_location (stmt);
-	tree arg0_type = TREE_TYPE (arg0);
-	/* Use ptr_type_node (no TBAA) for the arg2_type.
-	   FIXME: (Richard)  "A proper fix would be to transition this type as
-	   seen from the frontend to GIMPLE, for example in a similar way we
-	   do for MEM_REFs by piggy-backing that on an extra argument, a
-	   constant zero pointer of the alias pointer type to use (which would
-	   also serve as a type indicator of the store itself).  I'd use a
-	   target specific internal function for this (not sure if we can have
-	   those target specific, but I guess if it's folded away then that's
-	   fine) and get away with the overload set."  */
-	tree arg2_type = ptr_type_node;
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg0.  The resulting type will match
-	   the type of arg2.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg2_type, arg2, temp_offset);
-	/* Mask off any lower bits from the address.  */
-	tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
-					  arg2_type, temp_addr,
-					  build_int_cst (arg2_type, -16));
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (aligned_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (aligned_addr));
-	    gimple *g = gimple_build_assign (t, aligned_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    aligned_addr = t;
-	  }
-	/* The desired gimple result should be similar to:
-	   MEM[(__vector floatD.1407 *)_1] = vf1D.2697;  */
-	gimple *g
-	  = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr,
-					 build_int_cst (arg2_type, 0)), arg0);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* unaligned Vector loads.  */
-    case VSX_BUILTIN_LXVW4X_V16QI:
-    case VSX_BUILTIN_LXVW4X_V8HI:
-    case VSX_BUILTIN_LXVW4X_V4SF:
-    case VSX_BUILTIN_LXVW4X_V4SI:
-    case VSX_BUILTIN_LXVD2X_V2DF:
-    case VSX_BUILTIN_LXVD2X_V2DI:
-      {
-	arg0 = gimple_call_arg (stmt, 0);  // offset
-	arg1 = gimple_call_arg (stmt, 1);  // address
-	lhs = gimple_call_lhs (stmt);
-	location_t loc = gimple_location (stmt);
-	/* Since arg1 may be cast to a different type, just use ptr_type_node
-	   here instead of trying to enforce TBAA on pointer types.  */
-	tree arg1_type = ptr_type_node;
-	tree lhs_type = TREE_TYPE (lhs);
-	/* In GIMPLE the type of the MEM_REF specifies the alignment.  The
-	  required alignment (power) is 4 bytes regardless of data type.  */
-	tree align_ltype = build_aligned_type (lhs_type, 4);
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg0.  The resulting type will match
-	   the type of arg1.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg1_type, arg1, temp_offset);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (temp_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (temp_addr));
-	    gimple *g = gimple_build_assign (t, temp_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    temp_addr = t;
-	  }
-	/* Use the build2 helper to set up the mem_ref.  The MEM_REF could also
-	   take an offset, but since we've already incorporated the offset
-	   above, here we just pass in a zero.  */
-	gimple *g;
-	g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr,
-					      build_int_cst (arg1_type, 0)));
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* unaligned Vector stores.  */
-    case VSX_BUILTIN_STXVW4X_V16QI:
-    case VSX_BUILTIN_STXVW4X_V8HI:
-    case VSX_BUILTIN_STXVW4X_V4SF:
-    case VSX_BUILTIN_STXVW4X_V4SI:
-    case VSX_BUILTIN_STXVD2X_V2DF:
-    case VSX_BUILTIN_STXVD2X_V2DI:
-      {
-	arg0 = gimple_call_arg (stmt, 0); /* Value to be stored.  */
-	arg1 = gimple_call_arg (stmt, 1); /* Offset.  */
-	tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address.  */
-	location_t loc = gimple_location (stmt);
-	tree arg0_type = TREE_TYPE (arg0);
-	/* Use ptr_type_node (no TBAA) for the arg2_type.  */
-	tree arg2_type = ptr_type_node;
-	/* In GIMPLE the type of the MEM_REF specifies the alignment.  The
-	   required alignment (power) is 4 bytes regardless of data type.  */
-	tree align_stype = build_aligned_type (arg0_type, 4);
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg1.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg2_type, arg2, temp_offset);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (temp_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (temp_addr));
-	    gimple *g = gimple_build_assign (t, temp_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    temp_addr = t;
-	  }
-	gimple *g;
-	g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr,
-					 build_int_cst (arg2_type, 0)), arg0);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* Vector Fused multiply-add (fma).  */
-    case ALTIVEC_BUILTIN_VMADDFP:
-    case VSX_BUILTIN_XVMADDDP:
-    case ALTIVEC_BUILTIN_VMLADDUHM:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	tree arg2 = gimple_call_arg (stmt, 2);
-	lhs = gimple_call_lhs (stmt);
-	gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2);
-	gimple_call_set_lhs (g, lhs);
-	gimple_call_set_nothrow (g, true);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* Vector compares; EQ, NE, GE, GT, LE.  */
-    case ALTIVEC_BUILTIN_VCMPEQUB:
-    case ALTIVEC_BUILTIN_VCMPEQUH:
-    case ALTIVEC_BUILTIN_VCMPEQUW:
-    case P8V_BUILTIN_VCMPEQUD:
-    case P10V_BUILTIN_VCMPEQUT:
-      fold_compare_helper (gsi, EQ_EXPR, stmt);
-      return true;
-
-    case P9V_BUILTIN_CMPNEB:
-    case P9V_BUILTIN_CMPNEH:
-    case P9V_BUILTIN_CMPNEW:
-    case P10V_BUILTIN_CMPNET:
-      fold_compare_helper (gsi, NE_EXPR, stmt);
-      return true;
-
-    case VSX_BUILTIN_CMPGE_16QI:
-    case VSX_BUILTIN_CMPGE_U16QI:
-    case VSX_BUILTIN_CMPGE_8HI:
-    case VSX_BUILTIN_CMPGE_U8HI:
-    case VSX_BUILTIN_CMPGE_4SI:
-    case VSX_BUILTIN_CMPGE_U4SI:
-    case VSX_BUILTIN_CMPGE_2DI:
-    case VSX_BUILTIN_CMPGE_U2DI:
-    case P10V_BUILTIN_CMPGE_1TI:
-    case P10V_BUILTIN_CMPGE_U1TI:
-      fold_compare_helper (gsi, GE_EXPR, stmt);
-      return true;
-
-    case ALTIVEC_BUILTIN_VCMPGTSB:
-    case ALTIVEC_BUILTIN_VCMPGTUB:
-    case ALTIVEC_BUILTIN_VCMPGTSH:
-    case ALTIVEC_BUILTIN_VCMPGTUH:
-    case ALTIVEC_BUILTIN_VCMPGTSW:
-    case ALTIVEC_BUILTIN_VCMPGTUW:
-    case P8V_BUILTIN_VCMPGTUD:
-    case P8V_BUILTIN_VCMPGTSD:
-    case P10V_BUILTIN_VCMPGTUT:
-    case P10V_BUILTIN_VCMPGTST:
-      fold_compare_helper (gsi, GT_EXPR, stmt);
-      return true;
-
-    case VSX_BUILTIN_CMPLE_16QI:
-    case VSX_BUILTIN_CMPLE_U16QI:
-    case VSX_BUILTIN_CMPLE_8HI:
-    case VSX_BUILTIN_CMPLE_U8HI:
-    case VSX_BUILTIN_CMPLE_4SI:
-    case VSX_BUILTIN_CMPLE_U4SI:
-    case VSX_BUILTIN_CMPLE_2DI:
-    case VSX_BUILTIN_CMPLE_U2DI:
-    case P10V_BUILTIN_CMPLE_1TI:
-    case P10V_BUILTIN_CMPLE_U1TI:
-      fold_compare_helper (gsi, LE_EXPR, stmt);
-      return true;
-
-    /* flavors of vec_splat_[us]{8,16,32}.  */
-    case ALTIVEC_BUILTIN_VSPLTISB:
-    case ALTIVEC_BUILTIN_VSPLTISH:
-    case ALTIVEC_BUILTIN_VSPLTISW:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	lhs = gimple_call_lhs (stmt);
-
-	/* Only fold the vec_splat_*() if the lower bits of arg 0 is a
-	   5-bit signed constant in range -16 to +15.  */
-	if (TREE_CODE (arg0) != INTEGER_CST
-	    || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15))
-	  return false;
-	gimple_seq stmts = NULL;
-	location_t loc = gimple_location (stmt);
-	tree splat_value = gimple_convert (&stmts, loc,
-					   TREE_TYPE (TREE_TYPE (lhs)), arg0);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value);
-	g = gimple_build_assign (lhs, splat_tree);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* Flavors of vec_splat.  */
-    /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...};  */
-    case ALTIVEC_BUILTIN_VSPLTB:
-    case ALTIVEC_BUILTIN_VSPLTH:
-    case ALTIVEC_BUILTIN_VSPLTW:
-    case VSX_BUILTIN_XXSPLTD_V2DI:
-    case VSX_BUILTIN_XXSPLTD_V2DF:
-      {
-	arg0 = gimple_call_arg (stmt, 0); /* input vector.  */
-	arg1 = gimple_call_arg (stmt, 1); /* index into arg0.  */
-	/* Only fold the vec_splat_*() if arg1 is both a constant value and
-	   is a valid index into the arg0 vector.  */
-	unsigned int n_elts = VECTOR_CST_NELTS (arg0);
-	if (TREE_CODE (arg1) != INTEGER_CST
-	    || TREE_INT_CST_LOW (arg1) > (n_elts -1))
-	  return false;
-	lhs = gimple_call_lhs (stmt);
-	tree lhs_type = TREE_TYPE (lhs);
-	tree arg0_type = TREE_TYPE (arg0);
-	tree splat;
-	if (TREE_CODE (arg0) == VECTOR_CST)
-	  splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1));
-	else
-	  {
-	    /* Determine (in bits) the length and start location of the
-	       splat value for a call to the tree_vec_extract helper.  */
-	    int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type))
-				  * BITS_PER_UNIT / n_elts;
-	    int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size;
-	    tree len = build_int_cst (bitsizetype, splat_elem_size);
-	    tree start = build_int_cst (bitsizetype, splat_start_bit);
-	    splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0,
-				      len, start);
-	  }
-	/* And finally, build the new vector.  */
-	tree splat_tree = build_vector_from_val (lhs_type, splat);
-	g = gimple_build_assign (lhs, splat_tree);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* vec_mergel (integrals).  */
-    case ALTIVEC_BUILTIN_VMRGLH:
-    case ALTIVEC_BUILTIN_VMRGLW:
-    case VSX_BUILTIN_XXMRGLW_4SI:
-    case ALTIVEC_BUILTIN_VMRGLB:
-    case VSX_BUILTIN_VEC_MERGEL_V2DI:
-    case VSX_BUILTIN_XXMRGLW_4SF:
-    case VSX_BUILTIN_VEC_MERGEL_V2DF:
-      fold_mergehl_helper (gsi, stmt, 1);
-      return true;
-    /* vec_mergeh (integrals).  */
-    case ALTIVEC_BUILTIN_VMRGHH:
-    case ALTIVEC_BUILTIN_VMRGHW:
-    case VSX_BUILTIN_XXMRGHW_4SI:
-    case ALTIVEC_BUILTIN_VMRGHB:
-    case VSX_BUILTIN_VEC_MERGEH_V2DI:
-    case VSX_BUILTIN_XXMRGHW_4SF:
-    case VSX_BUILTIN_VEC_MERGEH_V2DF:
-      fold_mergehl_helper (gsi, stmt, 0);
-      return true;
-
-    /* Flavors of vec_mergee.  */
-    case P8V_BUILTIN_VMRGEW_V4SI:
-    case P8V_BUILTIN_VMRGEW_V2DI:
-    case P8V_BUILTIN_VMRGEW_V4SF:
-    case P8V_BUILTIN_VMRGEW_V2DF:
-      fold_mergeeo_helper (gsi, stmt, 0);
-      return true;
-    /* Flavors of vec_mergeo.  */
-    case P8V_BUILTIN_VMRGOW_V4SI:
-    case P8V_BUILTIN_VMRGOW_V2DI:
-    case P8V_BUILTIN_VMRGOW_V4SF:
-    case P8V_BUILTIN_VMRGOW_V2DF:
-      fold_mergeeo_helper (gsi, stmt, 1);
-      return true;
-
-    /* d = vec_pack (a, b) */
-    case P8V_BUILTIN_VPKUDUM:
-    case ALTIVEC_BUILTIN_VPKUHUM:
-    case ALTIVEC_BUILTIN_VPKUWUM:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	lhs = gimple_call_lhs (stmt);
-	gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* d = vec_unpackh (a) */
-    /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call
-       in this code is sensitive to endian-ness, and needs to be inverted to
-       handle both LE and BE targets.  */
-    case ALTIVEC_BUILTIN_VUPKHSB:
-    case ALTIVEC_BUILTIN_VUPKHSH:
-    case P8V_BUILTIN_VUPKHSW:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	lhs = gimple_call_lhs (stmt);
-	if (BYTES_BIG_ENDIAN)
-	  g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0);
-	else
-	  g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* d = vec_unpackl (a) */
-    case ALTIVEC_BUILTIN_VUPKLSB:
-    case ALTIVEC_BUILTIN_VUPKLSH:
-    case P8V_BUILTIN_VUPKLSW:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	lhs = gimple_call_lhs (stmt);
-	if (BYTES_BIG_ENDIAN)
-	  g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0);
-	else
-	  g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* There is no gimple type corresponding with pixel, so just return.  */
-    case ALTIVEC_BUILTIN_VUPKHPX:
-    case ALTIVEC_BUILTIN_VUPKLPX:
-      return false;
-
-    /* vec_perm.  */
-    case ALTIVEC_BUILTIN_VPERM_16QI:
-    case ALTIVEC_BUILTIN_VPERM_8HI:
-    case ALTIVEC_BUILTIN_VPERM_4SI:
-    case ALTIVEC_BUILTIN_VPERM_2DI:
-    case ALTIVEC_BUILTIN_VPERM_4SF:
-    case ALTIVEC_BUILTIN_VPERM_2DF:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	tree permute = gimple_call_arg (stmt, 2);
-	lhs = gimple_call_lhs (stmt);
-	location_t loc = gimple_location (stmt);
-	gimple_seq stmts = NULL;
-	// convert arg0 and arg1 to match the type of the permute
-	// for the VEC_PERM_EXPR operation.
-	tree permute_type = (TREE_TYPE (permute));
-	tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
-					permute_type, arg0);
-	tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
-					permute_type, arg1);
-	tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR,
-				      permute_type, arg0_ptype, arg1_ptype,
-				      permute);
-	// Convert the result back to the desired lhs type upon completion.
-	tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
-				  TREE_TYPE (lhs), lhs_ptype);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	g = gimple_build_assign (lhs, temp);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    default:
-      if (TARGET_DEBUG_BUILTIN)
-	fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n",
-		 fn_code, fn_name1, fn_name2);
-      break;
-    }
-
-  return false;
-}
-
-/*  Helper function to sort out which built-ins may be valid without having
-    a LHS.  */
-static bool
-rs6000_new_builtin_valid_without_lhs (enum rs6000_gen_builtins fn_code,
-				      tree fndecl)
-{
-  if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node)
-    return true;
-
-  switch (fn_code)
-    {
-    case RS6000_BIF_STVX_V16QI:
-    case RS6000_BIF_STVX_V8HI:
-    case RS6000_BIF_STVX_V4SI:
-    case RS6000_BIF_STVX_V4SF:
-    case RS6000_BIF_STVX_V2DI:
-    case RS6000_BIF_STVX_V2DF:
-    case RS6000_BIF_STXVW4X_V16QI:
-    case RS6000_BIF_STXVW4X_V8HI:
-    case RS6000_BIF_STXVW4X_V4SF:
-    case RS6000_BIF_STXVW4X_V4SI:
-    case RS6000_BIF_STXVD2X_V2DF:
-    case RS6000_BIF_STXVD2X_V2DI:
-      return true;
-    default:
-      return false;
-    }
-}
-
-/* Check whether a builtin function is supported in this target
-   configuration.  */
-bool
-rs6000_new_builtin_is_supported (enum rs6000_gen_builtins fncode)
-{
-  switch (rs6000_builtin_info_x[(size_t) fncode].enable)
-    {
-    case ENB_ALWAYS:
-      return true;
-    case ENB_P5:
-      return TARGET_POPCNTB;
-    case ENB_P6:
-      return TARGET_CMPB;
-    case ENB_P6_64:
-      return TARGET_CMPB && TARGET_POWERPC64;
-    case ENB_P7:
-      return TARGET_POPCNTD;
-    case ENB_P7_64:
-      return TARGET_POPCNTD && TARGET_POWERPC64;
-    case ENB_P8:
-      return TARGET_DIRECT_MOVE;
-    case ENB_P8V:
-      return TARGET_P8_VECTOR;
-    case ENB_P9:
-      return TARGET_MODULO;
-    case ENB_P9_64:
-      return TARGET_MODULO && TARGET_POWERPC64;
-    case ENB_P9V:
-      return TARGET_P9_VECTOR;
-    case ENB_P10:
-      return TARGET_POWER10;
-    case ENB_P10_64:
-      return TARGET_POWER10 && TARGET_POWERPC64;
-    case ENB_ALTIVEC:
-      return TARGET_ALTIVEC;
-    case ENB_VSX:
-      return TARGET_VSX;
-    case ENB_CELL:
-      return TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL;
-    case ENB_IEEE128_HW:
-      return TARGET_FLOAT128_HW;
-    case ENB_DFP:
-      return TARGET_DFP;
-    case ENB_CRYPTO:
-      return TARGET_CRYPTO;
-    case ENB_HTM:
-      return TARGET_HTM;
-    case ENB_MMA:
-      return TARGET_MMA;
-    default:
-      gcc_unreachable ();
-    }
-  gcc_unreachable ();
-}
-
-/* Expand the MMA built-ins early, so that we can convert the pass-by-reference
-   __vector_quad arguments into pass-by-value arguments, leading to more
-   efficient code generation.  */
-static bool
-rs6000_gimple_fold_new_mma_builtin (gimple_stmt_iterator *gsi,
-				    rs6000_gen_builtins fn_code)
-{
-  gimple *stmt = gsi_stmt (*gsi);
-  size_t fncode = (size_t) fn_code;
-
-  if (!bif_is_mma (rs6000_builtin_info_x[fncode]))
-    return false;
-
-  /* Each call that can be gimple-expanded has an associated built-in
-     function that it will expand into.  If this one doesn't, we have
-     already expanded it!  Exceptions: lxvp and stxvp.  */
-  if (rs6000_builtin_info_x[fncode].assoc_bif == RS6000_BIF_NONE
-      && fncode != RS6000_BIF_LXVP
-      && fncode != RS6000_BIF_STXVP)
-    return false;
-
-  bifdata *bd = &rs6000_builtin_info_x[fncode];
-  unsigned nopnds = bd->nargs;
-  gimple_seq new_seq = NULL;
-  gimple *new_call;
-  tree new_decl;
-
-  /* Compatibility built-ins; we used to call these
-     __builtin_mma_{dis,}assemble_pair, but now we call them
-     __builtin_vsx_{dis,}assemble_pair.  Handle the old versions.  */
-  if (fncode == RS6000_BIF_ASSEMBLE_PAIR)
-    fncode = RS6000_BIF_ASSEMBLE_PAIR_V;
-  else if (fncode == RS6000_BIF_DISASSEMBLE_PAIR)
-    fncode = RS6000_BIF_DISASSEMBLE_PAIR_V;
-
-  if (fncode == RS6000_BIF_DISASSEMBLE_ACC
-      || fncode == RS6000_BIF_DISASSEMBLE_PAIR_V)
-    {
-      /* This is an MMA disassemble built-in function.  */
-      push_gimplify_context (true);
-      unsigned nvec = (fncode == RS6000_BIF_DISASSEMBLE_ACC) ? 4 : 2;
-      tree dst_ptr = gimple_call_arg (stmt, 0);
-      tree src_ptr = gimple_call_arg (stmt, 1);
-      tree src_type = TREE_TYPE (src_ptr);
-      tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type));
-      gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq);
-
-      /* If we are not disassembling an accumulator/pair or our destination is
-	 another accumulator/pair, then just copy the entire thing as is.  */
-      if ((fncode == RS6000_BIF_DISASSEMBLE_ACC
-	   && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node)
-	  || (fncode == RS6000_BIF_DISASSEMBLE_PAIR_V
-	      && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node))
-	{
-	  tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR,
-						   src_type, dst_ptr));
-	  gimplify_assign (dst, src, &new_seq);
-	  pop_gimplify_context (NULL);
-	  gsi_replace_with_seq (gsi, new_seq, true);
-	  return true;
-	}
-
-      /* If we're disassembling an accumulator into a different type, we need
-	 to emit a xxmfacc instruction now, since we cannot do it later.  */
-      if (fncode == RS6000_BIF_DISASSEMBLE_ACC)
-	{
-	  new_decl = rs6000_builtin_decls_x[RS6000_BIF_XXMFACC_INTERNAL];
-	  new_call = gimple_build_call (new_decl, 1, src);
-	  src = create_tmp_reg_or_ssa_name (vector_quad_type_node);
-	  gimple_call_set_lhs (new_call, src);
-	  gimple_seq_add_stmt (&new_seq, new_call);
-	}
-
-      /* Copy the accumulator/pair vector by vector.  */
-      new_decl
-	= rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif];
-      tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node,
-						   ptr_mode, true);
-      tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr);
-      for (unsigned i = 0; i < nvec; i++)
-	{
-	  unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i;
-	  tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base,
-			     build_int_cst (dst_type, index * 16));
-	  tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node);
-	  new_call = gimple_build_call (new_decl, 2, src,
-					build_int_cstu (uint16_type_node, i));
-	  gimple_call_set_lhs (new_call, dstssa);
-	  gimple_seq_add_stmt (&new_seq, new_call);
-	  gimplify_assign (dst, dstssa, &new_seq);
-	}
-      pop_gimplify_context (NULL);
-      gsi_replace_with_seq (gsi, new_seq, true);
-      return true;
-    }
-
-  /* TODO: Do some factoring on these two chunks.  */
-  if (fncode == RS6000_BIF_LXVP)
-    {
-      push_gimplify_context (true);
-      tree offset = gimple_call_arg (stmt, 0);
-      tree ptr = gimple_call_arg (stmt, 1);
-      tree lhs = gimple_call_lhs (stmt);
-      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
-	ptr = build1 (VIEW_CONVERT_EXPR,
-		      build_pointer_type (vector_pair_type_node), ptr);
-      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
-					       TREE_TYPE (ptr), ptr, offset));
-      gimplify_assign (lhs, mem, &new_seq);
-      pop_gimplify_context (NULL);
-      gsi_replace_with_seq (gsi, new_seq, true);
-      return true;
-    }
-
-  if (fncode == RS6000_BIF_STXVP)
-    {
-      push_gimplify_context (true);
-      tree src = gimple_call_arg (stmt, 0);
-      tree offset = gimple_call_arg (stmt, 1);
-      tree ptr = gimple_call_arg (stmt, 2);
-      if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node)
-	ptr = build1 (VIEW_CONVERT_EXPR,
-		      build_pointer_type (vector_pair_type_node), ptr);
-      tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR,
-					       TREE_TYPE (ptr), ptr, offset));
-      gimplify_assign (mem, src, &new_seq);
-      pop_gimplify_context (NULL);
-      gsi_replace_with_seq (gsi, new_seq, true);
-      return true;
-    }
-
-  /* Convert this built-in into an internal version that uses pass-by-value
-     arguments.  The internal built-in is found in the assoc_bif field.  */
-  new_decl = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif];
-  tree lhs, op[MAX_MMA_OPERANDS];
-  tree acc = gimple_call_arg (stmt, 0);
-  push_gimplify_context (true);
-
-  if (bif_is_quad (*bd))
-    {
-      /* This built-in has a pass-by-reference accumulator input, so load it
-	 into a temporary accumulator for use as a pass-by-value input.  */
-      op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node);
-      for (unsigned i = 1; i < nopnds; i++)
-	op[i] = gimple_call_arg (stmt, i);
-      gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq);
-    }
-  else
-    {
-      /* This built-in does not use its pass-by-reference accumulator argument
-	 as an input argument, so remove it from the input list.  */
-      nopnds--;
-      for (unsigned i = 0; i < nopnds; i++)
-	op[i] = gimple_call_arg (stmt, i + 1);
-    }
-
-  switch (nopnds)
-    {
-    case 0:
-      new_call = gimple_build_call (new_decl, 0);
-      break;
-    case 1:
-      new_call = gimple_build_call (new_decl, 1, op[0]);
-      break;
-    case 2:
-      new_call = gimple_build_call (new_decl, 2, op[0], op[1]);
-      break;
-    case 3:
-      new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]);
-      break;
-    case 4:
-      new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]);
-      break;
-    case 5:
-      new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3],
-				    op[4]);
-      break;
-    case 6:
-      new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3],
-				    op[4], op[5]);
-      break;
-    case 7:
-      new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3],
-				    op[4], op[5], op[6]);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  if (fncode == RS6000_BIF_BUILD_PAIR || fncode == RS6000_BIF_ASSEMBLE_PAIR_V)
-    lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node);
-  else
-    lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node);
-  gimple_call_set_lhs (new_call, lhs);
-  gimple_seq_add_stmt (&new_seq, new_call);
-  gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq);
-  pop_gimplify_context (NULL);
-  gsi_replace_with_seq (gsi, new_seq, true);
-
-  return true;
-}
-
-/* Fold a machine-dependent built-in in GIMPLE.  (For folding into
-   a constant, use rs6000_fold_builtin.)  */
-static bool
-rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi)
-{
-  gimple *stmt = gsi_stmt (*gsi);
-  tree fndecl = gimple_call_fndecl (stmt);
-  gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD);
-  enum rs6000_gen_builtins fn_code
-    = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  tree arg0, arg1, lhs, temp;
-  enum tree_code bcode;
-  gimple *g;
-
-  size_t uns_fncode = (size_t) fn_code;
-  enum insn_code icode = rs6000_builtin_info_x[uns_fncode].icode;
-  const char *fn_name1 = rs6000_builtin_info_x[uns_fncode].bifname;
-  const char *fn_name2 = (icode != CODE_FOR_nothing)
-			  ? get_insn_name ((int) icode)
-			  : "nothing";
-
-  if (TARGET_DEBUG_BUILTIN)
-      fprintf (stderr, "rs6000_gimple_fold_new_builtin %d %s %s\n",
-	       fn_code, fn_name1, fn_name2);
-
-  if (!rs6000_fold_gimple)
-    return false;
-
-  /* Prevent gimple folding for code that does not have a LHS, unless it is
-     allowed per the rs6000_new_builtin_valid_without_lhs helper function.  */
-  if (!gimple_call_lhs (stmt)
-      && !rs6000_new_builtin_valid_without_lhs (fn_code, fndecl))
-    return false;
-
-  /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it.  */
-  if (!rs6000_new_builtin_is_supported (fn_code))
-    return false;
-
-  if (rs6000_gimple_fold_new_mma_builtin (gsi, fn_code))
-    return true;
-
-  switch (fn_code)
-    {
-    /* Flavors of vec_add.  We deliberately don't expand
-       RS6000_BIF_VADDUQM as it gets lowered from V1TImode to
-       TImode, resulting in much poorer code generation.  */
-    case RS6000_BIF_VADDUBM:
-    case RS6000_BIF_VADDUHM:
-    case RS6000_BIF_VADDUWM:
-    case RS6000_BIF_VADDUDM:
-    case RS6000_BIF_VADDFP:
-    case RS6000_BIF_XVADDDP:
-    case RS6000_BIF_XVADDSP:
-      bcode = PLUS_EXPR;
-    do_binary:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs)))
-	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs))))
-	{
-	  /* Ensure the binary operation is performed in a type
-	     that wraps if it is integral type.  */
-	  gimple_seq stmts = NULL;
-	  tree type = unsigned_type_for (TREE_TYPE (lhs));
-	  tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-				     type, arg0);
-	  tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-				     type, arg1);
-	  tree res = gimple_build (&stmts, gimple_location (stmt), bcode,
-				   type, uarg0, uarg1);
-	  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	  g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR,
-				   build1 (VIEW_CONVERT_EXPR,
-					   TREE_TYPE (lhs), res));
-	  gsi_replace (gsi, g, true);
-	  return true;
-	}
-      g = gimple_build_assign (lhs, bcode, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_sub.  We deliberately don't expand
-       RS6000_BIF_VSUBUQM. */
-    case RS6000_BIF_VSUBUBM:
-    case RS6000_BIF_VSUBUHM:
-    case RS6000_BIF_VSUBUWM:
-    case RS6000_BIF_VSUBUDM:
-    case RS6000_BIF_VSUBFP:
-    case RS6000_BIF_XVSUBDP:
-    case RS6000_BIF_XVSUBSP:
-      bcode = MINUS_EXPR;
-      goto do_binary;
-    case RS6000_BIF_XVMULSP:
-    case RS6000_BIF_XVMULDP:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Even element flavors of vec_mul (signed). */
-    case RS6000_BIF_VMULESB:
-    case RS6000_BIF_VMULESH:
-    case RS6000_BIF_VMULESW:
-    /* Even element flavors of vec_mul (unsigned).  */
-    case RS6000_BIF_VMULEUB:
-    case RS6000_BIF_VMULEUH:
-    case RS6000_BIF_VMULEUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Odd element flavors of vec_mul (signed).  */
-    case RS6000_BIF_VMULOSB:
-    case RS6000_BIF_VMULOSH:
-    case RS6000_BIF_VMULOSW:
-    /* Odd element flavors of vec_mul (unsigned). */
-    case RS6000_BIF_VMULOUB:
-    case RS6000_BIF_VMULOUH:
-    case RS6000_BIF_VMULOUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_div (Integer).  */
-    case RS6000_BIF_DIV_V2DI:
-    case RS6000_BIF_UDIV_V2DI:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_div (Float).  */
-    case RS6000_BIF_XVDIVSP:
-    case RS6000_BIF_XVDIVDP:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_and.  */
-    case RS6000_BIF_VAND_V16QI_UNS:
-    case RS6000_BIF_VAND_V16QI:
-    case RS6000_BIF_VAND_V8HI_UNS:
-    case RS6000_BIF_VAND_V8HI:
-    case RS6000_BIF_VAND_V4SI_UNS:
-    case RS6000_BIF_VAND_V4SI:
-    case RS6000_BIF_VAND_V2DI_UNS:
-    case RS6000_BIF_VAND_V2DI:
-    case RS6000_BIF_VAND_V4SF:
-    case RS6000_BIF_VAND_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_andc.  */
-    case RS6000_BIF_VANDC_V16QI_UNS:
-    case RS6000_BIF_VANDC_V16QI:
-    case RS6000_BIF_VANDC_V8HI_UNS:
-    case RS6000_BIF_VANDC_V8HI:
-    case RS6000_BIF_VANDC_V4SI_UNS:
-    case RS6000_BIF_VANDC_V4SI:
-    case RS6000_BIF_VANDC_V2DI_UNS:
-    case RS6000_BIF_VANDC_V2DI:
-    case RS6000_BIF_VANDC_V4SF:
-    case RS6000_BIF_VANDC_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_nand.  */
-    case RS6000_BIF_NAND_V16QI_UNS:
-    case RS6000_BIF_NAND_V16QI:
-    case RS6000_BIF_NAND_V8HI_UNS:
-    case RS6000_BIF_NAND_V8HI:
-    case RS6000_BIF_NAND_V4SI_UNS:
-    case RS6000_BIF_NAND_V4SI:
-    case RS6000_BIF_NAND_V2DI_UNS:
-    case RS6000_BIF_NAND_V2DI:
-    case RS6000_BIF_NAND_V4SF:
-    case RS6000_BIF_NAND_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_or.  */
-    case RS6000_BIF_VOR_V16QI_UNS:
-    case RS6000_BIF_VOR_V16QI:
-    case RS6000_BIF_VOR_V8HI_UNS:
-    case RS6000_BIF_VOR_V8HI:
-    case RS6000_BIF_VOR_V4SI_UNS:
-    case RS6000_BIF_VOR_V4SI:
-    case RS6000_BIF_VOR_V2DI_UNS:
-    case RS6000_BIF_VOR_V2DI:
-    case RS6000_BIF_VOR_V4SF:
-    case RS6000_BIF_VOR_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_orc.  */
-    case RS6000_BIF_ORC_V16QI_UNS:
-    case RS6000_BIF_ORC_V16QI:
-    case RS6000_BIF_ORC_V8HI_UNS:
-    case RS6000_BIF_ORC_V8HI:
-    case RS6000_BIF_ORC_V4SI_UNS:
-    case RS6000_BIF_ORC_V4SI:
-    case RS6000_BIF_ORC_V2DI_UNS:
-    case RS6000_BIF_ORC_V2DI:
-    case RS6000_BIF_ORC_V4SF:
-    case RS6000_BIF_ORC_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_xor.  */
-    case RS6000_BIF_VXOR_V16QI_UNS:
-    case RS6000_BIF_VXOR_V16QI:
-    case RS6000_BIF_VXOR_V8HI_UNS:
-    case RS6000_BIF_VXOR_V8HI:
-    case RS6000_BIF_VXOR_V4SI_UNS:
-    case RS6000_BIF_VXOR_V4SI:
-    case RS6000_BIF_VXOR_V2DI_UNS:
-    case RS6000_BIF_VXOR_V2DI:
-    case RS6000_BIF_VXOR_V4SF:
-    case RS6000_BIF_VXOR_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_nor.  */
-    case RS6000_BIF_VNOR_V16QI_UNS:
-    case RS6000_BIF_VNOR_V16QI:
-    case RS6000_BIF_VNOR_V8HI_UNS:
-    case RS6000_BIF_VNOR_V8HI:
-    case RS6000_BIF_VNOR_V4SI_UNS:
-    case RS6000_BIF_VNOR_V4SI:
-    case RS6000_BIF_VNOR_V2DI_UNS:
-    case RS6000_BIF_VNOR_V2DI:
-    case RS6000_BIF_VNOR_V4SF:
-    case RS6000_BIF_VNOR_V2DF:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_abs.  */
-    case RS6000_BIF_ABS_V16QI:
-    case RS6000_BIF_ABS_V8HI:
-    case RS6000_BIF_ABS_V4SI:
-    case RS6000_BIF_ABS_V4SF:
-    case RS6000_BIF_ABS_V2DI:
-    case RS6000_BIF_XVABSDP:
-    case RS6000_BIF_XVABSSP:
-      arg0 = gimple_call_arg (stmt, 0);
-      if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0)))
-	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0))))
-	return false;
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, ABS_EXPR, arg0);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_min.  */
-    case RS6000_BIF_XVMINDP:
-    case RS6000_BIF_XVMINSP:
-    case RS6000_BIF_VMINFP:
-      {
-	lhs = gimple_call_lhs (stmt);
-	tree type = TREE_TYPE (lhs);
-	if (HONOR_NANS (type))
-	  return false;
-	gcc_fallthrough ();
-      }
-    case RS6000_BIF_VMINSD:
-    case RS6000_BIF_VMINUD:
-    case RS6000_BIF_VMINSB:
-    case RS6000_BIF_VMINSH:
-    case RS6000_BIF_VMINSW:
-    case RS6000_BIF_VMINUB:
-    case RS6000_BIF_VMINUH:
-    case RS6000_BIF_VMINUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* flavors of vec_max.  */
-    case RS6000_BIF_XVMAXDP:
-    case RS6000_BIF_XVMAXSP:
-    case RS6000_BIF_VMAXFP:
-      {
-	lhs = gimple_call_lhs (stmt);
-	tree type = TREE_TYPE (lhs);
-	if (HONOR_NANS (type))
-	  return false;
-	gcc_fallthrough ();
-      }
-    case RS6000_BIF_VMAXSD:
-    case RS6000_BIF_VMAXUD:
-    case RS6000_BIF_VMAXSB:
-    case RS6000_BIF_VMAXSH:
-    case RS6000_BIF_VMAXSW:
-    case RS6000_BIF_VMAXUB:
-    case RS6000_BIF_VMAXUH:
-    case RS6000_BIF_VMAXUW:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_eqv.  */
-    case RS6000_BIF_EQV_V16QI:
-    case RS6000_BIF_EQV_V8HI:
-    case RS6000_BIF_EQV_V4SI:
-    case RS6000_BIF_EQV_V4SF:
-    case RS6000_BIF_EQV_V2DF:
-    case RS6000_BIF_EQV_V2DI:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1));
-      g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-    /* Flavors of vec_rotate_left.  */
-    case RS6000_BIF_VRLB:
-    case RS6000_BIF_VRLH:
-    case RS6000_BIF_VRLW:
-    case RS6000_BIF_VRLD:
-      arg0 = gimple_call_arg (stmt, 0);
-      arg1 = gimple_call_arg (stmt, 1);
-      lhs = gimple_call_lhs (stmt);
-      g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_replace (gsi, g, true);
-      return true;
-  /* Flavors of vector shift right algebraic.
-     vec_sra{b,h,w} -> vsra{b,h,w}.  */
-    case RS6000_BIF_VSRAB:
-    case RS6000_BIF_VSRAH:
-    case RS6000_BIF_VSRAW:
-    case RS6000_BIF_VSRAD:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	lhs = gimple_call_lhs (stmt);
-	tree arg1_type = TREE_TYPE (arg1);
-	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
-	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
-	location_t loc = gimple_location (stmt);
-	/* Force arg1 into the range valid matching the arg0 type.  */
-	/* Build a vector consisting of the max valid bit-size values.  */
-	int n_elts = VECTOR_CST_NELTS (arg1);
-	tree element_size = build_int_cst (unsigned_element_type,
-					   128 / n_elts);
-	tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
-	for (int i = 0; i < n_elts; i++)
-	  elts.safe_push (element_size);
-	tree modulo_tree = elts.build ();
-	/* Modulo the provided shift value against that vector.  */
-	gimple_seq stmts = NULL;
-	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-					   unsigned_arg1_type, arg1);
-	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
-				      unsigned_arg1_type, unsigned_arg1,
-				      modulo_tree);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	/* And finally, do the shift.  */
-	g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-   /* Flavors of vector shift left.
-      builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}.  */
-    case RS6000_BIF_VSLB:
-    case RS6000_BIF_VSLH:
-    case RS6000_BIF_VSLW:
-    case RS6000_BIF_VSLD:
-      {
-	location_t loc;
-	gimple_seq stmts = NULL;
-	arg0 = gimple_call_arg (stmt, 0);
-	tree arg0_type = TREE_TYPE (arg0);
-	if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type))
-	    && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type)))
-	  return false;
-	arg1 = gimple_call_arg (stmt, 1);
-	tree arg1_type = TREE_TYPE (arg1);
-	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
-	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
-	loc = gimple_location (stmt);
-	lhs = gimple_call_lhs (stmt);
-	/* Force arg1 into the range valid matching the arg0 type.  */
-	/* Build a vector consisting of the max valid bit-size values.  */
-	int n_elts = VECTOR_CST_NELTS (arg1);
-	int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type))
-				* BITS_PER_UNIT;
-	tree element_size = build_int_cst (unsigned_element_type,
-					   tree_size_in_bits / n_elts);
-	tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1);
-	for (int i = 0; i < n_elts; i++)
-	  elts.safe_push (element_size);
-	tree modulo_tree = elts.build ();
-	/* Modulo the provided shift value against that vector.  */
-	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-					   unsigned_arg1_type, arg1);
-	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
-				      unsigned_arg1_type, unsigned_arg1,
-				      modulo_tree);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	/* And finally, do the shift.  */
-	g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* Flavors of vector shift right.  */
-    case RS6000_BIF_VSRB:
-    case RS6000_BIF_VSRH:
-    case RS6000_BIF_VSRW:
-    case RS6000_BIF_VSRD:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	lhs = gimple_call_lhs (stmt);
-	tree arg1_type = TREE_TYPE (arg1);
-	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
-	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
-	location_t loc = gimple_location (stmt);
-	gimple_seq stmts = NULL;
-	/* Convert arg0 to unsigned.  */
-	tree arg0_unsigned
-	  = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-			  unsigned_type_for (TREE_TYPE (arg0)), arg0);
-	/* Force arg1 into the range valid matching the arg0 type.  */
-	/* Build a vector consisting of the max valid bit-size values.  */
-	int n_elts = VECTOR_CST_NELTS (arg1);
-	tree element_size = build_int_cst (unsigned_element_type,
-					   128 / n_elts);
-	tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
-	for (int i = 0; i < n_elts; i++)
-	  elts.safe_push (element_size);
-	tree modulo_tree = elts.build ();
-	/* Modulo the provided shift value against that vector.  */
-	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
-					   unsigned_arg1_type, arg1);
-	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
-				      unsigned_arg1_type, unsigned_arg1,
-				      modulo_tree);
-	/* Do the shift.  */
-	tree res
-	  = gimple_build (&stmts, RSHIFT_EXPR,
-			  TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1);
-	/* Convert result back to the lhs type.  */
-	res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	replace_call_with_value (gsi, res);
-	return true;
-      }
-    /* Vector loads.  */
-    case RS6000_BIF_LVX_V16QI:
-    case RS6000_BIF_LVX_V8HI:
-    case RS6000_BIF_LVX_V4SI:
-    case RS6000_BIF_LVX_V4SF:
-    case RS6000_BIF_LVX_V2DI:
-    case RS6000_BIF_LVX_V2DF:
-    case RS6000_BIF_LVX_V1TI:
-      {
-	arg0 = gimple_call_arg (stmt, 0);  // offset
-	arg1 = gimple_call_arg (stmt, 1);  // address
-	lhs = gimple_call_lhs (stmt);
-	location_t loc = gimple_location (stmt);
-	/* Since arg1 may be cast to a different type, just use ptr_type_node
-	   here instead of trying to enforce TBAA on pointer types.  */
-	tree arg1_type = ptr_type_node;
-	tree lhs_type = TREE_TYPE (lhs);
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg0.  The resulting type will match
-	   the type of arg1.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg1_type, arg1, temp_offset);
-	/* Mask off any lower bits from the address.  */
-	tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
-					  arg1_type, temp_addr,
-					  build_int_cst (arg1_type, -16));
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (aligned_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (aligned_addr));
-	    gimple *g = gimple_build_assign (t, aligned_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    aligned_addr = t;
-	  }
-	/* Use the build2 helper to set up the mem_ref.  The MEM_REF could also
-	   take an offset, but since we've already incorporated the offset
-	   above, here we just pass in a zero.  */
-	gimple *g
-	  = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr,
-					      build_int_cst (arg1_type, 0)));
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* Vector stores.  */
-    case RS6000_BIF_STVX_V16QI:
-    case RS6000_BIF_STVX_V8HI:
-    case RS6000_BIF_STVX_V4SI:
-    case RS6000_BIF_STVX_V4SF:
-    case RS6000_BIF_STVX_V2DI:
-    case RS6000_BIF_STVX_V2DF:
-      {
-	arg0 = gimple_call_arg (stmt, 0); /* Value to be stored.  */
-	arg1 = gimple_call_arg (stmt, 1); /* Offset.  */
-	tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address.  */
-	location_t loc = gimple_location (stmt);
-	tree arg0_type = TREE_TYPE (arg0);
-	/* Use ptr_type_node (no TBAA) for the arg2_type.
-	   FIXME: (Richard)  "A proper fix would be to transition this type as
-	   seen from the frontend to GIMPLE, for example in a similar way we
-	   do for MEM_REFs by piggy-backing that on an extra argument, a
-	   constant zero pointer of the alias pointer type to use (which would
-	   also serve as a type indicator of the store itself).  I'd use a
-	   target specific internal function for this (not sure if we can have
-	   those target specific, but I guess if it's folded away then that's
-	   fine) and get away with the overload set."  */
-	tree arg2_type = ptr_type_node;
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg0.  The resulting type will match
-	   the type of arg2.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg2_type, arg2, temp_offset);
-	/* Mask off any lower bits from the address.  */
-	tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
-					  arg2_type, temp_addr,
-					  build_int_cst (arg2_type, -16));
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (aligned_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (aligned_addr));
-	    gimple *g = gimple_build_assign (t, aligned_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    aligned_addr = t;
-	  }
-	/* The desired gimple result should be similar to:
-	   MEM[(__vector floatD.1407 *)_1] = vf1D.2697;  */
-	gimple *g
-	  = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr,
-					 build_int_cst (arg2_type, 0)), arg0);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* unaligned Vector loads.  */
-    case RS6000_BIF_LXVW4X_V16QI:
-    case RS6000_BIF_LXVW4X_V8HI:
-    case RS6000_BIF_LXVW4X_V4SF:
-    case RS6000_BIF_LXVW4X_V4SI:
-    case RS6000_BIF_LXVD2X_V2DF:
-    case RS6000_BIF_LXVD2X_V2DI:
-      {
-	arg0 = gimple_call_arg (stmt, 0);  // offset
-	arg1 = gimple_call_arg (stmt, 1);  // address
-	lhs = gimple_call_lhs (stmt);
-	location_t loc = gimple_location (stmt);
-	/* Since arg1 may be cast to a different type, just use ptr_type_node
-	   here instead of trying to enforce TBAA on pointer types.  */
-	tree arg1_type = ptr_type_node;
-	tree lhs_type = TREE_TYPE (lhs);
-	/* In GIMPLE the type of the MEM_REF specifies the alignment.  The
-	  required alignment (power) is 4 bytes regardless of data type.  */
-	tree align_ltype = build_aligned_type (lhs_type, 4);
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg0.  The resulting type will match
-	   the type of arg1.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg1_type, arg1, temp_offset);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (temp_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (temp_addr));
-	    gimple *g = gimple_build_assign (t, temp_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    temp_addr = t;
-	  }
-	/* Use the build2 helper to set up the mem_ref.  The MEM_REF could also
-	   take an offset, but since we've already incorporated the offset
-	   above, here we just pass in a zero.  */
-	gimple *g;
-	g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr,
-					      build_int_cst (arg1_type, 0)));
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* unaligned Vector stores.  */
-    case RS6000_BIF_STXVW4X_V16QI:
-    case RS6000_BIF_STXVW4X_V8HI:
-    case RS6000_BIF_STXVW4X_V4SF:
-    case RS6000_BIF_STXVW4X_V4SI:
-    case RS6000_BIF_STXVD2X_V2DF:
-    case RS6000_BIF_STXVD2X_V2DI:
-      {
-	arg0 = gimple_call_arg (stmt, 0); /* Value to be stored.  */
-	arg1 = gimple_call_arg (stmt, 1); /* Offset.  */
-	tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address.  */
-	location_t loc = gimple_location (stmt);
-	tree arg0_type = TREE_TYPE (arg0);
-	/* Use ptr_type_node (no TBAA) for the arg2_type.  */
-	tree arg2_type = ptr_type_node;
-	/* In GIMPLE the type of the MEM_REF specifies the alignment.  The
-	   required alignment (power) is 4 bytes regardless of data type.  */
-	tree align_stype = build_aligned_type (arg0_type, 4);
-	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
-	   the tree using the value from arg1.  */
-	gimple_seq stmts = NULL;
-	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
-	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
-				       arg2_type, arg2, temp_offset);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	if (!is_gimple_mem_ref_addr (temp_addr))
-	  {
-	    tree t = make_ssa_name (TREE_TYPE (temp_addr));
-	    gimple *g = gimple_build_assign (t, temp_addr);
-	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	    temp_addr = t;
-	  }
-	gimple *g;
-	g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr,
-					 build_int_cst (arg2_type, 0)), arg0);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* Vector Fused multiply-add (fma).  */
-    case RS6000_BIF_VMADDFP:
-    case RS6000_BIF_XVMADDDP:
-    case RS6000_BIF_XVMADDSP:
-    case RS6000_BIF_VMLADDUHM:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	tree arg2 = gimple_call_arg (stmt, 2);
-	lhs = gimple_call_lhs (stmt);
-	gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2);
-	gimple_call_set_lhs (g, lhs);
-	gimple_call_set_nothrow (g, true);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* Vector compares; EQ, NE, GE, GT, LE.  */
-    case RS6000_BIF_VCMPEQUB:
-    case RS6000_BIF_VCMPEQUH:
-    case RS6000_BIF_VCMPEQUW:
-    case RS6000_BIF_VCMPEQUD:
-    /* We deliberately omit RS6000_BIF_VCMPEQUT for now, because gimple
-       folding produces worse code for 128-bit compares.  */
-      fold_compare_helper (gsi, EQ_EXPR, stmt);
-      return true;
-
-    case RS6000_BIF_VCMPNEB:
-    case RS6000_BIF_VCMPNEH:
-    case RS6000_BIF_VCMPNEW:
-    /* We deliberately omit RS6000_BIF_VCMPNET for now, because gimple
-       folding produces worse code for 128-bit compares.  */
-      fold_compare_helper (gsi, NE_EXPR, stmt);
-      return true;
-
-    case RS6000_BIF_CMPGE_16QI:
-    case RS6000_BIF_CMPGE_U16QI:
-    case RS6000_BIF_CMPGE_8HI:
-    case RS6000_BIF_CMPGE_U8HI:
-    case RS6000_BIF_CMPGE_4SI:
-    case RS6000_BIF_CMPGE_U4SI:
-    case RS6000_BIF_CMPGE_2DI:
-    case RS6000_BIF_CMPGE_U2DI:
-    /* We deliberately omit RS6000_BIF_CMPGE_1TI and RS6000_BIF_CMPGE_U1TI
-       for now, because gimple folding produces worse code for 128-bit
-       compares.  */
-      fold_compare_helper (gsi, GE_EXPR, stmt);
-      return true;
-
-    case RS6000_BIF_VCMPGTSB:
-    case RS6000_BIF_VCMPGTUB:
-    case RS6000_BIF_VCMPGTSH:
-    case RS6000_BIF_VCMPGTUH:
-    case RS6000_BIF_VCMPGTSW:
-    case RS6000_BIF_VCMPGTUW:
-    case RS6000_BIF_VCMPGTUD:
-    case RS6000_BIF_VCMPGTSD:
-    /* We deliberately omit RS6000_BIF_VCMPGTUT and RS6000_BIF_VCMPGTST
-       for now, because gimple folding produces worse code for 128-bit
-       compares.  */
-      fold_compare_helper (gsi, GT_EXPR, stmt);
-      return true;
-
-    case RS6000_BIF_CMPLE_16QI:
-    case RS6000_BIF_CMPLE_U16QI:
-    case RS6000_BIF_CMPLE_8HI:
-    case RS6000_BIF_CMPLE_U8HI:
-    case RS6000_BIF_CMPLE_4SI:
-    case RS6000_BIF_CMPLE_U4SI:
-    case RS6000_BIF_CMPLE_2DI:
-    case RS6000_BIF_CMPLE_U2DI:
-    /* We deliberately omit RS6000_BIF_CMPLE_1TI and RS6000_BIF_CMPLE_U1TI
-       for now, because gimple folding produces worse code for 128-bit
-       compares.  */
-      fold_compare_helper (gsi, LE_EXPR, stmt);
-      return true;
-
-    /* flavors of vec_splat_[us]{8,16,32}.  */
-    case RS6000_BIF_VSPLTISB:
-    case RS6000_BIF_VSPLTISH:
-    case RS6000_BIF_VSPLTISW:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	lhs = gimple_call_lhs (stmt);
-
-	/* Only fold the vec_splat_*() if the lower bits of arg 0 is a
-	   5-bit signed constant in range -16 to +15.  */
-	if (TREE_CODE (arg0) != INTEGER_CST
-	    || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15))
-	  return false;
-	gimple_seq stmts = NULL;
-	location_t loc = gimple_location (stmt);
-	tree splat_value = gimple_convert (&stmts, loc,
-					   TREE_TYPE (TREE_TYPE (lhs)), arg0);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value);
-	g = gimple_build_assign (lhs, splat_tree);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* Flavors of vec_splat.  */
-    /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...};  */
-    case RS6000_BIF_VSPLTB:
-    case RS6000_BIF_VSPLTH:
-    case RS6000_BIF_VSPLTW:
-    case RS6000_BIF_XXSPLTD_V2DI:
-    case RS6000_BIF_XXSPLTD_V2DF:
-      {
-	arg0 = gimple_call_arg (stmt, 0); /* input vector.  */
-	arg1 = gimple_call_arg (stmt, 1); /* index into arg0.  */
-	/* Only fold the vec_splat_*() if arg1 is both a constant value and
-	   is a valid index into the arg0 vector.  */
-	unsigned int n_elts = VECTOR_CST_NELTS (arg0);
-	if (TREE_CODE (arg1) != INTEGER_CST
-	    || TREE_INT_CST_LOW (arg1) > (n_elts -1))
-	  return false;
-	lhs = gimple_call_lhs (stmt);
-	tree lhs_type = TREE_TYPE (lhs);
-	tree arg0_type = TREE_TYPE (arg0);
-	tree splat;
-	if (TREE_CODE (arg0) == VECTOR_CST)
-	  splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1));
-	else
-	  {
-	    /* Determine (in bits) the length and start location of the
-	       splat value for a call to the tree_vec_extract helper.  */
-	    int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type))
-				  * BITS_PER_UNIT / n_elts;
-	    int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size;
-	    tree len = build_int_cst (bitsizetype, splat_elem_size);
-	    tree start = build_int_cst (bitsizetype, splat_start_bit);
-	    splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0,
-				      len, start);
-	  }
-	/* And finally, build the new vector.  */
-	tree splat_tree = build_vector_from_val (lhs_type, splat);
-	g = gimple_build_assign (lhs, splat_tree);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* vec_mergel (integrals).  */
-    case RS6000_BIF_VMRGLH:
-    case RS6000_BIF_VMRGLW:
-    case RS6000_BIF_XXMRGLW_4SI:
-    case RS6000_BIF_VMRGLB:
-    case RS6000_BIF_VEC_MERGEL_V2DI:
-    case RS6000_BIF_XXMRGLW_4SF:
-    case RS6000_BIF_VEC_MERGEL_V2DF:
-      fold_mergehl_helper (gsi, stmt, 1);
-      return true;
-    /* vec_mergeh (integrals).  */
-    case RS6000_BIF_VMRGHH:
-    case RS6000_BIF_VMRGHW:
-    case RS6000_BIF_XXMRGHW_4SI:
-    case RS6000_BIF_VMRGHB:
-    case RS6000_BIF_VEC_MERGEH_V2DI:
-    case RS6000_BIF_XXMRGHW_4SF:
-    case RS6000_BIF_VEC_MERGEH_V2DF:
-      fold_mergehl_helper (gsi, stmt, 0);
-      return true;
-
-    /* Flavors of vec_mergee.  */
-    case RS6000_BIF_VMRGEW_V4SI:
-    case RS6000_BIF_VMRGEW_V2DI:
-    case RS6000_BIF_VMRGEW_V4SF:
-    case RS6000_BIF_VMRGEW_V2DF:
-      fold_mergeeo_helper (gsi, stmt, 0);
-      return true;
-    /* Flavors of vec_mergeo.  */
-    case RS6000_BIF_VMRGOW_V4SI:
-    case RS6000_BIF_VMRGOW_V2DI:
-    case RS6000_BIF_VMRGOW_V4SF:
-    case RS6000_BIF_VMRGOW_V2DF:
-      fold_mergeeo_helper (gsi, stmt, 1);
-      return true;
-
-    /* d = vec_pack (a, b) */
-    case RS6000_BIF_VPKUDUM:
-    case RS6000_BIF_VPKUHUM:
-    case RS6000_BIF_VPKUWUM:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	lhs = gimple_call_lhs (stmt);
-	gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    /* d = vec_unpackh (a) */
-    /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call
-       in this code is sensitive to endian-ness, and needs to be inverted to
-       handle both LE and BE targets.  */
-    case RS6000_BIF_VUPKHSB:
-    case RS6000_BIF_VUPKHSH:
-    case RS6000_BIF_VUPKHSW:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	lhs = gimple_call_lhs (stmt);
-	if (BYTES_BIG_ENDIAN)
-	  g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0);
-	else
-	  g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* d = vec_unpackl (a) */
-    case RS6000_BIF_VUPKLSB:
-    case RS6000_BIF_VUPKLSH:
-    case RS6000_BIF_VUPKLSW:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	lhs = gimple_call_lhs (stmt);
-	if (BYTES_BIG_ENDIAN)
-	  g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0);
-	else
-	  g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0);
-	gimple_set_location (g, gimple_location (stmt));
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-    /* There is no gimple type corresponding with pixel, so just return.  */
-    case RS6000_BIF_VUPKHPX:
-    case RS6000_BIF_VUPKLPX:
-      return false;
-
-    /* vec_perm.  */
-    case RS6000_BIF_VPERM_16QI:
-    case RS6000_BIF_VPERM_8HI:
-    case RS6000_BIF_VPERM_4SI:
-    case RS6000_BIF_VPERM_2DI:
-    case RS6000_BIF_VPERM_4SF:
-    case RS6000_BIF_VPERM_2DF:
-    case RS6000_BIF_VPERM_16QI_UNS:
-    case RS6000_BIF_VPERM_8HI_UNS:
-    case RS6000_BIF_VPERM_4SI_UNS:
-    case RS6000_BIF_VPERM_2DI_UNS:
-      {
-	arg0 = gimple_call_arg (stmt, 0);
-	arg1 = gimple_call_arg (stmt, 1);
-	tree permute = gimple_call_arg (stmt, 2);
-	lhs = gimple_call_lhs (stmt);
-	location_t loc = gimple_location (stmt);
-	gimple_seq stmts = NULL;
-	// convert arg0 and arg1 to match the type of the permute
-	// for the VEC_PERM_EXPR operation.
-	tree permute_type = (TREE_TYPE (permute));
-	tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
-					permute_type, arg0);
-	tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
-					permute_type, arg1);
-	tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR,
-				      permute_type, arg0_ptype, arg1_ptype,
-				      permute);
-	// Convert the result back to the desired lhs type upon completion.
-	tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
-				  TREE_TYPE (lhs), lhs_ptype);
-	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
-	g = gimple_build_assign (lhs, temp);
-	gimple_set_location (g, loc);
-	gsi_replace (gsi, g, true);
-	return true;
-      }
-
-    default:
-      if (TARGET_DEBUG_BUILTIN)
-	fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n",
-		 fn_code, fn_name1, fn_name2);
-      break;
-    }
-
-  return false;
-}
-
-/* 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).
-   SUBTARGET may be used as the target for computing one of EXP's operands.
-   IGNORE is nonzero if the value is to be ignored.  */
-
-rtx
-rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
-		       machine_mode mode ATTRIBUTE_UNUSED,
-		       int ignore ATTRIBUTE_UNUSED)
-{
-  if (new_builtins_are_live)
-    return rs6000_expand_new_builtin (exp, target, subtarget, mode, ignore);
-
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  enum rs6000_builtins fcode
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  size_t uns_fcode = (size_t)fcode;
-  const struct builtin_description *d;
-  size_t i;
-  rtx ret;
-  bool success;
-  HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
-  bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
-  enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
-
-  /* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit
-     floating point type, depending on whether long double is the IBM extended
-     double (KFmode) or long double is IEEE 128-bit (TFmode).  It is simpler if
-     we only define one variant of the built-in function, and switch the code
-     when defining it, rather than defining two built-ins and using the
-     overload table in rs6000-c.c to switch between the two.  If we don't have
-     the proper assembler, don't do this switch because CODE_FOR_*kf* and
-     CODE_FOR_*tf* will be CODE_FOR_nothing.  */
-  if (FLOAT128_IEEE_P (TFmode))
-    switch (icode)
-      {
-      default:
-	break;
-
-      case CODE_FOR_sqrtkf2_odd:	icode = CODE_FOR_sqrttf2_odd;	break;
-      case CODE_FOR_trunckfdf2_odd:	icode = CODE_FOR_trunctfdf2_odd; break;
-      case CODE_FOR_addkf3_odd:		icode = CODE_FOR_addtf3_odd;	break;
-      case CODE_FOR_subkf3_odd:		icode = CODE_FOR_subtf3_odd;	break;
-      case CODE_FOR_mulkf3_odd:		icode = CODE_FOR_multf3_odd;	break;
-      case CODE_FOR_divkf3_odd:		icode = CODE_FOR_divtf3_odd;	break;
-      case CODE_FOR_fmakf4_odd:		icode = CODE_FOR_fmatf4_odd;	break;
-      case CODE_FOR_xsxexpqp_kf:	icode = CODE_FOR_xsxexpqp_tf;	break;
-      case CODE_FOR_xsxsigqp_kf:	icode = CODE_FOR_xsxsigqp_tf;	break;
-      case CODE_FOR_xststdcnegqp_kf:	icode = CODE_FOR_xststdcnegqp_tf; break;
-      case CODE_FOR_xsiexpqp_kf:	icode = CODE_FOR_xsiexpqp_tf;	break;
-      case CODE_FOR_xsiexpqpf_kf:	icode = CODE_FOR_xsiexpqpf_tf;	break;
-      case CODE_FOR_xststdcqp_kf:	icode = CODE_FOR_xststdcqp_tf;	break;
-
-      case CODE_FOR_xscmpexpqp_eq_kf:
-	icode = CODE_FOR_xscmpexpqp_eq_tf;
-	break;
-
-      case CODE_FOR_xscmpexpqp_lt_kf:
-	icode = CODE_FOR_xscmpexpqp_lt_tf;
-	break;
-
-      case CODE_FOR_xscmpexpqp_gt_kf:
-	icode = CODE_FOR_xscmpexpqp_gt_tf;
-	break;
-
-      case CODE_FOR_xscmpexpqp_unordered_kf:
-	icode = CODE_FOR_xscmpexpqp_unordered_tf;
-	break;
-      }
-
-  if (TARGET_DEBUG_BUILTIN)
-    {
-      const char *name1 = rs6000_builtin_info[uns_fcode].name;
-      const char *name2 = (icode != CODE_FOR_nothing)
-			   ? get_insn_name ((int) icode)
-			   : "nothing";
-      const char *name3;
-
-      switch (rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_TYPE_MASK)
-	{
-	default:		   name3 = "unknown";	break;
-	case RS6000_BTC_SPECIAL:   name3 = "special";	break;
-	case RS6000_BTC_UNARY:	   name3 = "unary";	break;
-	case RS6000_BTC_BINARY:	   name3 = "binary";	break;
-	case RS6000_BTC_TERNARY:   name3 = "ternary";	break;
-	case RS6000_BTC_QUATERNARY:name3 = "quaternary";break;
-	case RS6000_BTC_PREDICATE: name3 = "predicate";	break;
-	case RS6000_BTC_ABS:	   name3 = "abs";	break;
-	case RS6000_BTC_DST:	   name3 = "dst";	break;
-	}
-
-
-      fprintf (stderr,
-	       "rs6000_expand_builtin, %s (%d), insn = %s (%d), type=%s%s\n",
-	       (name1) ? name1 : "---", fcode,
-	       (name2) ? name2 : "---", (int) icode,
-	       name3,
-	       func_valid_p ? "" : ", not valid");
-    }	     
-
-  if (!func_valid_p)
-    {
-      rs6000_invalid_builtin (fcode);
-
-      /* Given it is invalid, just generate a normal call.  */
-      return expand_call (exp, target, ignore);
-    }
-
-  switch (fcode)
-    {
-    case RS6000_BUILTIN_RECIP:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
-    case RS6000_BUILTIN_RECIPF:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
-    case RS6000_BUILTIN_RSQRTF:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
-    case RS6000_BUILTIN_RSQRT:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
-    case POWER7_BUILTIN_BPERMD:
-      return rs6000_expand_binop_builtin (((TARGET_64BIT)
-					   ? CODE_FOR_bpermd_di
-					   : CODE_FOR_bpermd_si), exp, target);
-
-    case RS6000_BUILTIN_GET_TB:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
-					   target);
-
-    case RS6000_BUILTIN_MFTB:
-      return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
-					    ? CODE_FOR_rs6000_mftb_di
-					    : CODE_FOR_rs6000_mftb_si),
-					   target);
-
-    case RS6000_BUILTIN_MFFS:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
-
-    case RS6000_BUILTIN_MTFSB0:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
-
-    case RS6000_BUILTIN_MTFSB1:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
-
-    case RS6000_BUILTIN_SET_FPSCR_RN:
-      return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
-						 exp);
-
-    case RS6000_BUILTIN_SET_FPSCR_DRN:
-      return
-        rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
-					     exp);
-
-    case RS6000_BUILTIN_MFFSL:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
-
-    case RS6000_BUILTIN_MTFSF:
-      return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
-
-    case RS6000_BUILTIN_CPU_INIT:
-    case RS6000_BUILTIN_CPU_IS:
-    case RS6000_BUILTIN_CPU_SUPPORTS:
-      return cpu_expand_builtin (fcode, exp, target);
-
-    case MISC_BUILTIN_SPEC_BARRIER:
-      {
-	emit_insn (gen_speculation_barrier ());
-	return NULL_RTX;
-      }
-
-    case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
-      {
-	int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
-		     : (int) CODE_FOR_altivec_lvsl_direct);
-	machine_mode tmode = insn_data[icode2].operand[0].mode;
-	machine_mode mode = insn_data[icode2].operand[1].mode;
-	tree arg;
-	rtx op, addr, pat;
-
-	gcc_assert (TARGET_ALTIVEC);
-
-	arg = CALL_EXPR_ARG (exp, 0);
-	gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
-	op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
-	addr = memory_address (mode, op);
-	/* We need to negate the address.  */
-	op = gen_reg_rtx (GET_MODE (addr));
-	emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
-	op = gen_rtx_MEM (mode, op);
-
-	if (target == 0
-	    || GET_MODE (target) != tmode
-	    || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
-	  target = gen_reg_rtx (tmode);
-
-	pat = GEN_FCN (icode2) (target, op);
-	if (!pat)
-	  return 0;
-	emit_insn (pat);
-
-	return target;
-      }
-
-    case ALTIVEC_BUILTIN_VCFUX:
-    case ALTIVEC_BUILTIN_VCFSX:
-    case ALTIVEC_BUILTIN_VCTUXS:
-    case ALTIVEC_BUILTIN_VCTSXS:
-  /* FIXME: There's got to be a nicer way to handle this case than
-     constructing a new CALL_EXPR.  */
-      if (call_expr_nargs (exp) == 1)
-	{
-	  exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
-				 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
-	}
-      break;
-
-      /* For the pack and unpack int128 routines, fix up the builtin so it
-	 uses the correct IBM128 type.  */
-    case MISC_BUILTIN_PACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
-	{
-	  icode = CODE_FOR_packtf;
-	  fcode = MISC_BUILTIN_PACK_TF;
-	  uns_fcode = (size_t)fcode;
-	}
-      break;
-
-    case MISC_BUILTIN_UNPACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
-	{
-	  icode = CODE_FOR_unpacktf;
-	  fcode = MISC_BUILTIN_UNPACK_TF;
-	  uns_fcode = (size_t)fcode;
-	}
-      break;
-
-    default:
-      break;
-    }
-
-  if (TARGET_MMA)
-    {
-      ret = mma_expand_builtin (exp, target, &success);
-
-      if (success)
-	return ret;
-    }
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
-
-      if (success)
-	return ret;
-    }
-  if (TARGET_HTM)
-    {
-      ret = htm_expand_builtin (exp, target, &success);
-
-      if (success)
-	return ret;
-    }  
-
-  unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK;
-  /* RS6000_BTC_SPECIAL represents no-operand operators.  */
-  gcc_assert (attr == RS6000_BTC_UNARY
-	      || attr == RS6000_BTC_BINARY
-	      || attr == RS6000_BTC_TERNARY
-	      || attr == RS6000_BTC_QUATERNARY
-	      || attr == RS6000_BTC_SPECIAL);
-  
-  /* Handle simple unary operations.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (icode, exp, target);
-
-  /* Handle simple binary operations.  */
-  d = bdesc_2arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_binop_builtin (icode, exp, target);
-
-  /* Handle simple ternary operations.  */
-  d = bdesc_3arg;
-  for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_ternop_builtin (icode, exp, target);
-
-  /* Handle simple quaternary operations.  */
-  d = bdesc_4arg;
-  for (i = 0; i < ARRAY_SIZE  (bdesc_4arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_quaternop_builtin (icode, exp, target);
-
-  /* Handle simple no-argument operations. */
-  d = bdesc_0arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_zeroop_builtin (icode, target);
-
-  gcc_unreachable ();
-}
-
-/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD.  */
-rtx
-rs6000_expand_ldst_mask (rtx target, tree arg0)
-{
-  int icode2 = BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
-				: (int) CODE_FOR_altivec_lvsl_direct;
-  machine_mode tmode = insn_data[icode2].operand[0].mode;
-  machine_mode mode = insn_data[icode2].operand[1].mode;
-
-  gcc_assert (TARGET_ALTIVEC);
-
-  gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
-  rtx op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
-  rtx addr = memory_address (mode, op);
-  /* We need to negate the address.  */
-  op = gen_reg_rtx (GET_MODE (addr));
-  emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
-  op = gen_rtx_MEM (mode, op);
-
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || !insn_data[icode2].operand[0].predicate (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  rtx pat = GEN_FCN (icode2) (target, op);
-  if (!pat)
-    return 0;
-  emit_insn (pat);
-
-  return target;
-}
-
-/* Expand the CPU builtin in FCODE and store the result in TARGET.  */
-static rtx
-new_cpu_expand_builtin (enum rs6000_gen_builtins fcode,
-			tree exp ATTRIBUTE_UNUSED, rtx target)
-{
-  /* __builtin_cpu_init () is a nop, so expand to nothing.  */
-  if (fcode == RS6000_BIF_CPU_INIT)
-    return const0_rtx;
-
-  if (target == 0 || GET_MODE (target) != SImode)
-    target = gen_reg_rtx (SImode);
-
-  /* TODO: Factor the #ifdef'd code into a separate function.  */
-#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
-  tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
-  /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back
-     to a STRING_CST.  */
-  if (TREE_CODE (arg) == ARRAY_REF
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST
-      && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST
-      && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0)
-    arg = TREE_OPERAND (arg, 0);
-
-  if (TREE_CODE (arg) != STRING_CST)
-    {
-      error ("builtin %qs only accepts a string argument",
-	     rs6000_builtin_info_x[(size_t) fcode].bifname);
-      return const0_rtx;
-    }
-
-  if (fcode == RS6000_BIF_CPU_IS)
-    {
-      const char *cpu = TREE_STRING_POINTER (arg);
-      rtx cpuid = NULL_RTX;
-      for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++)
-	if (strcmp (cpu, cpu_is_info[i].cpu) == 0)
-	  {
-	    /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM.  */
-	    cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM);
-	    break;
-	  }
-      if (cpuid == NULL_RTX)
-	{
-	  /* Invalid CPU argument.  */
-	  error ("cpu %qs is an invalid argument to builtin %qs",
-		 cpu, rs6000_builtin_info_x[(size_t) fcode].bifname);
-	  return const0_rtx;
-	}
-
-      rtx platform = gen_reg_rtx (SImode);
-      rtx address = gen_rtx_PLUS (Pmode,
-				  gen_rtx_REG (Pmode, TLS_REGNUM),
-				  GEN_INT (TCB_PLATFORM_OFFSET));
-      rtx tcbmem = gen_const_mem (SImode, address);
-      emit_move_insn (platform, tcbmem);
-      emit_insn (gen_eqsi3 (target, platform, cpuid));
-    }
-  else if (fcode == RS6000_BIF_CPU_SUPPORTS)
-    {
-      const char *hwcap = TREE_STRING_POINTER (arg);
-      rtx mask = NULL_RTX;
-      int hwcap_offset;
-      for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++)
-	if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0)
-	  {
-	    mask = GEN_INT (cpu_supports_info[i].mask);
-	    hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id);
-	    break;
-	  }
-      if (mask == NULL_RTX)
-	{
-	  /* Invalid HWCAP argument.  */
-	  error ("%s %qs is an invalid argument to builtin %qs",
-		 "hwcap", hwcap,
-		 rs6000_builtin_info_x[(size_t) fcode].bifname);
-	  return const0_rtx;
-	}
-
-      rtx tcb_hwcap = gen_reg_rtx (SImode);
-      rtx address = gen_rtx_PLUS (Pmode,
-				  gen_rtx_REG (Pmode, TLS_REGNUM),
-				  GEN_INT (hwcap_offset));
-      rtx tcbmem = gen_const_mem (SImode, address);
-      emit_move_insn (tcb_hwcap, tcbmem);
-      rtx scratch1 = gen_reg_rtx (SImode);
-      emit_insn (gen_rtx_SET (scratch1,
-			      gen_rtx_AND (SImode, tcb_hwcap, mask)));
-      rtx scratch2 = gen_reg_rtx (SImode);
-      emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx));
-      emit_insn (gen_rtx_SET (target,
-			      gen_rtx_XOR (SImode, scratch2, const1_rtx)));
-    }
-  else
-    gcc_unreachable ();
-
-  /* Record that we have expanded a CPU builtin, so that we can later
-     emit a reference to the special symbol exported by LIBC to ensure we
-     do not link against an old LIBC that doesn't support this feature.  */
-  cpu_builtin_p = true;
-
-#else
-  warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware "
-	   "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname);
-
-  /* For old LIBCs, always return FALSE.  */
-  emit_move_insn (target, GEN_INT (0));
-#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */
-
-  return target;
-}
-
-/* For the element-reversing load/store built-ins, produce the correct
-   insn_code depending on the target endianness.  */
-static insn_code
-elemrev_icode (rs6000_gen_builtins fcode)
-{
-  switch (fcode)
-    {
-    case RS6000_BIF_ST_ELEMREV_V1TI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
-			      : CODE_FOR_vsx_st_elemrev_v1ti;
-
-    case RS6000_BIF_ST_ELEMREV_V2DF:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
-			      : CODE_FOR_vsx_st_elemrev_v2df;
-
-    case RS6000_BIF_ST_ELEMREV_V2DI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
-			      : CODE_FOR_vsx_st_elemrev_v2di;
-
-    case RS6000_BIF_ST_ELEMREV_V4SF:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
-			      : CODE_FOR_vsx_st_elemrev_v4sf;
-
-    case RS6000_BIF_ST_ELEMREV_V4SI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
-			      : CODE_FOR_vsx_st_elemrev_v4si;
-
-    case RS6000_BIF_ST_ELEMREV_V8HI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
-			      : CODE_FOR_vsx_st_elemrev_v8hi;
-
-    case RS6000_BIF_ST_ELEMREV_V16QI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
-			      : CODE_FOR_vsx_st_elemrev_v16qi;
-
-    case RS6000_BIF_LD_ELEMREV_V2DF:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
-			      : CODE_FOR_vsx_ld_elemrev_v2df;
-
-    case RS6000_BIF_LD_ELEMREV_V1TI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
-			      : CODE_FOR_vsx_ld_elemrev_v1ti;
-
-    case RS6000_BIF_LD_ELEMREV_V2DI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
-			      : CODE_FOR_vsx_ld_elemrev_v2di;
-
-    case RS6000_BIF_LD_ELEMREV_V4SF:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
-			      : CODE_FOR_vsx_ld_elemrev_v4sf;
-
-    case RS6000_BIF_LD_ELEMREV_V4SI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
-			      : CODE_FOR_vsx_ld_elemrev_v4si;
-
-    case RS6000_BIF_LD_ELEMREV_V8HI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
-			      : CODE_FOR_vsx_ld_elemrev_v8hi;
-
-    case RS6000_BIF_LD_ELEMREV_V16QI:
-      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
-			      : CODE_FOR_vsx_ld_elemrev_v16qi;
-    default:
-      ;
-    }
-
-  gcc_unreachable ();
-}
-
-/* Expand an AltiVec vector load builtin, and return the expanded rtx.  */
-static rtx
-ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
-{
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || !insn_data[icode].operand[0].predicate (target, tmode))
-    target = gen_reg_rtx (tmode);
-
-  op[1] = copy_to_mode_reg (Pmode, op[1]);
-
-  /* These CELL built-ins use BLKmode instead of tmode for historical
-     (i.e., unknown) reasons.  TODO: Is this necessary?  */
-  bool blk = (icode == CODE_FOR_altivec_lvlx
-	      || icode == CODE_FOR_altivec_lvlxl
-	      || icode == CODE_FOR_altivec_lvrx
-	      || icode == CODE_FOR_altivec_lvrxl);
-
-  /* For LVX, express the RTL accurately by ANDing the address with -16.
-     LVXL and LVE*X expand to use UNSPECs to hide their special behavior,
-     so the raw address is fine.  */
-  /* TODO: That statement seems wrong, as the UNSPECs don't surround the
-     memory expression, so a latent bug may lie here.  The &-16 is likely
-     needed for all VMX-style loads.  */
-  if (icode == CODE_FOR_altivec_lvx_v1ti
-      || icode == CODE_FOR_altivec_lvx_v2df
-      || icode == CODE_FOR_altivec_lvx_v2di
-      || icode == CODE_FOR_altivec_lvx_v4sf
-      || icode == CODE_FOR_altivec_lvx_v4si
-      || icode == CODE_FOR_altivec_lvx_v8hi
-      || icode == CODE_FOR_altivec_lvx_v16qi)
-    {
-      rtx rawaddr;
-      if (op[0] == const0_rtx)
-	rawaddr = op[1];
-      else
-	{
-	  op[0] = copy_to_mode_reg (Pmode, op[0]);
-	  rawaddr = gen_rtx_PLUS (Pmode, op[1], op[0]);
-	}
-      rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16));
-      addr = gen_rtx_MEM (blk ? BLKmode : tmode, addr);
-
-      emit_insn (gen_rtx_SET (target, addr));
-    }
-  else
-    {
-      rtx addr;
-      if (op[0] == const0_rtx)
-	addr = gen_rtx_MEM (blk ? BLKmode : tmode, op[1]);
-      else
-	{
-	  op[0] = copy_to_mode_reg (Pmode, op[0]);
-	  addr = gen_rtx_MEM (blk ? BLKmode : tmode,
-			      gen_rtx_PLUS (Pmode, op[1], op[0]));
-	}
-
-      rtx pat = GEN_FCN (icode) (target, addr);
-      if (!pat)
-	return 0;
-      emit_insn (pat);
-    }
-
-  return target;
-}
-
-/* Expand a builtin function that loads a scalar into a vector register
-   with sign extension, and return the expanded rtx.  */
-static rtx
-lxvrse_expand_builtin (rtx target, insn_code icode, rtx *op,
-		       machine_mode tmode, machine_mode smode)
-{
-  rtx pat, addr;
-  op[1] = copy_to_mode_reg (Pmode, op[1]);
-
-  if (op[0] == const0_rtx)
-    addr = gen_rtx_MEM (tmode, op[1]);
-  else
-    {
-      op[0] = copy_to_mode_reg (Pmode, op[0]);
-      addr = gen_rtx_MEM (smode,
-			  gen_rtx_PLUS (Pmode, op[1], op[0]));
-    }
-
-  rtx discratch = gen_reg_rtx (V2DImode);
-  rtx tiscratch = gen_reg_rtx (TImode);
-
-  /* Emit the lxvr*x insn.  */
-  pat = GEN_FCN (icode) (tiscratch, addr);
-  if (!pat)
-    return 0;
-  emit_insn (pat);
-
-  /* Emit a sign extension from V16QI,V8HI,V4SI to V2DI.  */
-  rtx temp1;
-  if (icode == CODE_FOR_vsx_lxvrbx)
-    {
-      temp1  = simplify_gen_subreg (V16QImode, tiscratch, TImode, 0);
-      emit_insn (gen_vsx_sign_extend_qi_v2di (discratch, temp1));
-    }
-  else if (icode == CODE_FOR_vsx_lxvrhx)
-    {
-      temp1  = simplify_gen_subreg (V8HImode, tiscratch, TImode, 0);
-      emit_insn (gen_vsx_sign_extend_hi_v2di (discratch, temp1));
-    }
-  else if (icode == CODE_FOR_vsx_lxvrwx)
-    {
-      temp1  = simplify_gen_subreg (V4SImode, tiscratch, TImode, 0);
-      emit_insn (gen_vsx_sign_extend_si_v2di (discratch, temp1));
-    }
-  else if (icode == CODE_FOR_vsx_lxvrdx)
-    discratch = simplify_gen_subreg (V2DImode, tiscratch, TImode, 0);
-  else
-    gcc_unreachable ();
-
-  /* Emit the sign extension from V2DI (double) to TI (quad).  */
-  rtx temp2 = simplify_gen_subreg (TImode, discratch, V2DImode, 0);
-  emit_insn (gen_extendditi2_vector (target, temp2));
-
-  return target;
-}
-
-/* Expand a builtin function that loads a scalar into a vector register
-   with zero extension, and return the expanded rtx.  */
-static rtx
-lxvrze_expand_builtin (rtx target, insn_code icode, rtx *op,
-		       machine_mode tmode, machine_mode smode)
-{
-  rtx pat, addr;
-  op[1] = copy_to_mode_reg (Pmode, op[1]);
-
-  if (op[0] == const0_rtx)
-    addr = gen_rtx_MEM (tmode, op[1]);
-  else
-    {
-      op[0] = copy_to_mode_reg (Pmode, op[0]);
-      addr = gen_rtx_MEM (smode,
-			  gen_rtx_PLUS (Pmode, op[1], op[0]));
-    }
-
-  pat = GEN_FCN (icode) (target, addr);
-  if (!pat)
-    return 0;
-  emit_insn (pat);
-  return target;
-}
-
-/* Expand an AltiVec vector store builtin, and return the expanded rtx.  */
-static rtx
-stv_expand_builtin (insn_code icode, rtx *op,
-		    machine_mode tmode, machine_mode smode)
-{
-  op[2] = copy_to_mode_reg (Pmode, op[2]);
-
-  /* For STVX, express the RTL accurately by ANDing the address with -16.
-     STVXL and STVE*X expand to use UNSPECs to hide their special behavior,
-     so the raw address is fine.  */
-  /* TODO: That statement seems wrong, as the UNSPECs don't surround the
-     memory expression, so a latent bug may lie here.  The &-16 is likely
-     needed for all VMX-style stores.  */
-  if (icode == CODE_FOR_altivec_stvx_v2df
-      || icode == CODE_FOR_altivec_stvx_v2di
-      || icode == CODE_FOR_altivec_stvx_v4sf
-      || icode == CODE_FOR_altivec_stvx_v4si
-      || icode == CODE_FOR_altivec_stvx_v8hi
-      || icode == CODE_FOR_altivec_stvx_v16qi)
-    {
-      rtx rawaddr;
-      if (op[1] == const0_rtx)
-	rawaddr = op[2];
-      else
-	{
-	  op[1] = copy_to_mode_reg (Pmode, op[1]);
-	  rawaddr = gen_rtx_PLUS (Pmode, op[2], op[1]);
-	}
-
-      rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16));
-      addr = gen_rtx_MEM (tmode, addr);
-      op[0] = copy_to_mode_reg (tmode, op[0]);
-      emit_insn (gen_rtx_SET (addr, op[0]));
-    }
-  else if (icode == CODE_FOR_vsx_stxvrbx
-	   || icode == CODE_FOR_vsx_stxvrhx
-	   || icode == CODE_FOR_vsx_stxvrwx
-	   || icode == CODE_FOR_vsx_stxvrdx)
-    {
-      rtx truncrtx = gen_rtx_TRUNCATE (tmode, op[0]);
-      op[0] = copy_to_mode_reg (E_TImode, truncrtx);
-
-      rtx addr;
-      if (op[1] == const0_rtx)
-	addr = gen_rtx_MEM (Pmode, op[2]);
-      else
-	{
-	  op[1] = copy_to_mode_reg (Pmode, op[1]);
-	  addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1]));
-	}
-      rtx pat = GEN_FCN (icode) (addr, op[0]);
-      if (pat)
-	emit_insn (pat);
-    }
-  else
-    {
-      if (!insn_data[icode].operand[1].predicate (op[0], smode))
-	op[0] = copy_to_mode_reg (smode, op[0]);
-
-      rtx addr;
-      if (op[1] == const0_rtx)
-	addr = gen_rtx_MEM (tmode, op[2]);
-      else
-	{
-	  op[1] = copy_to_mode_reg (Pmode, op[1]);
-	  addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1]));
-	}
-
-      rtx pat = GEN_FCN (icode) (addr, op[0]);
-      if (pat)
-	emit_insn (pat);
-    }
-
-  return NULL_RTX;
-}
-
-/* Expand the MMA built-in in EXP, and return it.  */
-static rtx
-new_mma_expand_builtin (tree exp, rtx target, insn_code icode,
-			rs6000_gen_builtins fcode)
-{
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
-  machine_mode tmode = VOIDmode;
-  rtx op[MAX_MMA_OPERANDS];
-  unsigned nopnds = 0;
-
-  if (!void_func)
-    {
-      tmode = insn_data[icode].operand[0].mode;
-      if (!(target
-	    && GET_MODE (target) == tmode
-	    && insn_data[icode].operand[0].predicate (target, tmode)))
-	target = gen_reg_rtx (tmode);
-      op[nopnds++] = target;
-    }
-  else
-    target = const0_rtx;
-
-  call_expr_arg_iterator iter;
-  tree arg;
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
-    {
-      if (arg == error_mark_node)
-	return const0_rtx;
-
-      rtx opnd;
-      const struct insn_operand_data *insn_op;
-      insn_op = &insn_data[icode].operand[nopnds];
-      if (TREE_CODE (arg) == ADDR_EXPR
-	  && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0))))
-	opnd = DECL_RTL (TREE_OPERAND (arg, 0));
-      else
-	opnd = expand_normal (arg);
-
-      if (!insn_op->predicate (opnd, insn_op->mode))
-	{
-	  /* TODO: This use of constraints needs explanation.  */
-	  if (!strcmp (insn_op->constraint, "n"))
-	    {
-	      if (!CONST_INT_P (opnd))
-		error ("argument %d must be an unsigned literal", nopnds);
-	      else
-		error ("argument %d is an unsigned literal that is "
-		       "out of range", nopnds);
-	      return const0_rtx;
-	    }
-	  opnd = copy_to_mode_reg (insn_op->mode, opnd);
-	}
-
-      /* Some MMA instructions have INOUT accumulator operands, so force
-	 their target register to be the same as their input register.  */
-      if (!void_func
-	  && nopnds == 1
-	  && !strcmp (insn_op->constraint, "0")
-	  && insn_op->mode == tmode
-	  && REG_P (opnd)
-	  && insn_data[icode].operand[0].predicate (opnd, tmode))
-	target = op[0] = opnd;
-
-      op[nopnds++] = opnd;
-    }
-
-  rtx pat;
-  switch (nopnds)
-    {
-    case 1:
-      pat = GEN_FCN (icode) (op[0]);
-      break;
-    case 2:
-      pat = GEN_FCN (icode) (op[0], op[1]);
-      break;
-    case 3:
-      /* The ASSEMBLE builtin source operands are reversed in little-endian
-	 mode, so reorder them.  */
-      if (fcode == RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL && !WORDS_BIG_ENDIAN)
-	std::swap (op[1], op[2]);
-      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
-      break;
-    case 4:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
-      break;
-    case 5:
-      /* The ASSEMBLE builtin source operands are reversed in little-endian
-	 mode, so reorder them.  */
-      if (fcode == RS6000_BIF_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN)
-	{
-	  std::swap (op[1], op[4]);
-	  std::swap (op[2], op[3]);
-	}
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
-      break;
-    case 6:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
-      break;
-    case 7:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  if (!pat)
-    return NULL_RTX;
-
-  emit_insn (pat);
-  return target;
-}
-
-/* Return the appropriate SPR number associated with the given builtin.  */
-static inline HOST_WIDE_INT
-new_htm_spr_num (enum rs6000_gen_builtins code)
-{
-  if (code == RS6000_BIF_GET_TFHAR
-      || code == RS6000_BIF_SET_TFHAR)
-    return TFHAR_SPR;
-  else if (code == RS6000_BIF_GET_TFIAR
-	   || code == RS6000_BIF_SET_TFIAR)
-    return TFIAR_SPR;
-  else if (code == RS6000_BIF_GET_TEXASR
-	   || code == RS6000_BIF_SET_TEXASR)
-    return TEXASR_SPR;
-  gcc_assert (code == RS6000_BIF_GET_TEXASRU
-	      || code == RS6000_BIF_SET_TEXASRU);
-  return TEXASRU_SPR;
-}
-
-/* Expand the HTM builtin in EXP and store the result in TARGET.
-   Return the expanded rtx.  */
-static rtx
-new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode,
-			tree exp, rtx target)
-{
-  if (!TARGET_POWERPC64
-      && (fcode == RS6000_BIF_TABORTDC
-	  || fcode == RS6000_BIF_TABORTDCI))
-    {
-      error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname);
-      return const0_rtx;
-    }
-
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
-  bool uses_spr = bif_is_htmspr (*bifaddr);
-  insn_code icode = bifaddr->icode;
-
-  if (uses_spr)
-    icode = rs6000_htm_spr_icode (nonvoid);
-
-  rtx op[MAX_HTM_OPERANDS];
-  int nopnds = 0;
-  const insn_operand_data *insn_op = &insn_data[icode].operand[0];
-
-  if (nonvoid)
-    {
-      machine_mode tmode = (uses_spr) ? insn_op->mode : E_SImode;
-      if (!target
-	  || GET_MODE (target) != tmode
-	  || (uses_spr && !insn_op->predicate (target, tmode)))
-	target = gen_reg_rtx (tmode);
-      if (uses_spr)
-	op[nopnds++] = target;
-    }
-
-  tree arg;
-  call_expr_arg_iterator iter;
-
-  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
-    {
-      if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS)
-	return const0_rtx;
-
-      insn_op = &insn_data[icode].operand[nopnds];
-      op[nopnds] = expand_normal (arg);
-
-      if (!insn_op->predicate (op[nopnds], insn_op->mode))
-	{
-	  /* TODO: This use of constraints could use explanation.
-	     This happens a couple of places, perhaps make that a
-	     function to document what's happening.  */
-	  if (!strcmp (insn_op->constraint, "n"))
-	    {
-	      int arg_num = nonvoid ? nopnds : nopnds + 1;
-	      if (!CONST_INT_P (op[nopnds]))
-		error ("argument %d must be an unsigned literal", arg_num);
-	      else
-		error ("argument %d is an unsigned literal that is "
-		       "out of range", arg_num);
-	      return const0_rtx;
-	    }
-	  op[nopnds] = copy_to_mode_reg (insn_op->mode, op[nopnds]);
-	}
-
-      nopnds++;
-    }
-
-  /* Handle the builtins for extended mnemonics.  These accept
-     no arguments, but map to builtins that take arguments.  */
-  switch (fcode)
-    {
-    case RS6000_BIF_TENDALL:  /* Alias for: tend. 1  */
-    case RS6000_BIF_TRESUME:  /* Alias for: tsr. 1  */
-      op[nopnds++] = GEN_INT (1);
-      break;
-    case RS6000_BIF_TSUSPEND: /* Alias for: tsr. 0  */
-      op[nopnds++] = GEN_INT (0);
-      break;
-    default:
-      break;
-    }
+      arg1 = gimple_call_arg (stmt, 1);
+      lhs = gimple_call_lhs (stmt);
+      g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1);
+      gimple_set_location (g, gimple_location (stmt));
+      gsi_replace (gsi, g, true);
+      return true;
+  /* Flavors of vector shift right algebraic.
+     vec_sra{b,h,w} -> vsra{b,h,w}.  */
+    case RS6000_BIF_VSRAB:
+    case RS6000_BIF_VSRAH:
+    case RS6000_BIF_VSRAW:
+    case RS6000_BIF_VSRAD:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	arg1 = gimple_call_arg (stmt, 1);
+	lhs = gimple_call_lhs (stmt);
+	tree arg1_type = TREE_TYPE (arg1);
+	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
+	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
+	location_t loc = gimple_location (stmt);
+	/* Force arg1 into the range valid matching the arg0 type.  */
+	/* Build a vector consisting of the max valid bit-size values.  */
+	int n_elts = VECTOR_CST_NELTS (arg1);
+	tree element_size = build_int_cst (unsigned_element_type,
+					   128 / n_elts);
+	tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
+	for (int i = 0; i < n_elts; i++)
+	  elts.safe_push (element_size);
+	tree modulo_tree = elts.build ();
+	/* Modulo the provided shift value against that vector.  */
+	gimple_seq stmts = NULL;
+	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+					   unsigned_arg1_type, arg1);
+	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
+				      unsigned_arg1_type, unsigned_arg1,
+				      modulo_tree);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	/* And finally, do the shift.  */
+	g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1);
+	gimple_set_location (g, loc);
+	gsi_replace (gsi, g, true);
+	return true;
+      }
+   /* Flavors of vector shift left.
+      builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}.  */
+    case RS6000_BIF_VSLB:
+    case RS6000_BIF_VSLH:
+    case RS6000_BIF_VSLW:
+    case RS6000_BIF_VSLD:
+      {
+	location_t loc;
+	gimple_seq stmts = NULL;
+	arg0 = gimple_call_arg (stmt, 0);
+	tree arg0_type = TREE_TYPE (arg0);
+	if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type))
+	    && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type)))
+	  return false;
+	arg1 = gimple_call_arg (stmt, 1);
+	tree arg1_type = TREE_TYPE (arg1);
+	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
+	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
+	loc = gimple_location (stmt);
+	lhs = gimple_call_lhs (stmt);
+	/* Force arg1 into the range valid matching the arg0 type.  */
+	/* Build a vector consisting of the max valid bit-size values.  */
+	int n_elts = VECTOR_CST_NELTS (arg1);
+	int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type))
+				* BITS_PER_UNIT;
+	tree element_size = build_int_cst (unsigned_element_type,
+					   tree_size_in_bits / n_elts);
+	tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1);
+	for (int i = 0; i < n_elts; i++)
+	  elts.safe_push (element_size);
+	tree modulo_tree = elts.build ();
+	/* Modulo the provided shift value against that vector.  */
+	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+					   unsigned_arg1_type, arg1);
+	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
+				      unsigned_arg1_type, unsigned_arg1,
+				      modulo_tree);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	/* And finally, do the shift.  */
+	g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
+      }
+    /* Flavors of vector shift right.  */
+    case RS6000_BIF_VSRB:
+    case RS6000_BIF_VSRH:
+    case RS6000_BIF_VSRW:
+    case RS6000_BIF_VSRD:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	arg1 = gimple_call_arg (stmt, 1);
+	lhs = gimple_call_lhs (stmt);
+	tree arg1_type = TREE_TYPE (arg1);
+	tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1));
+	tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type));
+	location_t loc = gimple_location (stmt);
+	gimple_seq stmts = NULL;
+	/* Convert arg0 to unsigned.  */
+	tree arg0_unsigned
+	  = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+			  unsigned_type_for (TREE_TYPE (arg0)), arg0);
+	/* Force arg1 into the range valid matching the arg0 type.  */
+	/* Build a vector consisting of the max valid bit-size values.  */
+	int n_elts = VECTOR_CST_NELTS (arg1);
+	tree element_size = build_int_cst (unsigned_element_type,
+					   128 / n_elts);
+	tree_vector_builder elts (unsigned_arg1_type, n_elts, 1);
+	for (int i = 0; i < n_elts; i++)
+	  elts.safe_push (element_size);
+	tree modulo_tree = elts.build ();
+	/* Modulo the provided shift value against that vector.  */
+	tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR,
+					   unsigned_arg1_type, arg1);
+	tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR,
+				      unsigned_arg1_type, unsigned_arg1,
+				      modulo_tree);
+	/* Do the shift.  */
+	tree res
+	  = gimple_build (&stmts, RSHIFT_EXPR,
+			  TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1);
+	/* Convert result back to the lhs type.  */
+	res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	replace_call_with_value (gsi, res);
+	return true;
+      }
+    /* Vector loads.  */
+    case RS6000_BIF_LVX_V16QI:
+    case RS6000_BIF_LVX_V8HI:
+    case RS6000_BIF_LVX_V4SI:
+    case RS6000_BIF_LVX_V4SF:
+    case RS6000_BIF_LVX_V2DI:
+    case RS6000_BIF_LVX_V2DF:
+    case RS6000_BIF_LVX_V1TI:
+      {
+	arg0 = gimple_call_arg (stmt, 0);  // offset
+	arg1 = gimple_call_arg (stmt, 1);  // address
+	lhs = gimple_call_lhs (stmt);
+	location_t loc = gimple_location (stmt);
+	/* Since arg1 may be cast to a different type, just use ptr_type_node
+	   here instead of trying to enforce TBAA on pointer types.  */
+	tree arg1_type = ptr_type_node;
+	tree lhs_type = TREE_TYPE (lhs);
+	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
+	   the tree using the value from arg0.  The resulting type will match
+	   the type of arg1.  */
+	gimple_seq stmts = NULL;
+	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
+	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+				       arg1_type, arg1, temp_offset);
+	/* Mask off any lower bits from the address.  */
+	tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
+					  arg1_type, temp_addr,
+					  build_int_cst (arg1_type, -16));
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	if (!is_gimple_mem_ref_addr (aligned_addr))
+	  {
+	    tree t = make_ssa_name (TREE_TYPE (aligned_addr));
+	    gimple *g = gimple_build_assign (t, aligned_addr);
+	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	    aligned_addr = t;
+	  }
+	/* Use the build2 helper to set up the mem_ref.  The MEM_REF could also
+	   take an offset, but since we've already incorporated the offset
+	   above, here we just pass in a zero.  */
+	gimple *g
+	  = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr,
+					      build_int_cst (arg1_type, 0)));
+	gimple_set_location (g, loc);
+	gsi_replace (gsi, g, true);
+	return true;
+      }
+    /* Vector stores.  */
+    case RS6000_BIF_STVX_V16QI:
+    case RS6000_BIF_STVX_V8HI:
+    case RS6000_BIF_STVX_V4SI:
+    case RS6000_BIF_STVX_V4SF:
+    case RS6000_BIF_STVX_V2DI:
+    case RS6000_BIF_STVX_V2DF:
+      {
+	arg0 = gimple_call_arg (stmt, 0); /* Value to be stored.  */
+	arg1 = gimple_call_arg (stmt, 1); /* Offset.  */
+	tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address.  */
+	location_t loc = gimple_location (stmt);
+	tree arg0_type = TREE_TYPE (arg0);
+	/* Use ptr_type_node (no TBAA) for the arg2_type.
+	   FIXME: (Richard)  "A proper fix would be to transition this type as
+	   seen from the frontend to GIMPLE, for example in a similar way we
+	   do for MEM_REFs by piggy-backing that on an extra argument, a
+	   constant zero pointer of the alias pointer type to use (which would
+	   also serve as a type indicator of the store itself).  I'd use a
+	   target specific internal function for this (not sure if we can have
+	   those target specific, but I guess if it's folded away then that's
+	   fine) and get away with the overload set."  */
+	tree arg2_type = ptr_type_node;
+	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
+	   the tree using the value from arg0.  The resulting type will match
+	   the type of arg2.  */
+	gimple_seq stmts = NULL;
+	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
+	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+				       arg2_type, arg2, temp_offset);
+	/* Mask off any lower bits from the address.  */
+	tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
+					  arg2_type, temp_addr,
+					  build_int_cst (arg2_type, -16));
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	if (!is_gimple_mem_ref_addr (aligned_addr))
+	  {
+	    tree t = make_ssa_name (TREE_TYPE (aligned_addr));
+	    gimple *g = gimple_build_assign (t, aligned_addr);
+	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	    aligned_addr = t;
+	  }
+	/* The desired gimple result should be similar to:
+	   MEM[(__vector floatD.1407 *)_1] = vf1D.2697;  */
+	gimple *g
+	  = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr,
+					 build_int_cst (arg2_type, 0)), arg0);
+	gimple_set_location (g, loc);
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  /* If this builtin accesses SPRs, then pass in the appropriate
-     SPR number and SPR regno as the last two operands.  */
-  rtx cr = NULL_RTX;
-  if (uses_spr)
-    {
-      machine_mode mode = TARGET_POWERPC64 ? DImode : SImode;
-      op[nopnds++] = gen_rtx_CONST_INT (mode, new_htm_spr_num (fcode));
-    }
-  /* If this builtin accesses a CR field, then pass in a scratch
-     CR field as the last operand.  */
-  else if (bif_is_htmcr (*bifaddr))
-    {
-      cr = gen_reg_rtx (CCmode);
-      op[nopnds++] = cr;
-    }
+    /* unaligned Vector loads.  */
+    case RS6000_BIF_LXVW4X_V16QI:
+    case RS6000_BIF_LXVW4X_V8HI:
+    case RS6000_BIF_LXVW4X_V4SF:
+    case RS6000_BIF_LXVW4X_V4SI:
+    case RS6000_BIF_LXVD2X_V2DF:
+    case RS6000_BIF_LXVD2X_V2DI:
+      {
+	arg0 = gimple_call_arg (stmt, 0);  // offset
+	arg1 = gimple_call_arg (stmt, 1);  // address
+	lhs = gimple_call_lhs (stmt);
+	location_t loc = gimple_location (stmt);
+	/* Since arg1 may be cast to a different type, just use ptr_type_node
+	   here instead of trying to enforce TBAA on pointer types.  */
+	tree arg1_type = ptr_type_node;
+	tree lhs_type = TREE_TYPE (lhs);
+	/* In GIMPLE the type of the MEM_REF specifies the alignment.  The
+	  required alignment (power) is 4 bytes regardless of data type.  */
+	tree align_ltype = build_aligned_type (lhs_type, 4);
+	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
+	   the tree using the value from arg0.  The resulting type will match
+	   the type of arg1.  */
+	gimple_seq stmts = NULL;
+	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0);
+	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+				       arg1_type, arg1, temp_offset);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	if (!is_gimple_mem_ref_addr (temp_addr))
+	  {
+	    tree t = make_ssa_name (TREE_TYPE (temp_addr));
+	    gimple *g = gimple_build_assign (t, temp_addr);
+	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	    temp_addr = t;
+	  }
+	/* Use the build2 helper to set up the mem_ref.  The MEM_REF could also
+	   take an offset, but since we've already incorporated the offset
+	   above, here we just pass in a zero.  */
+	gimple *g;
+	g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr,
+					      build_int_cst (arg1_type, 0)));
+	gimple_set_location (g, loc);
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  rtx pat;
-  switch (nopnds)
-    {
-    case 1:
-      pat = GEN_FCN (icode) (op[0]);
-      break;
-    case 2:
-      pat = GEN_FCN (icode) (op[0], op[1]);
-      break;
-    case 3:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
-      break;
-    case 4:
-      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-  if (!pat)
-    return NULL_RTX;
-  emit_insn (pat);
+    /* unaligned Vector stores.  */
+    case RS6000_BIF_STXVW4X_V16QI:
+    case RS6000_BIF_STXVW4X_V8HI:
+    case RS6000_BIF_STXVW4X_V4SF:
+    case RS6000_BIF_STXVW4X_V4SI:
+    case RS6000_BIF_STXVD2X_V2DF:
+    case RS6000_BIF_STXVD2X_V2DI:
+      {
+	arg0 = gimple_call_arg (stmt, 0); /* Value to be stored.  */
+	arg1 = gimple_call_arg (stmt, 1); /* Offset.  */
+	tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address.  */
+	location_t loc = gimple_location (stmt);
+	tree arg0_type = TREE_TYPE (arg0);
+	/* Use ptr_type_node (no TBAA) for the arg2_type.  */
+	tree arg2_type = ptr_type_node;
+	/* In GIMPLE the type of the MEM_REF specifies the alignment.  The
+	   required alignment (power) is 4 bytes regardless of data type.  */
+	tree align_stype = build_aligned_type (arg0_type, 4);
+	/* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'.  Create
+	   the tree using the value from arg1.  */
+	gimple_seq stmts = NULL;
+	tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
+	tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+				       arg2_type, arg2, temp_offset);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	if (!is_gimple_mem_ref_addr (temp_addr))
+	  {
+	    tree t = make_ssa_name (TREE_TYPE (temp_addr));
+	    gimple *g = gimple_build_assign (t, temp_addr);
+	    gsi_insert_before (gsi, g, GSI_SAME_STMT);
+	    temp_addr = t;
+	  }
+	gimple *g;
+	g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr,
+					 build_int_cst (arg2_type, 0)), arg0);
+	gimple_set_location (g, loc);
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  if (bif_is_htmcr (*bifaddr))
-    {
-      if (fcode == RS6000_BIF_TBEGIN)
-	{
-	  /* Emit code to set TARGET to true or false depending on
-	     whether the tbegin. instruction succeeded or failed
-	     to start a transaction.  We do this by placing the 1's
-	     complement of CR's EQ bit into TARGET.  */
-	  rtx scratch = gen_reg_rtx (SImode);
-	  emit_insn (gen_rtx_SET (scratch,
-				  gen_rtx_EQ (SImode, cr,
-					      const0_rtx)));
-	  emit_insn (gen_rtx_SET (target,
-				  gen_rtx_XOR (SImode, scratch,
-					       GEN_INT (1))));
-	}
-      else
-	{
-	  /* Emit code to copy the 4-bit condition register field
-	     CR into the least significant end of register TARGET.  */
-	  rtx scratch1 = gen_reg_rtx (SImode);
-	  rtx scratch2 = gen_reg_rtx (SImode);
-	  rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0);
-	  emit_insn (gen_movcc (subreg, cr));
-	  emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28)));
-	  emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf)));
-	}
-    }
+    /* Vector Fused multiply-add (fma).  */
+    case RS6000_BIF_VMADDFP:
+    case RS6000_BIF_XVMADDDP:
+    case RS6000_BIF_XVMADDSP:
+    case RS6000_BIF_VMLADDUHM:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	arg1 = gimple_call_arg (stmt, 1);
+	tree arg2 = gimple_call_arg (stmt, 2);
+	lhs = gimple_call_lhs (stmt);
+	gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2);
+	gimple_call_set_lhs (g, lhs);
+	gimple_call_set_nothrow (g, true);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  if (nonvoid)
-    return target;
-  return const0_rtx;
-}
+    /* Vector compares; EQ, NE, GE, GT, LE.  */
+    case RS6000_BIF_VCMPEQUB:
+    case RS6000_BIF_VCMPEQUH:
+    case RS6000_BIF_VCMPEQUW:
+    case RS6000_BIF_VCMPEQUD:
+    /* We deliberately omit RS6000_BIF_VCMPEQUT for now, because gimple
+       folding produces worse code for 128-bit compares.  */
+      fold_compare_helper (gsi, EQ_EXPR, stmt);
+      return true;
 
-/* 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).
-   SUBTARGET may be used as the target for computing one of EXP's operands.
-   IGNORE is nonzero if the value is to be ignored.
-   Use the new builtin infrastructure.  */
-static rtx
-rs6000_expand_new_builtin (tree exp, rtx target,
-			   rtx /* subtarget */,
-			   machine_mode /* mode */,
-			   int ignore)
-{
-  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  enum rs6000_gen_builtins fcode
-    = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  size_t uns_fcode = (size_t)fcode;
-  enum insn_code icode = rs6000_builtin_info_x[uns_fcode].icode;
+    case RS6000_BIF_VCMPNEB:
+    case RS6000_BIF_VCMPNEH:
+    case RS6000_BIF_VCMPNEW:
+    /* We deliberately omit RS6000_BIF_VCMPNET for now, because gimple
+       folding produces worse code for 128-bit compares.  */
+      fold_compare_helper (gsi, NE_EXPR, stmt);
+      return true;
 
-  /* TODO: The following commentary and code is inherited from the original
-     builtin processing code.  The commentary is a bit confusing, with the
-     intent being that KFmode is always IEEE-128, IFmode is always IBM
-     double-double, and TFmode is the current long double.  The code is
-     confusing in that it converts from KFmode to TFmode pattern names,
-     when the other direction is more intuitive.  Try to address this.  */
+    case RS6000_BIF_CMPGE_16QI:
+    case RS6000_BIF_CMPGE_U16QI:
+    case RS6000_BIF_CMPGE_8HI:
+    case RS6000_BIF_CMPGE_U8HI:
+    case RS6000_BIF_CMPGE_4SI:
+    case RS6000_BIF_CMPGE_U4SI:
+    case RS6000_BIF_CMPGE_2DI:
+    case RS6000_BIF_CMPGE_U2DI:
+    /* We deliberately omit RS6000_BIF_CMPGE_1TI and RS6000_BIF_CMPGE_U1TI
+       for now, because gimple folding produces worse code for 128-bit
+       compares.  */
+      fold_compare_helper (gsi, GE_EXPR, stmt);
+      return true;
 
-  /* We have two different modes (KFmode, TFmode) that are the IEEE
-     128-bit floating point type, depending on whether long double is the
-     IBM extended double (KFmode) or long double is IEEE 128-bit (TFmode).
-     It is simpler if we only define one variant of the built-in function,
-     and switch the code when defining it, rather than defining two built-
-     ins and using the overload table in rs6000-c.c to switch between the
-     two.  If we don't have the proper assembler, don't do this switch
-     because CODE_FOR_*kf* and CODE_FOR_*tf* will be CODE_FOR_nothing.  */
-  if (FLOAT128_IEEE_P (TFmode))
-    switch (icode)
-      {
-      case CODE_FOR_sqrtkf2_odd:
-	icode = CODE_FOR_sqrttf2_odd;
-	break;
-      case CODE_FOR_trunckfdf2_odd:
-	icode = CODE_FOR_trunctfdf2_odd;
-	break;
-      case CODE_FOR_addkf3_odd:
-	icode = CODE_FOR_addtf3_odd;
-	break;
-      case CODE_FOR_subkf3_odd:
-	icode = CODE_FOR_subtf3_odd;
-	break;
-      case CODE_FOR_mulkf3_odd:
-	icode = CODE_FOR_multf3_odd;
-	break;
-      case CODE_FOR_divkf3_odd:
-	icode = CODE_FOR_divtf3_odd;
-	break;
-      case CODE_FOR_fmakf4_odd:
-	icode = CODE_FOR_fmatf4_odd;
-	break;
-      case CODE_FOR_xsxexpqp_kf:
-	icode = CODE_FOR_xsxexpqp_tf;
-	break;
-      case CODE_FOR_xsxsigqp_kf:
-	icode = CODE_FOR_xsxsigqp_tf;
-	break;
-      case CODE_FOR_xststdcnegqp_kf:
-	icode = CODE_FOR_xststdcnegqp_tf;
-	break;
-      case CODE_FOR_xsiexpqp_kf:
-	icode = CODE_FOR_xsiexpqp_tf;
-	break;
-      case CODE_FOR_xsiexpqpf_kf:
-	icode = CODE_FOR_xsiexpqpf_tf;
-	break;
-      case CODE_FOR_xststdcqp_kf:
-	icode = CODE_FOR_xststdcqp_tf;
-	break;
-      case CODE_FOR_xscmpexpqp_eq_kf:
-	icode = CODE_FOR_xscmpexpqp_eq_tf;
-	break;
-      case CODE_FOR_xscmpexpqp_lt_kf:
-	icode = CODE_FOR_xscmpexpqp_lt_tf;
-	break;
-      case CODE_FOR_xscmpexpqp_gt_kf:
-	icode = CODE_FOR_xscmpexpqp_gt_tf;
-	break;
-      case CODE_FOR_xscmpexpqp_unordered_kf:
-	icode = CODE_FOR_xscmpexpqp_unordered_tf;
-	break;
-      default:
-	break;
+    case RS6000_BIF_VCMPGTSB:
+    case RS6000_BIF_VCMPGTUB:
+    case RS6000_BIF_VCMPGTSH:
+    case RS6000_BIF_VCMPGTUH:
+    case RS6000_BIF_VCMPGTSW:
+    case RS6000_BIF_VCMPGTUW:
+    case RS6000_BIF_VCMPGTUD:
+    case RS6000_BIF_VCMPGTSD:
+    /* We deliberately omit RS6000_BIF_VCMPGTUT and RS6000_BIF_VCMPGTST
+       for now, because gimple folding produces worse code for 128-bit
+       compares.  */
+      fold_compare_helper (gsi, GT_EXPR, stmt);
+      return true;
+
+    case RS6000_BIF_CMPLE_16QI:
+    case RS6000_BIF_CMPLE_U16QI:
+    case RS6000_BIF_CMPLE_8HI:
+    case RS6000_BIF_CMPLE_U8HI:
+    case RS6000_BIF_CMPLE_4SI:
+    case RS6000_BIF_CMPLE_U4SI:
+    case RS6000_BIF_CMPLE_2DI:
+    case RS6000_BIF_CMPLE_U2DI:
+    /* We deliberately omit RS6000_BIF_CMPLE_1TI and RS6000_BIF_CMPLE_U1TI
+       for now, because gimple folding produces worse code for 128-bit
+       compares.  */
+      fold_compare_helper (gsi, LE_EXPR, stmt);
+      return true;
+
+    /* flavors of vec_splat_[us]{8,16,32}.  */
+    case RS6000_BIF_VSPLTISB:
+    case RS6000_BIF_VSPLTISH:
+    case RS6000_BIF_VSPLTISW:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	lhs = gimple_call_lhs (stmt);
+
+	/* Only fold the vec_splat_*() if the lower bits of arg 0 is a
+	   5-bit signed constant in range -16 to +15.  */
+	if (TREE_CODE (arg0) != INTEGER_CST
+	    || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15))
+	  return false;
+	gimple_seq stmts = NULL;
+	location_t loc = gimple_location (stmt);
+	tree splat_value = gimple_convert (&stmts, loc,
+					   TREE_TYPE (TREE_TYPE (lhs)), arg0);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value);
+	g = gimple_build_assign (lhs, splat_tree);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
       }
 
-  /* In case of "#pragma target" changes, we initialize all builtins
-     but check for actual availability now, during expand time.  For
-     invalid builtins, generate a normal call.  */
-  bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
-  bif_enable e = bifaddr->enable;
+    /* Flavors of vec_splat.  */
+    /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...};  */
+    case RS6000_BIF_VSPLTB:
+    case RS6000_BIF_VSPLTH:
+    case RS6000_BIF_VSPLTW:
+    case RS6000_BIF_XXSPLTD_V2DI:
+    case RS6000_BIF_XXSPLTD_V2DF:
+      {
+	arg0 = gimple_call_arg (stmt, 0); /* input vector.  */
+	arg1 = gimple_call_arg (stmt, 1); /* index into arg0.  */
+	/* Only fold the vec_splat_*() if arg1 is both a constant value and
+	   is a valid index into the arg0 vector.  */
+	unsigned int n_elts = VECTOR_CST_NELTS (arg0);
+	if (TREE_CODE (arg1) != INTEGER_CST
+	    || TREE_INT_CST_LOW (arg1) > (n_elts -1))
+	  return false;
+	lhs = gimple_call_lhs (stmt);
+	tree lhs_type = TREE_TYPE (lhs);
+	tree arg0_type = TREE_TYPE (arg0);
+	tree splat;
+	if (TREE_CODE (arg0) == VECTOR_CST)
+	  splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1));
+	else
+	  {
+	    /* Determine (in bits) the length and start location of the
+	       splat value for a call to the tree_vec_extract helper.  */
+	    int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type))
+				  * BITS_PER_UNIT / n_elts;
+	    int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size;
+	    tree len = build_int_cst (bitsizetype, splat_elem_size);
+	    tree start = build_int_cst (bitsizetype, splat_start_bit);
+	    splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0,
+				      len, start);
+	  }
+	/* And finally, build the new vector.  */
+	tree splat_tree = build_vector_from_val (lhs_type, splat);
+	g = gimple_build_assign (lhs, splat_tree);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  if (!(e == ENB_ALWAYS
-	|| (e == ENB_P5 && TARGET_POPCNTB)
-	|| (e == ENB_P6 && TARGET_CMPB)
-	|| (e == ENB_P6_64 && TARGET_CMPB && TARGET_POWERPC64)
-	|| (e == ENB_ALTIVEC && TARGET_ALTIVEC)
-	|| (e == ENB_CELL && TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL)
-	|| (e == ENB_VSX && TARGET_VSX)
-	|| (e == ENB_P7 && TARGET_POPCNTD)
-	|| (e == ENB_P7_64 && TARGET_POPCNTD && TARGET_POWERPC64)
-	|| (e == ENB_P8 && TARGET_DIRECT_MOVE)
-	|| (e == ENB_P8V && TARGET_P8_VECTOR)
-	|| (e == ENB_P9 && TARGET_MODULO)
-	|| (e == ENB_P9_64 && TARGET_MODULO && TARGET_POWERPC64)
-	|| (e == ENB_P9V && TARGET_P9_VECTOR)
-	|| (e == ENB_IEEE128_HW && TARGET_FLOAT128_HW)
-	|| (e == ENB_DFP && TARGET_DFP)
-	|| (e == ENB_CRYPTO && TARGET_CRYPTO)
-	|| (e == ENB_HTM && TARGET_HTM)
-	|| (e == ENB_P10 && TARGET_POWER10)
-	|| (e == ENB_P10_64 && TARGET_POWER10 && TARGET_POWERPC64)
-	|| (e == ENB_MMA && TARGET_MMA)))
-    {
-      rs6000_invalid_new_builtin (fcode);
-      return expand_call (exp, target, ignore);
-    }
+    /* vec_mergel (integrals).  */
+    case RS6000_BIF_VMRGLH:
+    case RS6000_BIF_VMRGLW:
+    case RS6000_BIF_XXMRGLW_4SI:
+    case RS6000_BIF_VMRGLB:
+    case RS6000_BIF_VEC_MERGEL_V2DI:
+    case RS6000_BIF_XXMRGLW_4SF:
+    case RS6000_BIF_VEC_MERGEL_V2DF:
+      fold_mergehl_helper (gsi, stmt, 1);
+      return true;
+    /* vec_mergeh (integrals).  */
+    case RS6000_BIF_VMRGHH:
+    case RS6000_BIF_VMRGHW:
+    case RS6000_BIF_XXMRGHW_4SI:
+    case RS6000_BIF_VMRGHB:
+    case RS6000_BIF_VEC_MERGEH_V2DI:
+    case RS6000_BIF_XXMRGHW_4SF:
+    case RS6000_BIF_VEC_MERGEH_V2DF:
+      fold_mergehl_helper (gsi, stmt, 0);
+      return true;
 
-  if (bif_is_nosoft (*bifaddr)
-      && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
-    {
-      error ("%<%s%> not supported with %<-msoft-float%>",
-	     bifaddr->bifname);
-      return const0_rtx;
-    }
+    /* Flavors of vec_mergee.  */
+    case RS6000_BIF_VMRGEW_V4SI:
+    case RS6000_BIF_VMRGEW_V2DI:
+    case RS6000_BIF_VMRGEW_V4SF:
+    case RS6000_BIF_VMRGEW_V2DF:
+      fold_mergeeo_helper (gsi, stmt, 0);
+      return true;
+    /* Flavors of vec_mergeo.  */
+    case RS6000_BIF_VMRGOW_V4SI:
+    case RS6000_BIF_VMRGOW_V2DI:
+    case RS6000_BIF_VMRGOW_V4SF:
+    case RS6000_BIF_VMRGOW_V2DF:
+      fold_mergeeo_helper (gsi, stmt, 1);
+      return true;
 
-  if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
-    {
-      error ("%<%s%> is not supported in 32-bit mode", bifaddr->bifname);
-      return const0_rtx;
-    }
+    /* d = vec_pack (a, b) */
+    case RS6000_BIF_VPKUDUM:
+    case RS6000_BIF_VPKUHUM:
+    case RS6000_BIF_VPKUWUM:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	arg1 = gimple_call_arg (stmt, 1);
+	lhs = gimple_call_lhs (stmt);
+	gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  if (bif_is_ibmld (*bifaddr) && !FLOAT128_2REG_P (TFmode))
-    {
-      error ("%<%s%> requires %<long double%> to be IBM 128-bit format",
-	     bifaddr->bifname);
-      return const0_rtx;
-    }
+    /* d = vec_unpackh (a) */
+    /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call
+       in this code is sensitive to endian-ness, and needs to be inverted to
+       handle both LE and BE targets.  */
+    case RS6000_BIF_VUPKHSB:
+    case RS6000_BIF_VUPKHSH:
+    case RS6000_BIF_VUPKHSW:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	lhs = gimple_call_lhs (stmt);
+	if (BYTES_BIG_ENDIAN)
+	  g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0);
+	else
+	  g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
+      }
+    /* d = vec_unpackl (a) */
+    case RS6000_BIF_VUPKLSB:
+    case RS6000_BIF_VUPKLSH:
+    case RS6000_BIF_VUPKLSW:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	lhs = gimple_call_lhs (stmt);
+	if (BYTES_BIG_ENDIAN)
+	  g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0);
+	else
+	  g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0);
+	gimple_set_location (g, gimple_location (stmt));
+	gsi_replace (gsi, g, true);
+	return true;
+      }
+    /* There is no gimple type corresponding with pixel, so just return.  */
+    case RS6000_BIF_VUPKHPX:
+    case RS6000_BIF_VUPKLPX:
+      return false;
 
-  if (bif_is_cpu (*bifaddr))
-    return new_cpu_expand_builtin (fcode, exp, target);
+    /* vec_perm.  */
+    case RS6000_BIF_VPERM_16QI:
+    case RS6000_BIF_VPERM_8HI:
+    case RS6000_BIF_VPERM_4SI:
+    case RS6000_BIF_VPERM_2DI:
+    case RS6000_BIF_VPERM_4SF:
+    case RS6000_BIF_VPERM_2DF:
+    case RS6000_BIF_VPERM_16QI_UNS:
+    case RS6000_BIF_VPERM_8HI_UNS:
+    case RS6000_BIF_VPERM_4SI_UNS:
+    case RS6000_BIF_VPERM_2DI_UNS:
+      {
+	arg0 = gimple_call_arg (stmt, 0);
+	arg1 = gimple_call_arg (stmt, 1);
+	tree permute = gimple_call_arg (stmt, 2);
+	lhs = gimple_call_lhs (stmt);
+	location_t loc = gimple_location (stmt);
+	gimple_seq stmts = NULL;
+	// convert arg0 and arg1 to match the type of the permute
+	// for the VEC_PERM_EXPR operation.
+	tree permute_type = (TREE_TYPE (permute));
+	tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
+					permute_type, arg0);
+	tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
+					permute_type, arg1);
+	tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR,
+				      permute_type, arg0_ptype, arg1_ptype,
+				      permute);
+	// Convert the result back to the desired lhs type upon completion.
+	tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR,
+				  TREE_TYPE (lhs), lhs_ptype);
+	gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	g = gimple_build_assign (lhs, temp);
+	gimple_set_location (g, loc);
+	gsi_replace (gsi, g, true);
+	return true;
+      }
 
-  if (bif_is_init (*bifaddr))
-    return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+    default:
+      if (TARGET_DEBUG_BUILTIN)
+	fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n",
+		 fn_code, fn_name1, fn_name2);
+      break;
+    }
 
-  if (bif_is_set (*bifaddr))
-    return altivec_expand_vec_set_builtin (exp);
+  return false;
+}
 
-  if (bif_is_extract (*bifaddr))
-    return altivec_expand_vec_ext_builtin (exp, target);
+/* 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).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
 
-  if (bif_is_predicate (*bifaddr))
-    return altivec_expand_predicate_builtin (icode, exp, target);
+rtx
+rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+		       machine_mode mode ATTRIBUTE_UNUSED,
+		       int ignore ATTRIBUTE_UNUSED)
+{
+  return rs6000_expand_new_builtin (exp, target, subtarget, mode, ignore);
+}
 
-  if (bif_is_htm (*bifaddr))
-    return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD.  */
+rtx
+rs6000_expand_ldst_mask (rtx target, tree arg0)
+{
+  int icode2 = BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+				: (int) CODE_FOR_altivec_lvsl_direct;
+  machine_mode tmode = insn_data[icode2].operand[0].mode;
+  machine_mode mode = insn_data[icode2].operand[1].mode;
 
-  if (bif_is_32bit (*bifaddr) && TARGET_32BIT)
-    {
-      if (fcode == RS6000_BIF_MFTB)
-	icode = CODE_FOR_rs6000_mftb_si;
-      else if (fcode == RS6000_BIF_BPERMD)
-	icode = CODE_FOR_bpermd_si;
-      else
-	gcc_unreachable ();
-    }
+  gcc_assert (TARGET_ALTIVEC);
 
-  if (bif_is_endian (*bifaddr) && BYTES_BIG_ENDIAN)
-    {
-      if (fcode == RS6000_BIF_LD_ELEMREV_V1TI)
-	icode = CODE_FOR_vsx_load_v1ti;
-      else if (fcode == RS6000_BIF_LD_ELEMREV_V2DF)
-	icode = CODE_FOR_vsx_load_v2df;
-      else if (fcode == RS6000_BIF_LD_ELEMREV_V2DI)
-	icode = CODE_FOR_vsx_load_v2di;
-      else if (fcode == RS6000_BIF_LD_ELEMREV_V4SF)
-	icode = CODE_FOR_vsx_load_v4sf;
-      else if (fcode == RS6000_BIF_LD_ELEMREV_V4SI)
-	icode = CODE_FOR_vsx_load_v4si;
-      else if (fcode == RS6000_BIF_LD_ELEMREV_V8HI)
-	icode = CODE_FOR_vsx_load_v8hi;
-      else if (fcode == RS6000_BIF_LD_ELEMREV_V16QI)
-	icode = CODE_FOR_vsx_load_v16qi;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V1TI)
-	icode = CODE_FOR_vsx_store_v1ti;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V2DF)
-	icode = CODE_FOR_vsx_store_v2df;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V2DI)
-	icode = CODE_FOR_vsx_store_v2di;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V4SF)
-	icode = CODE_FOR_vsx_store_v4sf;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V4SI)
-	icode = CODE_FOR_vsx_store_v4si;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V8HI)
-	icode = CODE_FOR_vsx_store_v8hi;
-      else if (fcode == RS6000_BIF_ST_ELEMREV_V16QI)
-	icode = CODE_FOR_vsx_store_v16qi;
-      else
-	gcc_unreachable ();
-    }
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
+  rtx op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
+  rtx addr = memory_address (mode, op);
+  /* We need to negate the address.  */
+  op = gen_reg_rtx (GET_MODE (addr));
+  emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+  op = gen_rtx_MEM (mode, op);
 
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || !insn_data[icode2].operand[0].predicate (target, tmode))
+    target = gen_reg_rtx (tmode);
 
-  /* TRUE iff the built-in function returns void.  */
-  bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
-  /* Position of first argument (0 for void-returning functions, else 1).  */
-  int k;
-  /* Modes for the return value, if any, and arguments.  */
-  const int MAX_BUILTIN_ARGS = 6;
-  machine_mode mode[MAX_BUILTIN_ARGS + 1];
+  rtx pat = GEN_FCN (icode2) (target, op);
+  if (!pat)
+    return 0;
+  emit_insn (pat);
 
-  if (void_func)
-    k = 0;
-  else
-    {
-      k = 1;
-      mode[0] = insn_data[icode].operand[0].mode;
-    }
+  return target;
+}
 
-  /* Tree expressions for each argument.  */
-  tree arg[MAX_BUILTIN_ARGS];
-  /* RTL expressions for each argument.  */
-  rtx op[MAX_BUILTIN_ARGS];
+/* Expand the CPU builtin in FCODE and store the result in TARGET.  */
+static rtx
+new_cpu_expand_builtin (enum rs6000_gen_builtins fcode,
+			tree exp ATTRIBUTE_UNUSED, rtx target)
+{
+  /* __builtin_cpu_init () is a nop, so expand to nothing.  */
+  if (fcode == RS6000_BIF_CPU_INIT)
+    return const0_rtx;
 
-  int nargs = bifaddr->nargs;
-  gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+  if (target == 0 || GET_MODE (target) != SImode)
+    target = gen_reg_rtx (SImode);
 
+  /* TODO: Factor the #ifdef'd code into a separate function.  */
+#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
+  tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0);
+  /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back
+     to a STRING_CST.  */
+  if (TREE_CODE (arg) == ARRAY_REF
+      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST
+      && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST
+      && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0)
+    arg = TREE_OPERAND (arg, 0);
 
-  for (int i = 0; i < nargs; i++)
+  if (TREE_CODE (arg) != STRING_CST)
     {
-      arg[i] = CALL_EXPR_ARG (exp, i);
-      if (arg[i] == error_mark_node)
-	return const0_rtx;
-      STRIP_NOPS (arg[i]);
-      op[i] = expand_normal (arg[i]);
-      /* We have a couple of pesky patterns that don't specify the mode...  */
-      mode[i+k] = insn_data[icode].operand[i+k].mode;
-      if (!mode[i+k])
-	mode[i+k] = Pmode;
+      error ("builtin %qs only accepts a string argument",
+	     rs6000_builtin_info_x[(size_t) fcode].bifname);
+      return const0_rtx;
     }
 
-  /* Check for restricted constant arguments.  */
-  for (int i = 0; i < 2; i++)
+  if (fcode == RS6000_BIF_CPU_IS)
     {
-      switch (bifaddr->restr[i])
-	{
-	case RES_BITS:
-	  {
-	    size_t mask = 1;
-	    mask <<= bifaddr->restr_val1[i];
-	    mask--;
-	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
-	    STRIP_NOPS (restr_arg);
-	    if (!(TREE_CODE (restr_arg) == INTEGER_CST
-		  && (TREE_INT_CST_LOW (restr_arg) & ~mask) == 0))
-	      {
-		error ("argument %d must be a %d-bit unsigned literal",
-		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
-		return CONST0_RTX (mode[0]);
-	      }
-	    break;
-	  }
-	case RES_RANGE:
-	  {
-	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
-	    STRIP_NOPS (restr_arg);
-	    if (!(TREE_CODE (restr_arg) == INTEGER_CST
-		  && IN_RANGE (tree_to_shwi (restr_arg),
-			       bifaddr->restr_val1[i],
-			       bifaddr->restr_val2[i])))
-	      {
-		error ("argument %d must be a literal between %d and %d,"
-		       " inclusive",
-		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
-		       bifaddr->restr_val2[i]);
-		return CONST0_RTX (mode[0]);
-	      }
-	    break;
-	  }
-	case RES_VAR_RANGE:
+      const char *cpu = TREE_STRING_POINTER (arg);
+      rtx cpuid = NULL_RTX;
+      for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++)
+	if (strcmp (cpu, cpu_is_info[i].cpu) == 0)
 	  {
-	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
-	    STRIP_NOPS (restr_arg);
-	    if (TREE_CODE (restr_arg) == INTEGER_CST
-		&& !IN_RANGE (tree_to_shwi (restr_arg),
-			      bifaddr->restr_val1[i],
-			      bifaddr->restr_val2[i]))
-	      {
-		error ("argument %d must be a variable or a literal "
-		       "between %d and %d, inclusive",
-		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
-		       bifaddr->restr_val2[i]);
-		return CONST0_RTX (mode[0]);
-	      }
+	    /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM.  */
+	    cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM);
 	    break;
 	  }
-	case RES_VALUES:
+      if (cpuid == NULL_RTX)
+	{
+	  /* Invalid CPU argument.  */
+	  error ("cpu %qs is an invalid argument to builtin %qs",
+		 cpu, rs6000_builtin_info_x[(size_t) fcode].bifname);
+	  return const0_rtx;
+	}
+
+      rtx platform = gen_reg_rtx (SImode);
+      rtx address = gen_rtx_PLUS (Pmode,
+				  gen_rtx_REG (Pmode, TLS_REGNUM),
+				  GEN_INT (TCB_PLATFORM_OFFSET));
+      rtx tcbmem = gen_const_mem (SImode, address);
+      emit_move_insn (platform, tcbmem);
+      emit_insn (gen_eqsi3 (target, platform, cpuid));
+    }
+  else if (fcode == RS6000_BIF_CPU_SUPPORTS)
+    {
+      const char *hwcap = TREE_STRING_POINTER (arg);
+      rtx mask = NULL_RTX;
+      int hwcap_offset;
+      for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++)
+	if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0)
 	  {
-	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
-	    STRIP_NOPS (restr_arg);
-	    if (!(TREE_CODE (restr_arg) == INTEGER_CST
-		  && (tree_to_shwi (restr_arg) == bifaddr->restr_val1[i]
-		      || tree_to_shwi (restr_arg) == bifaddr->restr_val2[i])))
-	      {
-		error ("argument %d must be either a literal %d or a "
-		       "literal %d",
-		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
-		       bifaddr->restr_val2[i]);
-		return CONST0_RTX (mode[0]);
-	      }
+	    mask = GEN_INT (cpu_supports_info[i].mask);
+	    hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id);
 	    break;
 	  }
-	default:
-	case RES_NONE:
-	  break;
+      if (mask == NULL_RTX)
+	{
+	  /* Invalid HWCAP argument.  */
+	  error ("%s %qs is an invalid argument to builtin %qs",
+		 "hwcap", hwcap,
+		 rs6000_builtin_info_x[(size_t) fcode].bifname);
+	  return const0_rtx;
 	}
+
+      rtx tcb_hwcap = gen_reg_rtx (SImode);
+      rtx address = gen_rtx_PLUS (Pmode,
+				  gen_rtx_REG (Pmode, TLS_REGNUM),
+				  GEN_INT (hwcap_offset));
+      rtx tcbmem = gen_const_mem (SImode, address);
+      emit_move_insn (tcb_hwcap, tcbmem);
+      rtx scratch1 = gen_reg_rtx (SImode);
+      emit_insn (gen_rtx_SET (scratch1,
+			      gen_rtx_AND (SImode, tcb_hwcap, mask)));
+      rtx scratch2 = gen_reg_rtx (SImode);
+      emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx));
+      emit_insn (gen_rtx_SET (target,
+			      gen_rtx_XOR (SImode, scratch2, const1_rtx)));
     }
+  else
+    gcc_unreachable ();
 
-  if (bif_is_ldstmask (*bifaddr))
-    return rs6000_expand_ldst_mask (target, arg[0]);
+  /* Record that we have expanded a CPU builtin, so that we can later
+     emit a reference to the special symbol exported by LIBC to ensure we
+     do not link against an old LIBC that doesn't support this feature.  */
+  cpu_builtin_p = true;
 
-  if (bif_is_stvec (*bifaddr))
-    {
-      if (bif_is_reve (*bifaddr))
-	icode = elemrev_icode (fcode);
-      return stv_expand_builtin (icode, op, mode[0], mode[1]);
-    }
+#else
+  warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware "
+	   "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname);
 
-  if (bif_is_ldvec (*bifaddr))
+  /* For old LIBCs, always return FALSE.  */
+  emit_move_insn (target, GEN_INT (0));
+#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */
+
+  return target;
+}
+
+/* For the element-reversing load/store built-ins, produce the correct
+   insn_code depending on the target endianness.  */
+static insn_code
+elemrev_icode (rs6000_gen_builtins fcode)
+{
+  switch (fcode)
     {
-      if (bif_is_reve (*bifaddr))
-	icode = elemrev_icode (fcode);
-      return ldv_expand_builtin (target, icode, op, mode[0]);
-    }
+    case RS6000_BIF_ST_ELEMREV_V1TI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
+			      : CODE_FOR_vsx_st_elemrev_v1ti;
 
-  if (bif_is_lxvrse (*bifaddr))
-    return lxvrse_expand_builtin (target, icode, op, mode[0], mode[1]);
+    case RS6000_BIF_ST_ELEMREV_V2DF:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
+			      : CODE_FOR_vsx_st_elemrev_v2df;
 
-  if (bif_is_lxvrze (*bifaddr))
-    return lxvrze_expand_builtin (target, icode, op, mode[0], mode[1]);
+    case RS6000_BIF_ST_ELEMREV_V2DI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
+			      : CODE_FOR_vsx_st_elemrev_v2di;
 
-  if (bif_is_mma (*bifaddr))
-    return new_mma_expand_builtin (exp, target, icode, fcode);
+    case RS6000_BIF_ST_ELEMREV_V4SF:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
+			      : CODE_FOR_vsx_st_elemrev_v4sf;
 
-  if (fcode == RS6000_BIF_PACK_IF
-      && TARGET_LONG_DOUBLE_128
-      && !TARGET_IEEEQUAD)
-    {
-      icode = CODE_FOR_packtf;
-      fcode = RS6000_BIF_PACK_TF;
-      uns_fcode = (size_t) fcode;
-    }
-  else if (fcode == RS6000_BIF_UNPACK_IF
-	   && TARGET_LONG_DOUBLE_128
-	   && !TARGET_IEEEQUAD)
-    {
-      icode = CODE_FOR_unpacktf;
-      fcode = RS6000_BIF_UNPACK_TF;
-      uns_fcode = (size_t) fcode;
-    }
+    case RS6000_BIF_ST_ELEMREV_V4SI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
+			      : CODE_FOR_vsx_st_elemrev_v4si;
 
-  if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node)
-    target = NULL_RTX;
-  else if (target == 0
-	   || GET_MODE (target) != mode[0]
-	   || !insn_data[icode].operand[0].predicate (target, mode[0]))
-    target = gen_reg_rtx (mode[0]);
+    case RS6000_BIF_ST_ELEMREV_V8HI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
+			      : CODE_FOR_vsx_st_elemrev_v8hi;
 
-  for (int i = 0; i < nargs; i++)
-    if (!insn_data[icode].operand[i+k].predicate (op[i], mode[i+k]))
-      op[i] = copy_to_mode_reg (mode[i+k], op[i]);
+    case RS6000_BIF_ST_ELEMREV_V16QI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
+			      : CODE_FOR_vsx_st_elemrev_v16qi;
 
-  rtx pat;
+    case RS6000_BIF_LD_ELEMREV_V2DF:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
+			      : CODE_FOR_vsx_ld_elemrev_v2df;
 
-  switch (nargs)
-    {
-    case 0:
-      pat = (void_func
-	     ? GEN_FCN (icode) ()
-	     : GEN_FCN (icode) (target));
-      break;
-    case 1:
-      pat = (void_func
-	     ? GEN_FCN (icode) (op[0])
-	     : GEN_FCN (icode) (target, op[0]));
-      break;
-    case 2:
-      pat = (void_func
-	     ? GEN_FCN (icode) (op[0], op[1])
-	     : GEN_FCN (icode) (target, op[0], op[1]));
-      break;
-    case 3:
-      pat = (void_func
-	     ? GEN_FCN (icode) (op[0], op[1], op[2])
-	     : GEN_FCN (icode) (target, op[0], op[1], op[2]));
-      break;
-    case 4:
-      pat = (void_func
-	     ? GEN_FCN (icode) (op[0], op[1], op[2], op[3])
-	     : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]));
-      break;
-    case 5:
-      pat = (void_func
-	     ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4])
-	     : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]));
-      break;
-    case 6:
-      pat = (void_func
-	     ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5])
-	     : GEN_FCN (icode) (target, op[0], op[1],
-				op[2], op[3], op[4], op[5]));
-      break;
+    case RS6000_BIF_LD_ELEMREV_V1TI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
+			      : CODE_FOR_vsx_ld_elemrev_v1ti;
+
+    case RS6000_BIF_LD_ELEMREV_V2DI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
+			      : CODE_FOR_vsx_ld_elemrev_v2di;
+
+    case RS6000_BIF_LD_ELEMREV_V4SF:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
+			      : CODE_FOR_vsx_ld_elemrev_v4sf;
+
+    case RS6000_BIF_LD_ELEMREV_V4SI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
+			      : CODE_FOR_vsx_ld_elemrev_v4si;
+
+    case RS6000_BIF_LD_ELEMREV_V8HI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
+			      : CODE_FOR_vsx_ld_elemrev_v8hi;
+
+    case RS6000_BIF_LD_ELEMREV_V16QI:
+      return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
+			      : CODE_FOR_vsx_ld_elemrev_v16qi;
     default:
-      gcc_assert (MAX_BUILTIN_ARGS == 6);
-      gcc_unreachable ();
+      ;
     }
 
-  if (!pat)
-    return 0;
-
-  emit_insn (pat);
-  return target;
+  gcc_unreachable ();
 }
 
-/* Create a builtin vector type with a name.  Taking care not to give
-   the canonical type a name.  */
-
-static tree
-rs6000_vector_type (const char *name, tree elt_type, unsigned num_elts)
+/* Expand an AltiVec vector load builtin, and return the expanded rtx.  */
+static rtx
+ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
 {
-  tree result = build_vector_type (elt_type, num_elts);
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || !insn_data[icode].operand[0].predicate (target, tmode))
+    target = gen_reg_rtx (tmode);
 
-  /* Copy so we don't give the canonical type a name.  */
-  result = build_variant_type_copy (result);
+  op[1] = copy_to_mode_reg (Pmode, op[1]);
 
-  add_builtin_type (name, result);
+  /* These CELL built-ins use BLKmode instead of tmode for historical
+     (i.e., unknown) reasons.  TODO: Is this necessary?  */
+  bool blk = (icode == CODE_FOR_altivec_lvlx
+	      || icode == CODE_FOR_altivec_lvlxl
+	      || icode == CODE_FOR_altivec_lvrx
+	      || icode == CODE_FOR_altivec_lvrxl);
 
-  return result;
-}
+  /* For LVX, express the RTL accurately by ANDing the address with -16.
+     LVXL and LVE*X expand to use UNSPECs to hide their special behavior,
+     so the raw address is fine.  */
+  /* TODO: That statement seems wrong, as the UNSPECs don't surround the
+     memory expression, so a latent bug may lie here.  The &-16 is likely
+     needed for all VMX-style loads.  */
+  if (icode == CODE_FOR_altivec_lvx_v1ti
+      || icode == CODE_FOR_altivec_lvx_v2df
+      || icode == CODE_FOR_altivec_lvx_v2di
+      || icode == CODE_FOR_altivec_lvx_v4sf
+      || icode == CODE_FOR_altivec_lvx_v4si
+      || icode == CODE_FOR_altivec_lvx_v8hi
+      || icode == CODE_FOR_altivec_lvx_v16qi)
+    {
+      rtx rawaddr;
+      if (op[0] == const0_rtx)
+	rawaddr = op[1];
+      else
+	{
+	  op[0] = copy_to_mode_reg (Pmode, op[0]);
+	  rawaddr = gen_rtx_PLUS (Pmode, op[1], op[0]);
+	}
+      rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16));
+      addr = gen_rtx_MEM (blk ? BLKmode : tmode, addr);
 
-void
-rs6000_init_builtins (void)
-{
-  tree tdecl;
-  tree ftype;
-  tree t;
-  machine_mode mode;
-  const char *str;
+      emit_insn (gen_rtx_SET (target, addr));
+    }
+  else
+    {
+      rtx addr;
+      if (op[0] == const0_rtx)
+	addr = gen_rtx_MEM (blk ? BLKmode : tmode, op[1]);
+      else
+	{
+	  op[0] = copy_to_mode_reg (Pmode, op[0]);
+	  addr = gen_rtx_MEM (blk ? BLKmode : tmode,
+			      gen_rtx_PLUS (Pmode, op[1], op[0]));
+	}
+
+      rtx pat = GEN_FCN (icode) (target, addr);
+      if (!pat)
+	return 0;
+      emit_insn (pat);
+    }
 
-  if (TARGET_DEBUG_BUILTIN)
-    fprintf (stderr, "rs6000_init_builtins%s%s\n",
-	     (TARGET_ALTIVEC)	   ? ", altivec" : "",
-	     (TARGET_VSX)	   ? ", vsx"	 : "");
+  return target;
+}
+
+/* Expand a builtin function that loads a scalar into a vector register
+   with sign extension, and return the expanded rtx.  */
+static rtx
+lxvrse_expand_builtin (rtx target, insn_code icode, rtx *op,
+		       machine_mode tmode, machine_mode smode)
+{
+  rtx pat, addr;
+  op[1] = copy_to_mode_reg (Pmode, op[1]);
 
-  if (new_builtins_are_live)
-    V2DI_type_node = rs6000_vector_type ("__vector long long",
-					 long_long_integer_type_node, 2);
+  if (op[0] == const0_rtx)
+    addr = gen_rtx_MEM (tmode, op[1]);
   else
     {
-      str = TARGET_POWERPC64 ? "__vector long" : "__vector long long";
-      V2DI_type_node = rs6000_vector_type (str,
-					   long_long_integer_type_node,
-					   2);
+      op[0] = copy_to_mode_reg (Pmode, op[0]);
+      addr = gen_rtx_MEM (smode,
+			  gen_rtx_PLUS (Pmode, op[1], op[0]));
     }
-  ptr_V2DI_type_node
-    = build_pointer_type (build_qualified_type (V2DI_type_node,
-						TYPE_QUAL_CONST));
-
-  V2DF_type_node = rs6000_vector_type ("__vector double", double_type_node, 2);
-  ptr_V2DF_type_node
-    = build_pointer_type (build_qualified_type (V2DF_type_node,
-						TYPE_QUAL_CONST));
-
-  V4SI_type_node = rs6000_vector_type ("__vector signed int",
-				       intSI_type_node, 4);
-  ptr_V4SI_type_node
-    = build_pointer_type (build_qualified_type (V4SI_type_node,
-						TYPE_QUAL_CONST));
 
-  V4SF_type_node = rs6000_vector_type ("__vector float", float_type_node, 4);
-  ptr_V4SF_type_node
-    = build_pointer_type (build_qualified_type (V4SF_type_node,
-						TYPE_QUAL_CONST));
+  rtx discratch = gen_reg_rtx (V2DImode);
+  rtx tiscratch = gen_reg_rtx (TImode);
 
-  V8HI_type_node = rs6000_vector_type ("__vector signed short",
-				       intHI_type_node, 8);
-  ptr_V8HI_type_node
-    = build_pointer_type (build_qualified_type (V8HI_type_node,
-						TYPE_QUAL_CONST));
+  /* Emit the lxvr*x insn.  */
+  pat = GEN_FCN (icode) (tiscratch, addr);
+  if (!pat)
+    return 0;
+  emit_insn (pat);
 
-  V16QI_type_node = rs6000_vector_type ("__vector signed char",
-					intQI_type_node, 16);
-  ptr_V16QI_type_node
-    = build_pointer_type (build_qualified_type (V16QI_type_node,
-						TYPE_QUAL_CONST));
+  /* Emit a sign extension from V16QI,V8HI,V4SI to V2DI.  */
+  rtx temp1;
+  if (icode == CODE_FOR_vsx_lxvrbx)
+    {
+      temp1  = simplify_gen_subreg (V16QImode, tiscratch, TImode, 0);
+      emit_insn (gen_vsx_sign_extend_qi_v2di (discratch, temp1));
+    }
+  else if (icode == CODE_FOR_vsx_lxvrhx)
+    {
+      temp1  = simplify_gen_subreg (V8HImode, tiscratch, TImode, 0);
+      emit_insn (gen_vsx_sign_extend_hi_v2di (discratch, temp1));
+    }
+  else if (icode == CODE_FOR_vsx_lxvrwx)
+    {
+      temp1  = simplify_gen_subreg (V4SImode, tiscratch, TImode, 0);
+      emit_insn (gen_vsx_sign_extend_si_v2di (discratch, temp1));
+    }
+  else if (icode == CODE_FOR_vsx_lxvrdx)
+    discratch = simplify_gen_subreg (V2DImode, tiscratch, TImode, 0);
+  else
+    gcc_unreachable ();
 
-  unsigned_V16QI_type_node = rs6000_vector_type ("__vector unsigned char",
-					unsigned_intQI_type_node, 16);
-  ptr_unsigned_V16QI_type_node
-    = build_pointer_type (build_qualified_type (unsigned_V16QI_type_node,
-						TYPE_QUAL_CONST));
+  /* Emit the sign extension from V2DI (double) to TI (quad).  */
+  rtx temp2 = simplify_gen_subreg (TImode, discratch, V2DImode, 0);
+  emit_insn (gen_extendditi2_vector (target, temp2));
 
-  unsigned_V8HI_type_node = rs6000_vector_type ("__vector unsigned short",
-				       unsigned_intHI_type_node, 8);
-  ptr_unsigned_V8HI_type_node
-    = build_pointer_type (build_qualified_type (unsigned_V8HI_type_node,
-						TYPE_QUAL_CONST));
+  return target;
+}
 
-  unsigned_V4SI_type_node = rs6000_vector_type ("__vector unsigned int",
-				       unsigned_intSI_type_node, 4);
-  ptr_unsigned_V4SI_type_node
-    = build_pointer_type (build_qualified_type (unsigned_V4SI_type_node,
-						TYPE_QUAL_CONST));
+/* Expand a builtin function that loads a scalar into a vector register
+   with zero extension, and return the expanded rtx.  */
+static rtx
+lxvrze_expand_builtin (rtx target, insn_code icode, rtx *op,
+		       machine_mode tmode, machine_mode smode)
+{
+  rtx pat, addr;
+  op[1] = copy_to_mode_reg (Pmode, op[1]);
 
-  if (new_builtins_are_live)
-    unsigned_V2DI_type_node
-      = rs6000_vector_type ("__vector unsigned long long",
-			    long_long_unsigned_type_node, 2);
+  if (op[0] == const0_rtx)
+    addr = gen_rtx_MEM (tmode, op[1]);
   else
     {
-      str = TARGET_POWERPC64
-	? "__vector unsigned long"
-	: "__vector unsigned long long";
-      unsigned_V2DI_type_node
-	= rs6000_vector_type (str, long_long_unsigned_type_node, 2);
+      op[0] = copy_to_mode_reg (Pmode, op[0]);
+      addr = gen_rtx_MEM (smode,
+			  gen_rtx_PLUS (Pmode, op[1], op[0]));
     }
 
-  ptr_unsigned_V2DI_type_node
-    = build_pointer_type (build_qualified_type (unsigned_V2DI_type_node,
-						TYPE_QUAL_CONST));
-
-  opaque_V4SI_type_node = build_opaque_vector_type (intSI_type_node, 4);
+  pat = GEN_FCN (icode) (target, addr);
+  if (!pat)
+    return 0;
+  emit_insn (pat);
+  return target;
+}
 
-  const_str_type_node
-    = build_pointer_type (build_qualified_type (char_type_node,
-						TYPE_QUAL_CONST));
+/* Expand an AltiVec vector store builtin, and return the expanded rtx.  */
+static rtx
+stv_expand_builtin (insn_code icode, rtx *op,
+		    machine_mode tmode, machine_mode smode)
+{
+  op[2] = copy_to_mode_reg (Pmode, op[2]);
 
-  /* We use V1TI mode as a special container to hold __int128_t items that
-     must live in VSX registers.  */
-  if (intTI_type_node)
+  /* For STVX, express the RTL accurately by ANDing the address with -16.
+     STVXL and STVE*X expand to use UNSPECs to hide their special behavior,
+     so the raw address is fine.  */
+  /* TODO: That statement seems wrong, as the UNSPECs don't surround the
+     memory expression, so a latent bug may lie here.  The &-16 is likely
+     needed for all VMX-style stores.  */
+  if (icode == CODE_FOR_altivec_stvx_v2df
+      || icode == CODE_FOR_altivec_stvx_v2di
+      || icode == CODE_FOR_altivec_stvx_v4sf
+      || icode == CODE_FOR_altivec_stvx_v4si
+      || icode == CODE_FOR_altivec_stvx_v8hi
+      || icode == CODE_FOR_altivec_stvx_v16qi)
     {
-      V1TI_type_node = rs6000_vector_type ("__vector __int128",
-					   intTI_type_node, 1);
-      ptr_V1TI_type_node
-	= build_pointer_type (build_qualified_type (V1TI_type_node,
-						    TYPE_QUAL_CONST));
-      unsigned_V1TI_type_node
-	= rs6000_vector_type ("__vector unsigned __int128",
-			      unsigned_intTI_type_node, 1);
-      ptr_unsigned_V1TI_type_node
-	= build_pointer_type (build_qualified_type (unsigned_V1TI_type_node,
-						    TYPE_QUAL_CONST));
-    }
-
-  /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
-     types, especially in C++ land.  Similarly, 'vector pixel' is distinct from
-     'vector unsigned short'.  */
+      rtx rawaddr;
+      if (op[1] == const0_rtx)
+	rawaddr = op[2];
+      else
+	{
+	  op[1] = copy_to_mode_reg (Pmode, op[1]);
+	  rawaddr = gen_rtx_PLUS (Pmode, op[2], op[1]);
+	}
 
-  bool_char_type_node = build_distinct_type_copy (unsigned_intQI_type_node);
-  bool_short_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
-  bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node);
-  bool_long_long_type_node = build_distinct_type_copy (unsigned_intDI_type_node);
-  pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
+      rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16));
+      addr = gen_rtx_MEM (tmode, addr);
+      op[0] = copy_to_mode_reg (tmode, op[0]);
+      emit_insn (gen_rtx_SET (addr, op[0]));
+    }
+  else if (icode == CODE_FOR_vsx_stxvrbx
+	   || icode == CODE_FOR_vsx_stxvrhx
+	   || icode == CODE_FOR_vsx_stxvrwx
+	   || icode == CODE_FOR_vsx_stxvrdx)
+    {
+      rtx truncrtx = gen_rtx_TRUNCATE (tmode, op[0]);
+      op[0] = copy_to_mode_reg (E_TImode, truncrtx);
 
-  long_integer_type_internal_node = long_integer_type_node;
-  long_unsigned_type_internal_node = long_unsigned_type_node;
-  long_long_integer_type_internal_node = long_long_integer_type_node;
-  long_long_unsigned_type_internal_node = long_long_unsigned_type_node;
-  intQI_type_internal_node = intQI_type_node;
-  uintQI_type_internal_node = unsigned_intQI_type_node;
-  intHI_type_internal_node = intHI_type_node;
-  uintHI_type_internal_node = unsigned_intHI_type_node;
-  intSI_type_internal_node = intSI_type_node;
-  uintSI_type_internal_node = unsigned_intSI_type_node;
-  intDI_type_internal_node = intDI_type_node;
-  uintDI_type_internal_node = unsigned_intDI_type_node;
-  intTI_type_internal_node = intTI_type_node;
-  uintTI_type_internal_node = unsigned_intTI_type_node;
-  float_type_internal_node = float_type_node;
-  double_type_internal_node = double_type_node;
-  long_double_type_internal_node = long_double_type_node;
-  dfloat64_type_internal_node = dfloat64_type_node;
-  dfloat128_type_internal_node = dfloat128_type_node;
-  void_type_internal_node = void_type_node;
+      rtx addr;
+      if (op[1] == const0_rtx)
+	addr = gen_rtx_MEM (Pmode, op[2]);
+      else
+	{
+	  op[1] = copy_to_mode_reg (Pmode, op[1]);
+	  addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1]));
+	}
+      rtx pat = GEN_FCN (icode) (addr, op[0]);
+      if (pat)
+	emit_insn (pat);
+    }
+  else
+    {
+      if (!insn_data[icode].operand[1].predicate (op[0], smode))
+	op[0] = copy_to_mode_reg (smode, op[0]);
 
-  ptr_intQI_type_node
-    = build_pointer_type (build_qualified_type (intQI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_uintQI_type_node
-    = build_pointer_type (build_qualified_type (uintQI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_intHI_type_node
-    = build_pointer_type (build_qualified_type (intHI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_uintHI_type_node
-    = build_pointer_type (build_qualified_type (uintHI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_intSI_type_node
-    = build_pointer_type (build_qualified_type (intSI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_uintSI_type_node
-    = build_pointer_type (build_qualified_type (uintSI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_intDI_type_node
-    = build_pointer_type (build_qualified_type (intDI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_uintDI_type_node
-    = build_pointer_type (build_qualified_type (uintDI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_intTI_type_node
-    = build_pointer_type (build_qualified_type (intTI_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_uintTI_type_node
-    = build_pointer_type (build_qualified_type (uintTI_type_internal_node,
-						TYPE_QUAL_CONST));
+      rtx addr;
+      if (op[1] == const0_rtx)
+	addr = gen_rtx_MEM (tmode, op[2]);
+      else
+	{
+	  op[1] = copy_to_mode_reg (Pmode, op[1]);
+	  addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1]));
+	}
 
-  t = build_qualified_type (long_integer_type_internal_node, TYPE_QUAL_CONST);
-  ptr_long_integer_type_node = build_pointer_type (t);
+      rtx pat = GEN_FCN (icode) (addr, op[0]);
+      if (pat)
+	emit_insn (pat);
+    }
 
-  t = build_qualified_type (long_unsigned_type_internal_node, TYPE_QUAL_CONST);
-  ptr_long_unsigned_type_node = build_pointer_type (t);
+  return NULL_RTX;
+}
 
-  ptr_float_type_node
-    = build_pointer_type (build_qualified_type (float_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_double_type_node
-    = build_pointer_type (build_qualified_type (double_type_internal_node,
-						TYPE_QUAL_CONST));
-  ptr_long_double_type_node
-    = build_pointer_type (build_qualified_type (long_double_type_internal_node,
-						TYPE_QUAL_CONST));
-  if (dfloat64_type_node)
-    {
-      t = build_qualified_type (dfloat64_type_internal_node, TYPE_QUAL_CONST);
-      ptr_dfloat64_type_node = build_pointer_type (t);
-    }
-  else
-    ptr_dfloat64_type_node = NULL;
+/* Expand the MMA built-in in EXP, and return it.  */
+static rtx
+new_mma_expand_builtin (tree exp, rtx target, insn_code icode,
+			rs6000_gen_builtins fcode)
+{
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
+  machine_mode tmode = VOIDmode;
+  rtx op[MAX_MMA_OPERANDS];
+  unsigned nopnds = 0;
 
-  if (dfloat128_type_node)
+  if (!void_func)
     {
-      t = build_qualified_type (dfloat128_type_internal_node, TYPE_QUAL_CONST);
-      ptr_dfloat128_type_node = build_pointer_type (t);
+      tmode = insn_data[icode].operand[0].mode;
+      if (!(target
+	    && GET_MODE (target) == tmode
+	    && insn_data[icode].operand[0].predicate (target, tmode)))
+	target = gen_reg_rtx (tmode);
+      op[nopnds++] = target;
     }
   else
-    ptr_dfloat128_type_node = NULL;
+    target = const0_rtx;
 
-  t = build_qualified_type (long_long_integer_type_internal_node,
-			    TYPE_QUAL_CONST);
-  ptr_long_long_integer_type_node  = build_pointer_type (t);
+  call_expr_arg_iterator iter;
+  tree arg;
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+    {
+      if (arg == error_mark_node)
+	return const0_rtx;
 
-  t = build_qualified_type (long_long_unsigned_type_internal_node,
-			    TYPE_QUAL_CONST);
-  ptr_long_long_unsigned_type_node = build_pointer_type (t);
+      rtx opnd;
+      const struct insn_operand_data *insn_op;
+      insn_op = &insn_data[icode].operand[nopnds];
+      if (TREE_CODE (arg) == ADDR_EXPR
+	  && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0))))
+	opnd = DECL_RTL (TREE_OPERAND (arg, 0));
+      else
+	opnd = expand_normal (arg);
 
-  /* 128-bit floating point support.  KFmode is IEEE 128-bit floating point.
-     IFmode is the IBM extended 128-bit format that is a pair of doubles.
-     TFmode will be either IEEE 128-bit floating point or the IBM double-double
-     format that uses a pair of doubles, depending on the switches and
-     defaults.
+      if (!insn_op->predicate (opnd, insn_op->mode))
+	{
+	  /* TODO: This use of constraints needs explanation.  */
+	  if (!strcmp (insn_op->constraint, "n"))
+	    {
+	      if (!CONST_INT_P (opnd))
+		error ("argument %d must be an unsigned literal", nopnds);
+	      else
+		error ("argument %d is an unsigned literal that is "
+		       "out of range", nopnds);
+	      return const0_rtx;
+	    }
+	  opnd = copy_to_mode_reg (insn_op->mode, opnd);
+	}
 
-     If we don't support for either 128-bit IBM double double or IEEE 128-bit
-     floating point, we need make sure the type is non-zero or else self-test
-     fails during bootstrap.
+      /* Some MMA instructions have INOUT accumulator operands, so force
+	 their target register to be the same as their input register.  */
+      if (!void_func
+	  && nopnds == 1
+	  && !strcmp (insn_op->constraint, "0")
+	  && insn_op->mode == tmode
+	  && REG_P (opnd)
+	  && insn_data[icode].operand[0].predicate (opnd, tmode))
+	target = op[0] = opnd;
 
-     Always create __ibm128 as a separate type, even if the current long double
-     format is IBM extended double.
+      op[nopnds++] = opnd;
+    }
 
-     For IEEE 128-bit floating point, always create the type __ieee128.  If the
-     user used -mfloat128, rs6000-c.c will create a define from __float128 to
-     __ieee128.  */
-  if (TARGET_FLOAT128_TYPE)
+  rtx pat;
+  switch (nopnds)
     {
-      if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
-	ibm128_float_type_node = long_double_type_node;
-      else
+    case 1:
+      pat = GEN_FCN (icode) (op[0]);
+      break;
+    case 2:
+      pat = GEN_FCN (icode) (op[0], op[1]);
+      break;
+    case 3:
+      /* The ASSEMBLE builtin source operands are reversed in little-endian
+	 mode, so reorder them.  */
+      if (fcode == RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL && !WORDS_BIG_ENDIAN)
+	std::swap (op[1], op[2]);
+      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+      break;
+    case 4:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+      break;
+    case 5:
+      /* The ASSEMBLE builtin source operands are reversed in little-endian
+	 mode, so reorder them.  */
+      if (fcode == RS6000_BIF_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN)
 	{
-	  ibm128_float_type_node = make_node (REAL_TYPE);
-	  TYPE_PRECISION (ibm128_float_type_node) = 128;
-	  SET_TYPE_MODE (ibm128_float_type_node, IFmode);
-	  layout_type (ibm128_float_type_node);
+	  std::swap (op[1], op[4]);
+	  std::swap (op[2], op[3]);
 	}
-      t = build_qualified_type (ibm128_float_type_node, TYPE_QUAL_CONST);
-      ptr_ibm128_float_type_node = build_pointer_type (t);
-      lang_hooks.types.register_builtin_type (ibm128_float_type_node,
-					      "__ibm128");
-
-      if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
-	ieee128_float_type_node = long_double_type_node;
-      else
-	ieee128_float_type_node = float128_type_node;
-      t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
-      ptr_ieee128_float_type_node = build_pointer_type (t);
-      lang_hooks.types.register_builtin_type (ieee128_float_type_node,
-					      "__ieee128");
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
+      break;
+    case 6:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
+      break;
+    case 7:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]);
+      break;
+    default:
+      gcc_unreachable ();
     }
 
-  else
-    ieee128_float_type_node = ibm128_float_type_node = long_double_type_node;
+  if (!pat)
+    return NULL_RTX;
 
-  /* Vector pair and vector quad support.  */
-  vector_pair_type_node = make_node (OPAQUE_TYPE);
-  SET_TYPE_MODE (vector_pair_type_node, OOmode);
-  TYPE_SIZE (vector_pair_type_node) = bitsize_int (GET_MODE_BITSIZE (OOmode));
-  TYPE_PRECISION (vector_pair_type_node) = GET_MODE_BITSIZE (OOmode);
-  TYPE_SIZE_UNIT (vector_pair_type_node) = size_int (GET_MODE_SIZE (OOmode));
-  SET_TYPE_ALIGN (vector_pair_type_node, 256);
-  TYPE_USER_ALIGN (vector_pair_type_node) = 0;
-  lang_hooks.types.register_builtin_type (vector_pair_type_node,
-					  "__vector_pair");
-  t = build_qualified_type (vector_pair_type_node, TYPE_QUAL_CONST);
-  ptr_vector_pair_type_node = build_pointer_type (t);
+  emit_insn (pat);
+  return target;
+}
 
-  vector_quad_type_node = make_node (OPAQUE_TYPE);
-  SET_TYPE_MODE (vector_quad_type_node, XOmode);
-  TYPE_SIZE (vector_quad_type_node) = bitsize_int (GET_MODE_BITSIZE (XOmode));
-  TYPE_PRECISION (vector_quad_type_node) = GET_MODE_BITSIZE (XOmode);
-  TYPE_SIZE_UNIT (vector_quad_type_node) = size_int (GET_MODE_SIZE (XOmode));
-  SET_TYPE_ALIGN (vector_quad_type_node, 512);
-  TYPE_USER_ALIGN (vector_quad_type_node) = 0;
-  lang_hooks.types.register_builtin_type (vector_quad_type_node,
-					  "__vector_quad");
-  t = build_qualified_type (vector_quad_type_node, TYPE_QUAL_CONST);
-  ptr_vector_quad_type_node = build_pointer_type (t);
+/* Return the appropriate SPR number associated with the given builtin.  */
+static inline HOST_WIDE_INT
+new_htm_spr_num (enum rs6000_gen_builtins code)
+{
+  if (code == RS6000_BIF_GET_TFHAR
+      || code == RS6000_BIF_SET_TFHAR)
+    return TFHAR_SPR;
+  else if (code == RS6000_BIF_GET_TFIAR
+	   || code == RS6000_BIF_SET_TFIAR)
+    return TFIAR_SPR;
+  else if (code == RS6000_BIF_GET_TEXASR
+	   || code == RS6000_BIF_SET_TEXASR)
+    return TEXASR_SPR;
+  gcc_assert (code == RS6000_BIF_GET_TEXASRU
+	      || code == RS6000_BIF_SET_TEXASRU);
+  return TEXASRU_SPR;
+}
 
-  /* Initialize the modes for builtin_function_type, mapping a machine mode to
-     tree type node.  */
-  builtin_mode_to_type[QImode][0] = integer_type_node;
-  builtin_mode_to_type[QImode][1] = unsigned_intSI_type_node;
-  builtin_mode_to_type[HImode][0] = integer_type_node;
-  builtin_mode_to_type[HImode][1] = unsigned_intSI_type_node;
-  builtin_mode_to_type[SImode][0] = intSI_type_node;
-  builtin_mode_to_type[SImode][1] = unsigned_intSI_type_node;
-  builtin_mode_to_type[DImode][0] = intDI_type_node;
-  builtin_mode_to_type[DImode][1] = unsigned_intDI_type_node;
-  builtin_mode_to_type[TImode][0] = intTI_type_node;
-  builtin_mode_to_type[TImode][1] = unsigned_intTI_type_node;
-  builtin_mode_to_type[SFmode][0] = float_type_node;
-  builtin_mode_to_type[DFmode][0] = double_type_node;
-  builtin_mode_to_type[IFmode][0] = ibm128_float_type_node;
-  builtin_mode_to_type[KFmode][0] = ieee128_float_type_node;
-  builtin_mode_to_type[TFmode][0] = long_double_type_node;
-  builtin_mode_to_type[DDmode][0] = dfloat64_type_node;
-  builtin_mode_to_type[TDmode][0] = dfloat128_type_node;
-  builtin_mode_to_type[V1TImode][0] = V1TI_type_node;
-  builtin_mode_to_type[V1TImode][1] = unsigned_V1TI_type_node;
-  builtin_mode_to_type[V2DImode][0] = V2DI_type_node;
-  builtin_mode_to_type[V2DImode][1] = unsigned_V2DI_type_node;
-  builtin_mode_to_type[V2DFmode][0] = V2DF_type_node;
-  builtin_mode_to_type[V4SImode][0] = V4SI_type_node;
-  builtin_mode_to_type[V4SImode][1] = unsigned_V4SI_type_node;
-  builtin_mode_to_type[V4SFmode][0] = V4SF_type_node;
-  builtin_mode_to_type[V8HImode][0] = V8HI_type_node;
-  builtin_mode_to_type[V8HImode][1] = unsigned_V8HI_type_node;
-  builtin_mode_to_type[V16QImode][0] = V16QI_type_node;
-  builtin_mode_to_type[V16QImode][1] = unsigned_V16QI_type_node;
-  builtin_mode_to_type[OOmode][1] = vector_pair_type_node;
-  builtin_mode_to_type[XOmode][1] = vector_quad_type_node;
+/* Expand the HTM builtin in EXP and store the result in TARGET.
+   Return the expanded rtx.  */
+static rtx
+new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode,
+			tree exp, rtx target)
+{
+  if (!TARGET_POWERPC64
+      && (fcode == RS6000_BIF_TABORTDC
+	  || fcode == RS6000_BIF_TABORTDCI))
+    {
+      error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname);
+      return const0_rtx;
+    }
 
-  tdecl = add_builtin_type ("__bool char", bool_char_type_node);
-  TYPE_NAME (bool_char_type_node) = tdecl;
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+  bool uses_spr = bif_is_htmspr (*bifaddr);
+  insn_code icode = bifaddr->icode;
 
-  tdecl = add_builtin_type ("__bool short", bool_short_type_node);
-  TYPE_NAME (bool_short_type_node) = tdecl;
+  if (uses_spr)
+    icode = rs6000_htm_spr_icode (nonvoid);
 
-  tdecl = add_builtin_type ("__bool int", bool_int_type_node);
-  TYPE_NAME (bool_int_type_node) = tdecl;
+  rtx op[MAX_HTM_OPERANDS];
+  int nopnds = 0;
+  const insn_operand_data *insn_op = &insn_data[icode].operand[0];
 
-  tdecl = add_builtin_type ("__pixel", pixel_type_node);
-  TYPE_NAME (pixel_type_node) = tdecl;
+  if (nonvoid)
+    {
+      machine_mode tmode = (uses_spr) ? insn_op->mode : E_SImode;
+      if (!target
+	  || GET_MODE (target) != tmode
+	  || (uses_spr && !insn_op->predicate (target, tmode)))
+	target = gen_reg_rtx (tmode);
+      if (uses_spr)
+	op[nopnds++] = target;
+    }
 
-  bool_V16QI_type_node = rs6000_vector_type ("__vector __bool char",
-					     bool_char_type_node, 16);
-  ptr_bool_V16QI_type_node
-    = build_pointer_type (build_qualified_type (bool_V16QI_type_node,
-						TYPE_QUAL_CONST));
+  tree arg;
+  call_expr_arg_iterator iter;
 
-  bool_V8HI_type_node = rs6000_vector_type ("__vector __bool short",
-					    bool_short_type_node, 8);
-  ptr_bool_V8HI_type_node
-    = build_pointer_type (build_qualified_type (bool_V8HI_type_node,
-						TYPE_QUAL_CONST));
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+    {
+      if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS)
+	return const0_rtx;
 
-  bool_V4SI_type_node = rs6000_vector_type ("__vector __bool int",
-					    bool_int_type_node, 4);
-  ptr_bool_V4SI_type_node
-    = build_pointer_type (build_qualified_type (bool_V4SI_type_node,
-						TYPE_QUAL_CONST));
+      insn_op = &insn_data[icode].operand[nopnds];
+      op[nopnds] = expand_normal (arg);
 
-  bool_V2DI_type_node = rs6000_vector_type (TARGET_POWERPC64
-					    ? "__vector __bool long"
-					    : "__vector __bool long long",
-					    bool_long_long_type_node, 2);
-  ptr_bool_V2DI_type_node
-    = build_pointer_type (build_qualified_type (bool_V2DI_type_node,
-						TYPE_QUAL_CONST));
+      if (!insn_op->predicate (op[nopnds], insn_op->mode))
+	{
+	  /* TODO: This use of constraints could use explanation.
+	     This happens a couple of places, perhaps make that a
+	     function to document what's happening.  */
+	  if (!strcmp (insn_op->constraint, "n"))
+	    {
+	      int arg_num = nonvoid ? nopnds : nopnds + 1;
+	      if (!CONST_INT_P (op[nopnds]))
+		error ("argument %d must be an unsigned literal", arg_num);
+	      else
+		error ("argument %d is an unsigned literal that is "
+		       "out of range", arg_num);
+	      return const0_rtx;
+	    }
+	  op[nopnds] = copy_to_mode_reg (insn_op->mode, op[nopnds]);
+	}
 
-  bool_V1TI_type_node = rs6000_vector_type ("__vector __bool __int128",
-					    intTI_type_node, 1);
-  ptr_bool_V1TI_type_node
-    = build_pointer_type (build_qualified_type (bool_V1TI_type_node,
-						TYPE_QUAL_CONST));
+      nopnds++;
+    }
 
-  pixel_V8HI_type_node = rs6000_vector_type ("__vector __pixel",
-					     pixel_type_node, 8);
-  ptr_pixel_V8HI_type_node
-    = build_pointer_type (build_qualified_type (pixel_V8HI_type_node,
-						TYPE_QUAL_CONST));
-  pcvoid_type_node
-    = build_pointer_type (build_qualified_type (void_type_node,
-						TYPE_QUAL_CONST));
+  /* Handle the builtins for extended mnemonics.  These accept
+     no arguments, but map to builtins that take arguments.  */
+  switch (fcode)
+    {
+    case RS6000_BIF_TENDALL:  /* Alias for: tend. 1  */
+    case RS6000_BIF_TRESUME:  /* Alias for: tsr. 1  */
+      op[nopnds++] = GEN_INT (1);
+      break;
+    case RS6000_BIF_TSUSPEND: /* Alias for: tsr. 0  */
+      op[nopnds++] = GEN_INT (0);
+      break;
+    default:
+      break;
+    }
 
-  /* Execute the autogenerated initialization code for builtins.  */
-  rs6000_init_generated_builtins ();
+  /* If this builtin accesses SPRs, then pass in the appropriate
+     SPR number and SPR regno as the last two operands.  */
+  rtx cr = NULL_RTX;
+  if (uses_spr)
+    {
+      machine_mode mode = TARGET_POWERPC64 ? DImode : SImode;
+      op[nopnds++] = gen_rtx_CONST_INT (mode, new_htm_spr_num (fcode));
+    }
+  /* If this builtin accesses a CR field, then pass in a scratch
+     CR field as the last operand.  */
+  else if (bif_is_htmcr (*bifaddr))
+    {
+      cr = gen_reg_rtx (CCmode);
+      op[nopnds++] = cr;
+    }
+
+  rtx pat;
+  switch (nopnds)
+    {
+    case 1:
+      pat = GEN_FCN (icode) (op[0]);
+      break;
+    case 2:
+      pat = GEN_FCN (icode) (op[0], op[1]);
+      break;
+    case 3:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+      break;
+    case 4:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
+
+  if (bif_is_htmcr (*bifaddr))
+    {
+      if (fcode == RS6000_BIF_TBEGIN)
+	{
+	  /* Emit code to set TARGET to true or false depending on
+	     whether the tbegin. instruction succeeded or failed
+	     to start a transaction.  We do this by placing the 1's
+	     complement of CR's EQ bit into TARGET.  */
+	  rtx scratch = gen_reg_rtx (SImode);
+	  emit_insn (gen_rtx_SET (scratch,
+				  gen_rtx_EQ (SImode, cr,
+					      const0_rtx)));
+	  emit_insn (gen_rtx_SET (target,
+				  gen_rtx_XOR (SImode, scratch,
+					       GEN_INT (1))));
+	}
+      else
+	{
+	  /* Emit code to copy the 4-bit condition register field
+	     CR into the least significant end of register TARGET.  */
+	  rtx scratch1 = gen_reg_rtx (SImode);
+	  rtx scratch2 = gen_reg_rtx (SImode);
+	  rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0);
+	  emit_insn (gen_movcc (subreg, cr));
+	  emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28)));
+	  emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf)));
+	}
+    }
+
+  if (nonvoid)
+    return target;
+  return const0_rtx;
+}
+
+/* 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).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.
+   Use the new builtin infrastructure.  */
+static rtx
+rs6000_expand_new_builtin (tree exp, rtx target,
+			   rtx /* subtarget */,
+			   machine_mode /* mode */,
+			   int ignore)
+{
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  enum rs6000_gen_builtins fcode
+    = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
+  size_t uns_fcode = (size_t)fcode;
+  enum insn_code icode = rs6000_builtin_info_x[uns_fcode].icode;
+
+  /* TODO: The following commentary and code is inherited from the original
+     builtin processing code.  The commentary is a bit confusing, with the
+     intent being that KFmode is always IEEE-128, IFmode is always IBM
+     double-double, and TFmode is the current long double.  The code is
+     confusing in that it converts from KFmode to TFmode pattern names,
+     when the other direction is more intuitive.  Try to address this.  */
+
+  /* We have two different modes (KFmode, TFmode) that are the IEEE
+     128-bit floating point type, depending on whether long double is the
+     IBM extended double (KFmode) or long double is IEEE 128-bit (TFmode).
+     It is simpler if we only define one variant of the built-in function,
+     and switch the code when defining it, rather than defining two built-
+     ins and using the overload table in rs6000-c.c to switch between the
+     two.  If we don't have the proper assembler, don't do this switch
+     because CODE_FOR_*kf* and CODE_FOR_*tf* will be CODE_FOR_nothing.  */
+  if (FLOAT128_IEEE_P (TFmode))
+    switch (icode)
+      {
+      case CODE_FOR_sqrtkf2_odd:
+	icode = CODE_FOR_sqrttf2_odd;
+	break;
+      case CODE_FOR_trunckfdf2_odd:
+	icode = CODE_FOR_trunctfdf2_odd;
+	break;
+      case CODE_FOR_addkf3_odd:
+	icode = CODE_FOR_addtf3_odd;
+	break;
+      case CODE_FOR_subkf3_odd:
+	icode = CODE_FOR_subtf3_odd;
+	break;
+      case CODE_FOR_mulkf3_odd:
+	icode = CODE_FOR_multf3_odd;
+	break;
+      case CODE_FOR_divkf3_odd:
+	icode = CODE_FOR_divtf3_odd;
+	break;
+      case CODE_FOR_fmakf4_odd:
+	icode = CODE_FOR_fmatf4_odd;
+	break;
+      case CODE_FOR_xsxexpqp_kf:
+	icode = CODE_FOR_xsxexpqp_tf;
+	break;
+      case CODE_FOR_xsxsigqp_kf:
+	icode = CODE_FOR_xsxsigqp_tf;
+	break;
+      case CODE_FOR_xststdcnegqp_kf:
+	icode = CODE_FOR_xststdcnegqp_tf;
+	break;
+      case CODE_FOR_xsiexpqp_kf:
+	icode = CODE_FOR_xsiexpqp_tf;
+	break;
+      case CODE_FOR_xsiexpqpf_kf:
+	icode = CODE_FOR_xsiexpqpf_tf;
+	break;
+      case CODE_FOR_xststdcqp_kf:
+	icode = CODE_FOR_xststdcqp_tf;
+	break;
+      case CODE_FOR_xscmpexpqp_eq_kf:
+	icode = CODE_FOR_xscmpexpqp_eq_tf;
+	break;
+      case CODE_FOR_xscmpexpqp_lt_kf:
+	icode = CODE_FOR_xscmpexpqp_lt_tf;
+	break;
+      case CODE_FOR_xscmpexpqp_gt_kf:
+	icode = CODE_FOR_xscmpexpqp_gt_tf;
+	break;
+      case CODE_FOR_xscmpexpqp_unordered_kf:
+	icode = CODE_FOR_xscmpexpqp_unordered_tf;
+	break;
+      default:
+	break;
+      }
 
-  if (TARGET_DEBUG_BUILTIN)
-    {
-      fprintf (stderr, "\nAutogenerated built-in functions:\n\n");
-      for (int i = 1; i < (int) RS6000_BIF_MAX; i++)
-	{
-	  bif_enable e = rs6000_builtin_info_x[i].enable;
-	  if (e == ENB_P5 && !TARGET_POPCNTB)
-	    continue;
-	  if (e == ENB_P6 && !TARGET_CMPB)
-	    continue;
-	  if (e == ENB_P6_64 && !(TARGET_CMPB && TARGET_POWERPC64))
-	    continue;
-	  if (e == ENB_ALTIVEC && !TARGET_ALTIVEC)
-	    continue;
-	  if (e == ENB_VSX && !TARGET_VSX)
-	    continue;
-	  if (e == ENB_P7 && !TARGET_POPCNTD)
-	    continue;
-	  if (e == ENB_P7_64 && !(TARGET_POPCNTD && TARGET_POWERPC64))
-	    continue;
-	  if (e == ENB_P8 && !TARGET_DIRECT_MOVE)
-	    continue;
-	  if (e == ENB_P8V && !TARGET_P8_VECTOR)
-	    continue;
-	  if (e == ENB_P9 && !TARGET_MODULO)
-	    continue;
-	  if (e == ENB_P9_64 && !(TARGET_MODULO && TARGET_POWERPC64))
-	    continue;
-	  if (e == ENB_P9V && !TARGET_P9_VECTOR)
-	    continue;
-	  if (e == ENB_IEEE128_HW && !TARGET_FLOAT128_HW)
-	    continue;
-	  if (e == ENB_DFP && !TARGET_DFP)
-	    continue;
-	  if (e == ENB_CRYPTO && !TARGET_CRYPTO)
-	    continue;
-	  if (e == ENB_HTM && !TARGET_HTM)
-	    continue;
-	  if (e == ENB_P10 && !TARGET_POWER10)
-	    continue;
-	  if (e == ENB_P10_64 && !(TARGET_POWER10 && TARGET_POWERPC64))
-	    continue;
-	  if (e == ENB_MMA && !TARGET_MMA)
-	    continue;
-	  tree fntype = rs6000_builtin_info_x[i].fntype;
-	  tree t = TREE_TYPE (fntype);
-	  fprintf (stderr, "%s %s (", rs6000_type_string (t),
-		   rs6000_builtin_info_x[i].bifname);
-	  t = TYPE_ARG_TYPES (fntype);
-	  while (t && TREE_VALUE (t) != void_type_node)
-	    {
-	      fprintf (stderr, "%s",
-		       rs6000_type_string (TREE_VALUE (t)));
-	      t = TREE_CHAIN (t);
-	      if (t && TREE_VALUE (t) != void_type_node)
-		fprintf (stderr, ", ");
-	    }
-	  fprintf (stderr, "); %s [%4d]\n",
-		   rs6000_builtin_info_x[i].attr_string, (int) i);
-	}
-      fprintf (stderr, "\nEnd autogenerated built-in functions.\n\n\n");
-     }
+  /* In case of "#pragma target" changes, we initialize all builtins
+     but check for actual availability now, during expand time.  For
+     invalid builtins, generate a normal call.  */
+  bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+  bif_enable e = bifaddr->enable;
 
-  if (TARGET_XCOFF)
+  if (!(e == ENB_ALWAYS
+	|| (e == ENB_P5 && TARGET_POPCNTB)
+	|| (e == ENB_P6 && TARGET_CMPB)
+	|| (e == ENB_P6_64 && TARGET_CMPB && TARGET_POWERPC64)
+	|| (e == ENB_ALTIVEC && TARGET_ALTIVEC)
+	|| (e == ENB_CELL && TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL)
+	|| (e == ENB_VSX && TARGET_VSX)
+	|| (e == ENB_P7 && TARGET_POPCNTD)
+	|| (e == ENB_P7_64 && TARGET_POPCNTD && TARGET_POWERPC64)
+	|| (e == ENB_P8 && TARGET_DIRECT_MOVE)
+	|| (e == ENB_P8V && TARGET_P8_VECTOR)
+	|| (e == ENB_P9 && TARGET_MODULO)
+	|| (e == ENB_P9_64 && TARGET_MODULO && TARGET_POWERPC64)
+	|| (e == ENB_P9V && TARGET_P9_VECTOR)
+	|| (e == ENB_IEEE128_HW && TARGET_FLOAT128_HW)
+	|| (e == ENB_DFP && TARGET_DFP)
+	|| (e == ENB_CRYPTO && TARGET_CRYPTO)
+	|| (e == ENB_HTM && TARGET_HTM)
+	|| (e == ENB_P10 && TARGET_POWER10)
+	|| (e == ENB_P10_64 && TARGET_POWER10 && TARGET_POWERPC64)
+	|| (e == ENB_MMA && TARGET_MMA)))
     {
-      /* AIX libm provides clog as __clog.  */
-      if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
-	set_user_assembler_name (tdecl, "__clog");
-
-      /* When long double is 64 bit, some long double builtins of libc
-	 functions (like __builtin_frexpl) must call the double version
-	 (frexp) not the long double version (frexpl) that expects a 128 bit
-	 argument.  */
-      if (! TARGET_LONG_DOUBLE_128)
-	{
-	  if ((tdecl = builtin_decl_explicit (BUILT_IN_FMODL)) != NULL_TREE)
-	    set_user_assembler_name (tdecl, "fmod");
-	  if ((tdecl = builtin_decl_explicit (BUILT_IN_FREXPL)) != NULL_TREE)
-	    set_user_assembler_name (tdecl, "frexp");
-	  if ((tdecl = builtin_decl_explicit (BUILT_IN_LDEXPL)) != NULL_TREE)
-	    set_user_assembler_name (tdecl, "ldexp");
-	  if ((tdecl = builtin_decl_explicit (BUILT_IN_MODFL)) != NULL_TREE)
-	    set_user_assembler_name (tdecl, "modf");
-	}
+      rs6000_invalid_new_builtin (fcode);
+      return expand_call (exp, target, ignore);
     }
 
-  if (new_builtins_are_live)
+  if (bif_is_nosoft (*bifaddr)
+      && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
     {
-      altivec_builtin_mask_for_load
-	= rs6000_builtin_decls_x[RS6000_BIF_MASK_FOR_LOAD];
-
-#ifdef SUBTARGET_INIT_BUILTINS
-      SUBTARGET_INIT_BUILTINS;
-#endif
-      return;
+      error ("%<%s%> not supported with %<-msoft-float%>",
+	     bifaddr->bifname);
+      return const0_rtx;
     }
 
-  /* Create Altivec, VSX and MMA builtins on machines with at least the
-     general purpose extensions (970 and newer) to allow the use of
-     the target attribute.  */
-  if (TARGET_EXTRA_BUILTINS)
+  if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
     {
-      altivec_init_builtins ();
-      mma_init_builtins ();
+      error ("%<%s%> is not supported in 32-bit mode", bifaddr->bifname);
+      return const0_rtx;
     }
-  if (TARGET_HTM)
-    htm_init_builtins ();
-
-  if (TARGET_EXTRA_BUILTINS)
-    rs6000_common_init_builtins ();
-
-  ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode,
-				 RS6000_BUILTIN_RECIP, "__builtin_recipdiv");
-  def_builtin ("__builtin_recipdiv", ftype, RS6000_BUILTIN_RECIP);
-
-  ftype = builtin_function_type (SFmode, SFmode, SFmode, VOIDmode,
-				 RS6000_BUILTIN_RECIPF, "__builtin_recipdivf");
-  def_builtin ("__builtin_recipdivf", ftype, RS6000_BUILTIN_RECIPF);
-
-  ftype = builtin_function_type (DFmode, DFmode, VOIDmode, VOIDmode,
-				 RS6000_BUILTIN_RSQRT, "__builtin_rsqrt");
-  def_builtin ("__builtin_rsqrt", ftype, RS6000_BUILTIN_RSQRT);
-
-  ftype = builtin_function_type (SFmode, SFmode, VOIDmode, VOIDmode,
-				 RS6000_BUILTIN_RSQRTF, "__builtin_rsqrtf");
-  def_builtin ("__builtin_rsqrtf", ftype, RS6000_BUILTIN_RSQRTF);
-
-  mode = (TARGET_64BIT) ? DImode : SImode;
-  ftype = builtin_function_type (mode, mode, mode, VOIDmode,
-				 POWER7_BUILTIN_BPERMD, "__builtin_bpermd");
-  def_builtin ("__builtin_bpermd", ftype, POWER7_BUILTIN_BPERMD);
-
-  ftype = build_function_type_list (unsigned_intDI_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_ppc_get_timebase", ftype, RS6000_BUILTIN_GET_TB);
-
-  if (TARGET_64BIT)
-    ftype = build_function_type_list (unsigned_intDI_type_node,
-				      NULL_TREE);
-  else
-    ftype = build_function_type_list (unsigned_intSI_type_node,
-				      NULL_TREE);
-  def_builtin ("__builtin_ppc_mftb", ftype, RS6000_BUILTIN_MFTB);
-
-  ftype = build_function_type_list (double_type_node, NULL_TREE);
-  def_builtin ("__builtin_mffs", ftype, RS6000_BUILTIN_MFFS);
-
-  ftype = build_function_type_list (double_type_node, NULL_TREE);
-  def_builtin ("__builtin_mffsl", ftype, RS6000_BUILTIN_MFFSL);
-
-  ftype = build_function_type_list (void_type_node,
-				    intSI_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_mtfsb0", ftype, RS6000_BUILTIN_MTFSB0);
-
-  ftype = build_function_type_list (void_type_node,
-				    intSI_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_mtfsb1", ftype, RS6000_BUILTIN_MTFSB1);
-
-  ftype = build_function_type_list (void_type_node,
-				    intDI_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_set_fpscr_rn", ftype, RS6000_BUILTIN_SET_FPSCR_RN);
-
-  ftype = build_function_type_list (void_type_node,
-				    intDI_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_set_fpscr_drn", ftype, RS6000_BUILTIN_SET_FPSCR_DRN);
-
-  ftype = build_function_type_list (void_type_node,
-				    intSI_type_node, double_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_mtfsf", ftype, RS6000_BUILTIN_MTFSF);
-
-  ftype = build_function_type_list (void_type_node, NULL_TREE);
-  def_builtin ("__builtin_cpu_init", ftype, RS6000_BUILTIN_CPU_INIT);
-  def_builtin ("__builtin_ppc_speculation_barrier", ftype,
-	       MISC_BUILTIN_SPEC_BARRIER);
-
-  ftype = build_function_type_list (bool_int_type_node, const_ptr_type_node,
-				    NULL_TREE);
-  def_builtin ("__builtin_cpu_is", ftype, RS6000_BUILTIN_CPU_IS);
-  def_builtin ("__builtin_cpu_supports", ftype, RS6000_BUILTIN_CPU_SUPPORTS);
-
-#ifdef SUBTARGET_INIT_BUILTINS
-  SUBTARGET_INIT_BUILTINS;
-#endif
 
-  /* Register the compatibility builtins after all of the normal
-     builtins have been defined.  */
-  const struct builtin_compatibility *d = bdesc_compat;
-  unsigned i;
-  for (i = 0; i < ARRAY_SIZE (bdesc_compat); i++, d++)
+  if (bif_is_ibmld (*bifaddr) && !FLOAT128_2REG_P (TFmode))
     {
-      tree decl = rs6000_builtin_decls[(int)d->code];
-      if (decl != NULL)
-	add_builtin_function (d->name, TREE_TYPE (decl), (int)d->code,
-			      BUILT_IN_MD, NULL, NULL_TREE);
+      error ("%<%s%> requires %<long double%> to be IBM 128-bit format",
+	     bifaddr->bifname);
+      return const0_rtx;
     }
-}
 
-static tree
-rs6000_new_builtin_decl (unsigned code, bool /* initialize_p */)
-{
-  rs6000_gen_builtins fcode = (rs6000_gen_builtins) code;
-
-  if (fcode >= RS6000_OVLD_MAX)
-    return error_mark_node;
+  if (bif_is_cpu (*bifaddr))
+    return new_cpu_expand_builtin (fcode, exp, target);
 
-  return rs6000_builtin_decls_x[code];
-}
+  if (bif_is_init (*bifaddr))
+    return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
-/* Returns the rs6000 builtin decl for CODE.  Note that we don't check
-   the builtin mask here since there could be some #pragma/attribute
-   target functions and the rs6000_builtin_mask could be wrong when
-   this checking happens, though it will be updated properly later.  */
+  if (bif_is_set (*bifaddr))
+    return altivec_expand_vec_set_builtin (exp);
 
-tree
-rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
-{
-  if (new_builtins_are_live)
-    return rs6000_new_builtin_decl (code, initialize_p);
+  if (bif_is_extract (*bifaddr))
+    return altivec_expand_vec_ext_builtin (exp, target);
 
-  if (code >= RS6000_BUILTIN_COUNT)
-    return error_mark_node;
+  if (bif_is_predicate (*bifaddr))
+    return altivec_expand_predicate_builtin (icode, exp, target);
 
-  return rs6000_builtin_decls[code];
-}
+  if (bif_is_htm (*bifaddr))
+    return new_htm_expand_builtin (bifaddr, fcode, exp, target);
 
-static void
-altivec_init_builtins (void)
-{
-  const struct builtin_description *d;
-  size_t i;
-  tree ftype;
-  tree decl;
-
-  tree pvoid_type_node = build_pointer_type (void_type_node);
-
-  tree int_ftype_opaque
-    = build_function_type_list (integer_type_node,
-				opaque_V4SI_type_node, NULL_TREE);
-  tree opaque_ftype_opaque
-    = build_function_type_list (integer_type_node, NULL_TREE);
-  tree opaque_ftype_opaque_int
-    = build_function_type_list (opaque_V4SI_type_node,
-				opaque_V4SI_type_node, integer_type_node, NULL_TREE);
-  tree opaque_ftype_opaque_opaque_int
-    = build_function_type_list (opaque_V4SI_type_node,
-				opaque_V4SI_type_node, opaque_V4SI_type_node,
-				integer_type_node, NULL_TREE);
-  tree opaque_ftype_opaque_opaque_opaque
-    = build_function_type_list (opaque_V4SI_type_node,
-				opaque_V4SI_type_node, opaque_V4SI_type_node,
-				opaque_V4SI_type_node, NULL_TREE);
-  tree opaque_ftype_opaque_opaque
-    = build_function_type_list (opaque_V4SI_type_node,
-				opaque_V4SI_type_node, opaque_V4SI_type_node,
-				NULL_TREE);
-  tree int_ftype_int_opaque_opaque
-    = build_function_type_list (integer_type_node,
-                                integer_type_node, opaque_V4SI_type_node,
-                                opaque_V4SI_type_node, NULL_TREE);
-  tree int_ftype_int_v4si_v4si
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V4SI_type_node,
-				V4SI_type_node, NULL_TREE);
-  tree int_ftype_int_v2di_v2di
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V2DI_type_node,
-				V2DI_type_node, NULL_TREE);
-  tree int_ftype_int_v1ti_v1ti
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V1TI_type_node,
-				V1TI_type_node, NULL_TREE);
-  tree void_ftype_v4si
-    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
-  tree v8hi_ftype_void
-    = build_function_type_list (V8HI_type_node, NULL_TREE);
-  tree void_ftype_void
-    = build_function_type_list (void_type_node, NULL_TREE);
-  tree void_ftype_int
-    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
-
-  tree opaque_ftype_long_pcvoid
-    = build_function_type_list (opaque_V4SI_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v16qi_ftype_pcvoid
-    = build_function_type_list (V16QI_type_node,
-				pcvoid_type_node,
-				NULL_TREE);
-  tree v16qi_ftype_long_pcvoid
-    = build_function_type_list (V16QI_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v8hi_ftype_long_pcvoid
-    = build_function_type_list (V8HI_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v4si_ftype_long_pcvoid
-    = build_function_type_list (V4SI_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v4sf_ftype_long_pcvoid
-    = build_function_type_list (V4SF_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v2df_ftype_long_pcvoid
-    = build_function_type_list (V2DF_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v2di_ftype_long_pcvoid
-    = build_function_type_list (V2DI_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-  tree v1ti_ftype_long_pcvoid
-    = build_function_type_list (V1TI_type_node,
-				long_integer_type_node, pcvoid_type_node,
-				NULL_TREE);
-
-  tree void_ftype_opaque_long_pvoid
-    = build_function_type_list (void_type_node,
-				opaque_V4SI_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree void_ftype_v4si_long_pvoid
-    = build_function_type_list (void_type_node,
-				V4SI_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree void_ftype_v16qi_long_pvoid
-    = build_function_type_list (void_type_node,
-				V16QI_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-
-  tree void_ftype_v16qi_pvoid_long
-    = build_function_type_list (void_type_node,
-				V16QI_type_node, pvoid_type_node,
-				long_integer_type_node, NULL_TREE);
-
-  tree void_ftype_v8hi_long_pvoid
-    = build_function_type_list (void_type_node,
-				V8HI_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree void_ftype_v4sf_long_pvoid
-    = build_function_type_list (void_type_node,
-				V4SF_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree void_ftype_v2df_long_pvoid
-    = build_function_type_list (void_type_node,
-				V2DF_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree void_ftype_v1ti_long_pvoid
-    = build_function_type_list (void_type_node,
-				V1TI_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree void_ftype_v2di_long_pvoid
-    = build_function_type_list (void_type_node,
-				V2DI_type_node, long_integer_type_node,
-				pvoid_type_node, NULL_TREE);
-  tree int_ftype_int_v8hi_v8hi
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V8HI_type_node,
-				V8HI_type_node, NULL_TREE);
-  tree int_ftype_int_v16qi_v16qi
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V16QI_type_node,
-				V16QI_type_node, NULL_TREE);
-  tree int_ftype_int_v4sf_v4sf
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V4SF_type_node,
-				V4SF_type_node, NULL_TREE);
-  tree int_ftype_int_v2df_v2df
-    = build_function_type_list (integer_type_node,
-				integer_type_node, V2DF_type_node,
-				V2DF_type_node, NULL_TREE);
-  tree v2di_ftype_v2di
-    = build_function_type_list (V2DI_type_node, V2DI_type_node, NULL_TREE);
-  tree v4si_ftype_v4si
-    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
-  tree v8hi_ftype_v8hi
-    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
-  tree v16qi_ftype_v16qi
-    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
-  tree v4sf_ftype_v4sf
-    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
-  tree v2df_ftype_v2df
-    = build_function_type_list (V2DF_type_node, V2DF_type_node, NULL_TREE);
-  tree void_ftype_pcvoid_int_int
-    = build_function_type_list (void_type_node,
-				pcvoid_type_node, integer_type_node,
-				integer_type_node, NULL_TREE);
-
-  def_builtin ("__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
-  def_builtin ("__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
-  def_builtin ("__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
-  def_builtin ("__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
-  def_builtin ("__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
-  def_builtin ("__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
-  def_builtin ("__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
-  def_builtin ("__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
-  def_builtin ("__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
-  def_builtin ("__builtin_altivec_se_lxvrbx", v16qi_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRBX);
-  def_builtin ("__builtin_altivec_se_lxvrhx", v8hi_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRHX);
-  def_builtin ("__builtin_altivec_se_lxvrwx", v4si_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRWX);
-  def_builtin ("__builtin_altivec_se_lxvrdx", v2di_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRDX);
-  def_builtin ("__builtin_altivec_ze_lxvrbx", v16qi_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRBX);
-  def_builtin ("__builtin_altivec_ze_lxvrhx", v8hi_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRHX);
-  def_builtin ("__builtin_altivec_ze_lxvrwx", v4si_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRWX);
-  def_builtin ("__builtin_altivec_ze_lxvrdx", v2di_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRDX);
-  def_builtin ("__builtin_altivec_tr_stxvrbx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRBX);
-  def_builtin ("__builtin_altivec_tr_stxvrhx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRHX);
-  def_builtin ("__builtin_altivec_tr_stxvrwx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRWX);
-  def_builtin ("__builtin_altivec_tr_stxvrdx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRDX);
-  def_builtin ("__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
-  def_builtin ("__builtin_altivec_lvxl_v2df", v2df_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVXL_V2DF);
-  def_builtin ("__builtin_altivec_lvxl_v2di", v2di_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVXL_V2DI);
-  def_builtin ("__builtin_altivec_lvxl_v4sf", v4sf_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVXL_V4SF);
-  def_builtin ("__builtin_altivec_lvxl_v4si", v4si_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVXL_V4SI);
-  def_builtin ("__builtin_altivec_lvxl_v8hi", v8hi_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVXL_V8HI);
-  def_builtin ("__builtin_altivec_lvxl_v16qi", v16qi_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVXL_V16QI);
-  def_builtin ("__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
-  def_builtin ("__builtin_altivec_lvx_v1ti", v1ti_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V1TI);
-  def_builtin ("__builtin_altivec_lvx_v2df", v2df_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V2DF);
-  def_builtin ("__builtin_altivec_lvx_v2di", v2di_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V2DI);
-  def_builtin ("__builtin_altivec_lvx_v4sf", v4sf_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V4SF);
-  def_builtin ("__builtin_altivec_lvx_v4si", v4si_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V4SI);
-  def_builtin ("__builtin_altivec_lvx_v8hi", v8hi_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V8HI);
-  def_builtin ("__builtin_altivec_lvx_v16qi", v16qi_ftype_long_pcvoid,
-	       ALTIVEC_BUILTIN_LVX_V16QI);
-  def_builtin ("__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
-  def_builtin ("__builtin_altivec_stvx_v2df", void_ftype_v2df_long_pvoid,
-	       ALTIVEC_BUILTIN_STVX_V2DF);
-  def_builtin ("__builtin_altivec_stvx_v2di", void_ftype_v2di_long_pvoid,
-	       ALTIVEC_BUILTIN_STVX_V2DI);
-  def_builtin ("__builtin_altivec_stvx_v4sf", void_ftype_v4sf_long_pvoid,
-	       ALTIVEC_BUILTIN_STVX_V4SF);
-  def_builtin ("__builtin_altivec_stvx_v4si", void_ftype_v4si_long_pvoid,
-	       ALTIVEC_BUILTIN_STVX_V4SI);
-  def_builtin ("__builtin_altivec_stvx_v8hi", void_ftype_v8hi_long_pvoid,
-	       ALTIVEC_BUILTIN_STVX_V8HI);
-  def_builtin ("__builtin_altivec_stvx_v16qi", void_ftype_v16qi_long_pvoid,
-	       ALTIVEC_BUILTIN_STVX_V16QI);
-  def_builtin ("__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
-  def_builtin ("__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
-  def_builtin ("__builtin_altivec_stvxl_v2df", void_ftype_v2df_long_pvoid,
-	       ALTIVEC_BUILTIN_STVXL_V2DF);
-  def_builtin ("__builtin_altivec_stvxl_v2di", void_ftype_v2di_long_pvoid,
-	       ALTIVEC_BUILTIN_STVXL_V2DI);
-  def_builtin ("__builtin_altivec_stvxl_v4sf", void_ftype_v4sf_long_pvoid,
-	       ALTIVEC_BUILTIN_STVXL_V4SF);
-  def_builtin ("__builtin_altivec_stvxl_v4si", void_ftype_v4si_long_pvoid,
-	       ALTIVEC_BUILTIN_STVXL_V4SI);
-  def_builtin ("__builtin_altivec_stvxl_v8hi", void_ftype_v8hi_long_pvoid,
-	       ALTIVEC_BUILTIN_STVXL_V8HI);
-  def_builtin ("__builtin_altivec_stvxl_v16qi", void_ftype_v16qi_long_pvoid,
-	       ALTIVEC_BUILTIN_STVXL_V16QI);
-  def_builtin ("__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
-  def_builtin ("__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
-  def_builtin ("__builtin_vec_ld", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LD);
-  def_builtin ("__builtin_vec_lde", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDE);
-  def_builtin ("__builtin_vec_ldl", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDL);
-  def_builtin ("__builtin_vec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSL);
-  def_builtin ("__builtin_vec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSR);
-  def_builtin ("__builtin_vec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEBX);
-  def_builtin ("__builtin_vec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEHX);
-  def_builtin ("__builtin_vec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEWX);
-  def_builtin ("__builtin_vec_se_lxvrx", v1ti_ftype_long_pcvoid, P10_BUILTIN_VEC_SE_LXVRX);
-  def_builtin ("__builtin_vec_ze_lxvrx", v1ti_ftype_long_pcvoid, P10_BUILTIN_VEC_ZE_LXVRX);
-  def_builtin ("__builtin_vec_tr_stxvrx", void_ftype_opaque_long_pvoid, P10_BUILTIN_VEC_TR_STXVRX);
-  def_builtin ("__builtin_vec_st", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_ST);
-  def_builtin ("__builtin_vec_ste", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STE);
-  def_builtin ("__builtin_vec_stl", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STL);
-  def_builtin ("__builtin_vec_stvewx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEWX);
-  def_builtin ("__builtin_vec_stvebx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEBX);
-  def_builtin ("__builtin_vec_stvehx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEHX);
-
-  def_builtin ("__builtin_vsx_lxvd2x_v2df", v2df_ftype_long_pcvoid,
-	       VSX_BUILTIN_LXVD2X_V2DF);
-  def_builtin ("__builtin_vsx_lxvd2x_v2di", v2di_ftype_long_pcvoid,
-	       VSX_BUILTIN_LXVD2X_V2DI);
-  def_builtin ("__builtin_vsx_lxvw4x_v4sf", v4sf_ftype_long_pcvoid,
-	       VSX_BUILTIN_LXVW4X_V4SF);
-  def_builtin ("__builtin_vsx_lxvw4x_v4si", v4si_ftype_long_pcvoid,
-	       VSX_BUILTIN_LXVW4X_V4SI);
-  def_builtin ("__builtin_vsx_lxvw4x_v8hi", v8hi_ftype_long_pcvoid,
-	       VSX_BUILTIN_LXVW4X_V8HI);
-  def_builtin ("__builtin_vsx_lxvw4x_v16qi", v16qi_ftype_long_pcvoid,
-	       VSX_BUILTIN_LXVW4X_V16QI);
-  def_builtin ("__builtin_vsx_stxvd2x_v2df", void_ftype_v2df_long_pvoid,
-	       VSX_BUILTIN_STXVD2X_V2DF);
-  def_builtin ("__builtin_vsx_stxvd2x_v2di", void_ftype_v2di_long_pvoid,
-	       VSX_BUILTIN_STXVD2X_V2DI);
-  def_builtin ("__builtin_vsx_stxvw4x_v4sf", void_ftype_v4sf_long_pvoid,
-	       VSX_BUILTIN_STXVW4X_V4SF);
-  def_builtin ("__builtin_vsx_stxvw4x_v4si", void_ftype_v4si_long_pvoid,
-	       VSX_BUILTIN_STXVW4X_V4SI);
-  def_builtin ("__builtin_vsx_stxvw4x_v8hi", void_ftype_v8hi_long_pvoid,
-	       VSX_BUILTIN_STXVW4X_V8HI);
-  def_builtin ("__builtin_vsx_stxvw4x_v16qi", void_ftype_v16qi_long_pvoid,
-	       VSX_BUILTIN_STXVW4X_V16QI);
-
-  def_builtin ("__builtin_vsx_ld_elemrev_v2df", v2df_ftype_long_pcvoid,
-	       VSX_BUILTIN_LD_ELEMREV_V2DF);
-  def_builtin ("__builtin_vsx_ld_elemrev_v2di", v2di_ftype_long_pcvoid,
-	       VSX_BUILTIN_LD_ELEMREV_V2DI);
-  def_builtin ("__builtin_vsx_ld_elemrev_v4sf", v4sf_ftype_long_pcvoid,
-	       VSX_BUILTIN_LD_ELEMREV_V4SF);
-  def_builtin ("__builtin_vsx_ld_elemrev_v4si", v4si_ftype_long_pcvoid,
-	       VSX_BUILTIN_LD_ELEMREV_V4SI);
-  def_builtin ("__builtin_vsx_ld_elemrev_v8hi", v8hi_ftype_long_pcvoid,
-	       VSX_BUILTIN_LD_ELEMREV_V8HI);
-  def_builtin ("__builtin_vsx_ld_elemrev_v16qi", v16qi_ftype_long_pcvoid,
-	       VSX_BUILTIN_LD_ELEMREV_V16QI);
-  def_builtin ("__builtin_vsx_st_elemrev_v2df", void_ftype_v2df_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V2DF);
-  def_builtin ("__builtin_vsx_st_elemrev_v1ti", void_ftype_v1ti_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V1TI);
-  def_builtin ("__builtin_vsx_st_elemrev_v2di", void_ftype_v2di_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V2DI);
-  def_builtin ("__builtin_vsx_st_elemrev_v4sf", void_ftype_v4sf_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V4SF);
-  def_builtin ("__builtin_vsx_st_elemrev_v4si", void_ftype_v4si_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V4SI);
-  def_builtin ("__builtin_vsx_st_elemrev_v8hi", void_ftype_v8hi_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V8HI);
-  def_builtin ("__builtin_vsx_st_elemrev_v16qi", void_ftype_v16qi_long_pvoid,
-	       VSX_BUILTIN_ST_ELEMREV_V16QI);
-
-  def_builtin ("__builtin_vec_vsx_ld", opaque_ftype_long_pcvoid,
-	       VSX_BUILTIN_VEC_LD);
-  def_builtin ("__builtin_vec_vsx_st", void_ftype_opaque_long_pvoid,
-	       VSX_BUILTIN_VEC_ST);
-  def_builtin ("__builtin_vec_xl", opaque_ftype_long_pcvoid,
-	       VSX_BUILTIN_VEC_XL);
-  def_builtin ("__builtin_vec_xl_be", opaque_ftype_long_pcvoid,
-	       VSX_BUILTIN_VEC_XL_BE);
-  def_builtin ("__builtin_vec_xst", void_ftype_opaque_long_pvoid,
-	       VSX_BUILTIN_VEC_XST);
-  def_builtin ("__builtin_vec_xst_be", void_ftype_opaque_long_pvoid,
-	       VSX_BUILTIN_VEC_XST_BE);
-
-  def_builtin ("__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP);
-  def_builtin ("__builtin_vec_splats", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_SPLATS);
-  def_builtin ("__builtin_vec_promote", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_PROMOTE);
-
-  def_builtin ("__builtin_vec_sld", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_SLD);
-  def_builtin ("__builtin_vec_splat", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_SPLAT);
-  def_builtin ("__builtin_vec_extract", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_EXTRACT);
-  def_builtin ("__builtin_vec_insert", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_INSERT);
-  def_builtin ("__builtin_vec_vspltw", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTW);
-  def_builtin ("__builtin_vec_vsplth", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTH);
-  def_builtin ("__builtin_vec_vspltb", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTB);
-  def_builtin ("__builtin_vec_ctf", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTF);
-  def_builtin ("__builtin_vec_vcfsx", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFSX);
-  def_builtin ("__builtin_vec_vcfux", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFUX);
-  def_builtin ("__builtin_vec_cts", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTS);
-  def_builtin ("__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU);
-
-  def_builtin ("__builtin_vec_adde", opaque_ftype_opaque_opaque_opaque,
-		ALTIVEC_BUILTIN_VEC_ADDE);
-  def_builtin ("__builtin_vec_addec", opaque_ftype_opaque_opaque_opaque,
-		ALTIVEC_BUILTIN_VEC_ADDEC);
-  def_builtin ("__builtin_vec_cmpne", opaque_ftype_opaque_opaque,
-		ALTIVEC_BUILTIN_VEC_CMPNE);
-  def_builtin ("__builtin_vec_mul", opaque_ftype_opaque_opaque,
-		ALTIVEC_BUILTIN_VEC_MUL);
-  def_builtin ("__builtin_vec_sube", opaque_ftype_opaque_opaque_opaque,
-		ALTIVEC_BUILTIN_VEC_SUBE);
-  def_builtin ("__builtin_vec_subec", opaque_ftype_opaque_opaque_opaque,
-		ALTIVEC_BUILTIN_VEC_SUBEC);
-
-  /* Cell builtins.  */
-  def_builtin ("__builtin_altivec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLX);
-  def_builtin ("__builtin_altivec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLXL);
-  def_builtin ("__builtin_altivec_lvrx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRX);
-  def_builtin ("__builtin_altivec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRXL);
-
-  def_builtin ("__builtin_vec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLX);
-  def_builtin ("__builtin_vec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLXL);
-  def_builtin ("__builtin_vec_lvrx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRX);
-  def_builtin ("__builtin_vec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRXL);
-
-  def_builtin ("__builtin_altivec_stvlx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLX);
-  def_builtin ("__builtin_altivec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLXL);
-  def_builtin ("__builtin_altivec_stvrx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRX);
-  def_builtin ("__builtin_altivec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRXL);
-
-  def_builtin ("__builtin_vec_stvlx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLX);
-  def_builtin ("__builtin_vec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLXL);
-  def_builtin ("__builtin_vec_stvrx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRX);
-  def_builtin ("__builtin_vec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRXL);
-
-  if (TARGET_P9_VECTOR)
+  if (bif_is_32bit (*bifaddr) && TARGET_32BIT)
     {
-      def_builtin ("__builtin_altivec_stxvl", void_ftype_v16qi_pvoid_long,
-		   P9V_BUILTIN_STXVL);
-      def_builtin ("__builtin_altivec_xst_len_r", void_ftype_v16qi_pvoid_long,
-		   P9V_BUILTIN_XST_LEN_R);
+      if (fcode == RS6000_BIF_MFTB)
+	icode = CODE_FOR_rs6000_mftb_si;
+      else if (fcode == RS6000_BIF_BPERMD)
+	icode = CODE_FOR_bpermd_si;
+      else
+	gcc_unreachable ();
     }
 
-  /* Add the DST variants.  */
-  d = bdesc_dst;
-  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
+  if (bif_is_endian (*bifaddr) && BYTES_BIG_ENDIAN)
     {
-      /* It is expected that these dst built-in functions may have
-	 d->icode equal to CODE_FOR_nothing.  */
-      def_builtin (d->name, void_ftype_pcvoid_int_int, d->code);
+      if (fcode == RS6000_BIF_LD_ELEMREV_V1TI)
+	icode = CODE_FOR_vsx_load_v1ti;
+      else if (fcode == RS6000_BIF_LD_ELEMREV_V2DF)
+	icode = CODE_FOR_vsx_load_v2df;
+      else if (fcode == RS6000_BIF_LD_ELEMREV_V2DI)
+	icode = CODE_FOR_vsx_load_v2di;
+      else if (fcode == RS6000_BIF_LD_ELEMREV_V4SF)
+	icode = CODE_FOR_vsx_load_v4sf;
+      else if (fcode == RS6000_BIF_LD_ELEMREV_V4SI)
+	icode = CODE_FOR_vsx_load_v4si;
+      else if (fcode == RS6000_BIF_LD_ELEMREV_V8HI)
+	icode = CODE_FOR_vsx_load_v8hi;
+      else if (fcode == RS6000_BIF_LD_ELEMREV_V16QI)
+	icode = CODE_FOR_vsx_load_v16qi;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V1TI)
+	icode = CODE_FOR_vsx_store_v1ti;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V2DF)
+	icode = CODE_FOR_vsx_store_v2df;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V2DI)
+	icode = CODE_FOR_vsx_store_v2di;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V4SF)
+	icode = CODE_FOR_vsx_store_v4sf;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V4SI)
+	icode = CODE_FOR_vsx_store_v4si;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V8HI)
+	icode = CODE_FOR_vsx_store_v8hi;
+      else if (fcode == RS6000_BIF_ST_ELEMREV_V16QI)
+	icode = CODE_FOR_vsx_store_v16qi;
+      else
+	gcc_unreachable ();
     }
 
-  /* Initialize the predicates.  */
-  d = bdesc_altivec_preds;
-  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, d++)
+
+  /* TRUE iff the built-in function returns void.  */
+  bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
+  /* Position of first argument (0 for void-returning functions, else 1).  */
+  int k;
+  /* Modes for the return value, if any, and arguments.  */
+  const int MAX_BUILTIN_ARGS = 6;
+  machine_mode mode[MAX_BUILTIN_ARGS + 1];
+
+  if (void_func)
+    k = 0;
+  else
     {
-      machine_mode mode1;
-      tree type;
+      k = 1;
+      mode[0] = insn_data[icode].operand[0].mode;
+    }
 
-      if (rs6000_overloaded_builtin_p (d->code))
-	mode1 = VOIDmode;
-      else
-	{
-	  /* Cannot define builtin if the instruction is disabled.  */
-	  gcc_assert (d->icode != CODE_FOR_nothing);
-	  mode1 = insn_data[d->icode].operand[1].mode;
-	}
+  /* Tree expressions for each argument.  */
+  tree arg[MAX_BUILTIN_ARGS];
+  /* RTL expressions for each argument.  */
+  rtx op[MAX_BUILTIN_ARGS];
 
-      switch (mode1)
-	{
-	case E_VOIDmode:
-	  type = int_ftype_int_opaque_opaque;
-	  break;
-	case E_V1TImode:
-	  type = int_ftype_int_v1ti_v1ti;
-	  break;
-	case E_V2DImode:
-	  type = int_ftype_int_v2di_v2di;
-	  break;
-	case E_V4SImode:
-	  type = int_ftype_int_v4si_v4si;
-	  break;
-	case E_V8HImode:
-	  type = int_ftype_int_v8hi_v8hi;
-	  break;
-	case E_V16QImode:
-	  type = int_ftype_int_v16qi_v16qi;
-	  break;
-	case E_V4SFmode:
-	  type = int_ftype_int_v4sf_v4sf;
-	  break;
-	case E_V2DFmode:
-	  type = int_ftype_int_v2df_v2df;
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
+  int nargs = bifaddr->nargs;
+  gcc_assert (nargs <= MAX_BUILTIN_ARGS);
 
-      def_builtin (d->name, type, d->code);
-    }
 
-  /* Initialize the abs* operators.  */
-  d = bdesc_abs;
-  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
+  for (int i = 0; i < nargs; i++)
     {
-      machine_mode mode0;
-      tree type;
-
-      /* Cannot define builtin if the instruction is disabled.  */
-      gcc_assert (d->icode != CODE_FOR_nothing);
-      mode0 = insn_data[d->icode].operand[0].mode;
+      arg[i] = CALL_EXPR_ARG (exp, i);
+      if (arg[i] == error_mark_node)
+	return const0_rtx;
+      STRIP_NOPS (arg[i]);
+      op[i] = expand_normal (arg[i]);
+      /* We have a couple of pesky patterns that don't specify the mode...  */
+      mode[i+k] = insn_data[icode].operand[i+k].mode;
+      if (!mode[i+k])
+	mode[i+k] = Pmode;
+    }
 
-      switch (mode0)
+  /* Check for restricted constant arguments.  */
+  for (int i = 0; i < 2; i++)
+    {
+      switch (bifaddr->restr[i])
 	{
-	case E_V2DImode:
-	  type = v2di_ftype_v2di;
-	  break;
-	case E_V4SImode:
-	  type = v4si_ftype_v4si;
-	  break;
-	case E_V8HImode:
-	  type = v8hi_ftype_v8hi;
-	  break;
-	case E_V16QImode:
-	  type = v16qi_ftype_v16qi;
-	  break;
-	case E_V4SFmode:
-	  type = v4sf_ftype_v4sf;
-	  break;
-	case E_V2DFmode:
-	  type = v2df_ftype_v2df;
-	  break;
+	case RES_BITS:
+	  {
+	    size_t mask = 1;
+	    mask <<= bifaddr->restr_val1[i];
+	    mask--;
+	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+	    STRIP_NOPS (restr_arg);
+	    if (!(TREE_CODE (restr_arg) == INTEGER_CST
+		  && (TREE_INT_CST_LOW (restr_arg) & ~mask) == 0))
+	      {
+		error ("argument %d must be a %d-bit unsigned literal",
+		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i]);
+		return CONST0_RTX (mode[0]);
+	      }
+	    break;
+	  }
+	case RES_RANGE:
+	  {
+	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+	    STRIP_NOPS (restr_arg);
+	    if (!(TREE_CODE (restr_arg) == INTEGER_CST
+		  && IN_RANGE (tree_to_shwi (restr_arg),
+			       bifaddr->restr_val1[i],
+			       bifaddr->restr_val2[i])))
+	      {
+		error ("argument %d must be a literal between %d and %d,"
+		       " inclusive",
+		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+		       bifaddr->restr_val2[i]);
+		return CONST0_RTX (mode[0]);
+	      }
+	    break;
+	  }
+	case RES_VAR_RANGE:
+	  {
+	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+	    STRIP_NOPS (restr_arg);
+	    if (TREE_CODE (restr_arg) == INTEGER_CST
+		&& !IN_RANGE (tree_to_shwi (restr_arg),
+			      bifaddr->restr_val1[i],
+			      bifaddr->restr_val2[i]))
+	      {
+		error ("argument %d must be a variable or a literal "
+		       "between %d and %d, inclusive",
+		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+		       bifaddr->restr_val2[i]);
+		return CONST0_RTX (mode[0]);
+	      }
+	    break;
+	  }
+	case RES_VALUES:
+	  {
+	    tree restr_arg = arg[bifaddr->restr_opnd[i] - 1];
+	    STRIP_NOPS (restr_arg);
+	    if (!(TREE_CODE (restr_arg) == INTEGER_CST
+		  && (tree_to_shwi (restr_arg) == bifaddr->restr_val1[i]
+		      || tree_to_shwi (restr_arg) == bifaddr->restr_val2[i])))
+	      {
+		error ("argument %d must be either a literal %d or a "
+		       "literal %d",
+		       bifaddr->restr_opnd[i], bifaddr->restr_val1[i],
+		       bifaddr->restr_val2[i]);
+		return CONST0_RTX (mode[0]);
+	      }
+	    break;
+	  }
 	default:
-	  gcc_unreachable ();
+	case RES_NONE:
+	  break;
 	}
-
-      def_builtin (d->name, type, d->code);
     }
 
-  /* Initialize target builtin that implements
-     targetm.vectorize.builtin_mask_for_load.  */
+  if (bif_is_ldstmask (*bifaddr))
+    return rs6000_expand_ldst_mask (target, arg[0]);
 
-  decl = add_builtin_function ("__builtin_altivec_mask_for_load",
-			       v16qi_ftype_pcvoid,
-			       ALTIVEC_BUILTIN_MASK_FOR_LOAD,
-			       BUILT_IN_MD, NULL, NULL_TREE);
-  TREE_READONLY (decl) = 1;
-  if (TARGET_DEBUG_BUILTIN)
-    {
-      tree arg_type = TREE_VALUE (TYPE_ARG_TYPES (v16qi_ftype_pcvoid));
-      fprintf (stderr, "%s __builtin_altivec_mask_for_load (%s); [%4d]\n",
-	       rs6000_type_string (TREE_TYPE (v16qi_ftype_pcvoid)),
-	       rs6000_type_string (arg_type),
-	       (int) ALTIVEC_BUILTIN_MASK_FOR_LOAD);
-    }
-  /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
-  altivec_builtin_mask_for_load = decl;
-
-  /* Access to the vec_init patterns.  */
-  ftype = build_function_type_list (V4SI_type_node, integer_type_node,
-				    integer_type_node, integer_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_init_v4si", ftype, ALTIVEC_BUILTIN_VEC_INIT_V4SI);
-
-  ftype = build_function_type_list (V8HI_type_node, short_integer_type_node,
-				    short_integer_type_node,
-				    short_integer_type_node,
-				    short_integer_type_node,
-				    short_integer_type_node,
-				    short_integer_type_node,
-				    short_integer_type_node,
-				    short_integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_init_v8hi", ftype, ALTIVEC_BUILTIN_VEC_INIT_V8HI);
-
-  ftype = build_function_type_list (V16QI_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, char_type_node,
-				    char_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_init_v16qi", ftype,
-	       ALTIVEC_BUILTIN_VEC_INIT_V16QI);
-
-  ftype = build_function_type_list (V4SF_type_node, float_type_node,
-				    float_type_node, float_type_node,
-				    float_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_init_v4sf", ftype, ALTIVEC_BUILTIN_VEC_INIT_V4SF);
-
-  /* VSX builtins.  */
-  ftype = build_function_type_list (V2DF_type_node, double_type_node,
-				    double_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_init_v2df", ftype, VSX_BUILTIN_VEC_INIT_V2DF);
-
-  ftype = build_function_type_list (V2DI_type_node, intDI_type_node,
-				    intDI_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_init_v2di", ftype, VSX_BUILTIN_VEC_INIT_V2DI);
-
-  /* Access to the vec_set patterns.  */
-  ftype = build_function_type_list (V4SI_type_node, V4SI_type_node,
-				    intSI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_set_v4si", ftype, ALTIVEC_BUILTIN_VEC_SET_V4SI);
-
-  ftype = build_function_type_list (V8HI_type_node, V8HI_type_node,
-				    intHI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_set_v8hi", ftype, ALTIVEC_BUILTIN_VEC_SET_V8HI);
-
-  ftype = build_function_type_list (V16QI_type_node, V16QI_type_node,
-				    intQI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_set_v16qi", ftype, ALTIVEC_BUILTIN_VEC_SET_V16QI);
-
-  ftype = build_function_type_list (V4SF_type_node, V4SF_type_node,
-				    float_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_set_v4sf", ftype, ALTIVEC_BUILTIN_VEC_SET_V4SF);
-
-  ftype = build_function_type_list (V2DF_type_node, V2DF_type_node,
-				    double_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_set_v2df", ftype, VSX_BUILTIN_VEC_SET_V2DF);
-
-  ftype = build_function_type_list (V2DI_type_node, V2DI_type_node,
-				    intDI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_set_v2di", ftype, VSX_BUILTIN_VEC_SET_V2DI);
-
-  /* Access to the vec_extract patterns.  */
-  ftype = build_function_type_list (intSI_type_node, V4SI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_ext_v4si", ftype, ALTIVEC_BUILTIN_VEC_EXT_V4SI);
-
-  ftype = build_function_type_list (intHI_type_node, V8HI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_ext_v8hi", ftype, ALTIVEC_BUILTIN_VEC_EXT_V8HI);
-
-  ftype = build_function_type_list (intQI_type_node, V16QI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_ext_v16qi", ftype, ALTIVEC_BUILTIN_VEC_EXT_V16QI);
-
-  ftype = build_function_type_list (float_type_node, V4SF_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_ext_v4sf", ftype, ALTIVEC_BUILTIN_VEC_EXT_V4SF);
-
-  ftype = build_function_type_list (double_type_node, V2DF_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_ext_v2df", ftype, VSX_BUILTIN_VEC_EXT_V2DF);
-
-  ftype = build_function_type_list (intDI_type_node, V2DI_type_node,
-				    integer_type_node, NULL_TREE);
-  def_builtin ("__builtin_vec_ext_v2di", ftype, VSX_BUILTIN_VEC_EXT_V2DI);
-
-
-  if (V1TI_type_node)
+  if (bif_is_stvec (*bifaddr))
     {
-      tree v1ti_ftype_long_pcvoid
-	= build_function_type_list (V1TI_type_node,
-				    long_integer_type_node, pcvoid_type_node,
-				    NULL_TREE);
-      tree void_ftype_v1ti_long_pvoid
-	= build_function_type_list (void_type_node,
-				    V1TI_type_node, long_integer_type_node,
-				    pvoid_type_node, NULL_TREE);
-      def_builtin ("__builtin_vsx_ld_elemrev_v1ti", v1ti_ftype_long_pcvoid,
-		   VSX_BUILTIN_LD_ELEMREV_V1TI);
-      def_builtin ("__builtin_vsx_lxvd2x_v1ti", v1ti_ftype_long_pcvoid,
-		   VSX_BUILTIN_LXVD2X_V1TI);
-      def_builtin ("__builtin_vsx_stxvd2x_v1ti", void_ftype_v1ti_long_pvoid,
-		   VSX_BUILTIN_STXVD2X_V1TI);
-      ftype = build_function_type_list (V1TI_type_node, intTI_type_node,
-					NULL_TREE, NULL_TREE);
-      def_builtin ("__builtin_vec_init_v1ti", ftype, VSX_BUILTIN_VEC_INIT_V1TI);
-      ftype = build_function_type_list (V1TI_type_node, V1TI_type_node,
-					intTI_type_node,
-					integer_type_node, NULL_TREE);
-      def_builtin ("__builtin_vec_set_v1ti", ftype, VSX_BUILTIN_VEC_SET_V1TI);
-      ftype = build_function_type_list (intTI_type_node, V1TI_type_node,
-					integer_type_node, NULL_TREE);
-      def_builtin ("__builtin_vec_ext_v1ti", ftype, VSX_BUILTIN_VEC_EXT_V1TI);
+      if (bif_is_reve (*bifaddr))
+	icode = elemrev_icode (fcode);
+      return stv_expand_builtin (icode, op, mode[0], mode[1]);
     }
 
-}
-
-static void
-mma_init_builtins (void)
-{
-  const struct builtin_description *d = bdesc_mma;
-
-  for (unsigned i = 0; i < ARRAY_SIZE (bdesc_mma); i++, d++)
+  if (bif_is_ldvec (*bifaddr))
     {
-      tree op[MAX_MMA_OPERANDS], type;
-      unsigned icode = (unsigned) d->icode;
-      unsigned attr = rs6000_builtin_info[d->code].attr;
-      int attr_args = (attr & RS6000_BTC_OPND_MASK);
-      bool gimple_func = (attr & RS6000_BTC_GIMPLE);
-      unsigned nopnds = 0;
-
-      if (d->name == 0)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "mma_builtin, bdesc_mma[%ld] no name\n",
-		     (long unsigned) i);
-	  continue;
-	}
-
-      if (gimple_func)
-	{
-	  gcc_assert (icode == CODE_FOR_nothing);
-	  /* Some MMA built-ins that are expanded into gimple are converted
-	     into internal MMA built-ins that are expanded into rtl.
-	     The internal built-in follows immediately after this built-in.  */
-	  if (d->code != VSX_BUILTIN_LXVP
-	      && d->code != VSX_BUILTIN_STXVP)
-	    {
-	      op[nopnds++] = void_type_node;
-	      icode = d[1].icode;
-	    }
-	}
-      else
-	{
-	  if (!(d->code == MMA_BUILTIN_DISASSEMBLE_ACC_INTERNAL
-		 || d->code == VSX_BUILTIN_DISASSEMBLE_PAIR_INTERNAL)
-	       && (attr & RS6000_BTC_QUAD) == 0)
-	    attr_args--;
+      if (bif_is_reve (*bifaddr))
+	icode = elemrev_icode (fcode);
+      return ldv_expand_builtin (target, icode, op, mode[0]);
+    }
 
-	  /* Ensure we have the correct number and type of operands.  */
-	  gcc_assert (attr_args == insn_data[icode].n_operands - 1);
-	}
+  if (bif_is_lxvrse (*bifaddr))
+    return lxvrse_expand_builtin (target, icode, op, mode[0], mode[1]);
 
-      /* This is a disassemble pair/acc function. */
-      if (d->code == MMA_BUILTIN_DISASSEMBLE_ACC
-	  || d->code == VSX_BUILTIN_DISASSEMBLE_PAIR)
-	{
-	  op[nopnds++] = build_pointer_type (void_type_node);
-	  if (d->code == MMA_BUILTIN_DISASSEMBLE_ACC)
-	    op[nopnds++] = build_pointer_type (vector_quad_type_node);
-	  else
-	    op[nopnds++] = build_pointer_type (vector_pair_type_node);
-	}
-      else if (d->code == VSX_BUILTIN_LXVP)
-	{
-	  op[nopnds++] = vector_pair_type_node;
-	  op[nopnds++] = sizetype;
-	  op[nopnds++] = build_pointer_type (vector_pair_type_node);
-	}
-      else if (d->code == VSX_BUILTIN_STXVP)
-	{
-	  op[nopnds++] = void_type_node;
-	  op[nopnds++] = vector_pair_type_node;
-	  op[nopnds++] = sizetype;
-	  op[nopnds++] = build_pointer_type (vector_pair_type_node);
-	}
-      else
-	{
-	  /* This is a normal MMA built-in function.  */
-	  unsigned j = 0;
-	  if (attr & RS6000_BTC_QUAD
-	      && d->code != MMA_BUILTIN_DISASSEMBLE_ACC_INTERNAL
-	      && d->code != VSX_BUILTIN_DISASSEMBLE_PAIR_INTERNAL)
-	    j = 1;
-	  for (; j < (unsigned) insn_data[icode].n_operands; j++)
-	    {
-	      machine_mode mode = insn_data[icode].operand[j].mode;
-	      if (gimple_func && mode == XOmode)
-		op[nopnds++] = build_pointer_type (vector_quad_type_node);
-	      else if (gimple_func
-		       && mode == OOmode
-		       && (d->code == VSX_BUILTIN_BUILD_PAIR
-			   || d->code == VSX_BUILTIN_ASSEMBLE_PAIR))
-		op[nopnds++] = build_pointer_type (vector_pair_type_node);
-	      else
-		/* MMA uses unsigned types.  */
-		op[nopnds++] = builtin_mode_to_type[mode][1];
-	    }
-	}
+  if (bif_is_lxvrze (*bifaddr))
+    return lxvrze_expand_builtin (target, icode, op, mode[0], mode[1]);
 
-      switch (nopnds)
-	{
-	case 1:
-	  type = build_function_type_list (op[0], NULL_TREE);
-	  break;
-	case 2:
-	  type = build_function_type_list (op[0], op[1], NULL_TREE);
-	  break;
-	case 3:
-	  type = build_function_type_list (op[0], op[1], op[2], NULL_TREE);
-	  break;
-	case 4:
-	  type = build_function_type_list (op[0], op[1], op[2], op[3],
-					   NULL_TREE);
-	  break;
-	case 5:
-	  type = build_function_type_list (op[0], op[1], op[2], op[3], op[4],
-					   NULL_TREE);
-	  break;
-	case 6:
-	  type = build_function_type_list (op[0], op[1], op[2], op[3], op[4],
-					   op[5], NULL_TREE);
-	  break;
-	case 7:
-	  type = build_function_type_list (op[0], op[1], op[2], op[3], op[4],
-					   op[5], op[6], NULL_TREE);
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
+  if (bif_is_mma (*bifaddr))
+    return new_mma_expand_builtin (exp, target, icode, fcode);
 
-      def_builtin (d->name, type, d->code);
+  if (fcode == RS6000_BIF_PACK_IF
+      && TARGET_LONG_DOUBLE_128
+      && !TARGET_IEEEQUAD)
+    {
+      icode = CODE_FOR_packtf;
+      fcode = RS6000_BIF_PACK_TF;
+      uns_fcode = (size_t) fcode;
     }
-}
-
-static void
-htm_init_builtins (void)
-{
-  HOST_WIDE_INT builtin_mask = rs6000_builtin_mask;
-  const struct builtin_description *d;
-  size_t i;
-
-  d = bdesc_htm;
-  for (i = 0; i < ARRAY_SIZE (bdesc_htm); i++, d++)
+  else if (fcode == RS6000_BIF_UNPACK_IF
+	   && TARGET_LONG_DOUBLE_128
+	   && !TARGET_IEEEQUAD)
     {
-      tree op[MAX_HTM_OPERANDS], type;
-      HOST_WIDE_INT mask = d->mask;
-      unsigned attr = rs6000_builtin_info[d->code].attr;
-      bool void_func = (attr & RS6000_BTC_VOID);
-      int attr_args = (attr & RS6000_BTC_OPND_MASK);
-      int nopnds = 0;
-      tree gpr_type_node;
-      tree rettype;
-      tree argtype;
-
-      /* It is expected that these htm built-in functions may have
-	 d->icode equal to CODE_FOR_nothing.  */
-
-      if (TARGET_32BIT && TARGET_POWERPC64)
-	gpr_type_node = long_long_unsigned_type_node;
-      else
-	gpr_type_node = long_unsigned_type_node;
-
-      if (attr & RS6000_BTC_SPR)
-	{
-	  rettype = gpr_type_node;
-	  argtype = gpr_type_node;
-	}
-      else if (d->code == HTM_BUILTIN_TABORTDC
-	       || d->code == HTM_BUILTIN_TABORTDCI)
-	{
-	  rettype = unsigned_type_node;
-	  argtype = gpr_type_node;
-	}
-      else
-	{
-	  rettype = unsigned_type_node;
-	  argtype = unsigned_type_node;
-	}
+      icode = CODE_FOR_unpacktf;
+      fcode = RS6000_BIF_UNPACK_TF;
+      uns_fcode = (size_t) fcode;
+    }
 
-      if ((mask & builtin_mask) != mask)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "htm_builtin, skip binary %s\n", d->name);
-	  continue;
-	}
+  if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node)
+    target = NULL_RTX;
+  else if (target == 0
+	   || GET_MODE (target) != mode[0]
+	   || !insn_data[icode].operand[0].predicate (target, mode[0]))
+    target = gen_reg_rtx (mode[0]);
 
-      if (d->name == 0)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "htm_builtin, bdesc_htm[%ld] no name\n",
-		     (long unsigned) i);
-	  continue;
-	}
+  for (int i = 0; i < nargs; i++)
+    if (!insn_data[icode].operand[i+k].predicate (op[i], mode[i+k]))
+      op[i] = copy_to_mode_reg (mode[i+k], op[i]);
 
-      op[nopnds++] = (void_func) ? void_type_node : rettype;
+  rtx pat;
 
-      if (attr_args == RS6000_BTC_UNARY)
-	op[nopnds++] = argtype;
-      else if (attr_args == RS6000_BTC_BINARY)
-	{
-	  op[nopnds++] = argtype;
-	  op[nopnds++] = argtype;
-	}
-      else if (attr_args == RS6000_BTC_TERNARY)
-	{
-	  op[nopnds++] = argtype;
-	  op[nopnds++] = argtype;
-	  op[nopnds++] = argtype;
-	}
+  switch (nargs)
+    {
+    case 0:
+      pat = (void_func
+	     ? GEN_FCN (icode) ()
+	     : GEN_FCN (icode) (target));
+      break;
+    case 1:
+      pat = (void_func
+	     ? GEN_FCN (icode) (op[0])
+	     : GEN_FCN (icode) (target, op[0]));
+      break;
+    case 2:
+      pat = (void_func
+	     ? GEN_FCN (icode) (op[0], op[1])
+	     : GEN_FCN (icode) (target, op[0], op[1]));
+      break;
+    case 3:
+      pat = (void_func
+	     ? GEN_FCN (icode) (op[0], op[1], op[2])
+	     : GEN_FCN (icode) (target, op[0], op[1], op[2]));
+      break;
+    case 4:
+      pat = (void_func
+	     ? GEN_FCN (icode) (op[0], op[1], op[2], op[3])
+	     : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]));
+      break;
+    case 5:
+      pat = (void_func
+	     ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4])
+	     : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]));
+      break;
+    case 6:
+      pat = (void_func
+	     ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5])
+	     : GEN_FCN (icode) (target, op[0], op[1],
+				op[2], op[3], op[4], op[5]));
+      break;
+    default:
+      gcc_assert (MAX_BUILTIN_ARGS == 6);
+      gcc_unreachable ();
+    }
 
-      switch (nopnds)
-	{
-	case 1:
-	  type = build_function_type_list (op[0], NULL_TREE);
-	  break;
-	case 2:
-	  type = build_function_type_list (op[0], op[1], NULL_TREE);
-	  break;
-	case 3:
-	  type = build_function_type_list (op[0], op[1], op[2], NULL_TREE);
-	  break;
-	case 4:
-	  type = build_function_type_list (op[0], op[1], op[2], op[3],
-					   NULL_TREE);
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
+  if (!pat)
+    return 0;
 
-      def_builtin (d->name, type, d->code);
-    }
+  emit_insn (pat);
+  return target;
 }
 
-/* Map types for builtin functions with an explicit return type and
-   exactly 4 arguments.  Functions with fewer than 3 arguments use
-   builtin_function_type.  The number of quaternary built-in
-   functions is very small.  Handle each case specially.  */
+/* Create a builtin vector type with a name.  Taking care not to give
+   the canonical type a name.  */
+
 static tree
-builtin_quaternary_function_type (machine_mode mode_ret,
-				  machine_mode mode_arg0,
-				  machine_mode mode_arg1,
-				  machine_mode mode_arg2,
-				  machine_mode mode_arg3,
-				  enum rs6000_builtins builtin)
+rs6000_vector_type (const char *name, tree elt_type, unsigned num_elts)
 {
-  tree function_type = NULL;
-
-  static tree v2udi_type = builtin_mode_to_type[V2DImode][1];
-  static tree v16uqi_type = builtin_mode_to_type[V16QImode][1];
-  static tree uchar_type = builtin_mode_to_type[QImode][1];
-
-  static tree xxeval_type =
-    build_function_type_list (v2udi_type, v2udi_type, v2udi_type,
-			      v2udi_type, uchar_type, NULL_TREE);
-
-  static tree xxpermx_type =
-    build_function_type_list (v2udi_type, v2udi_type, v2udi_type,
-			      v16uqi_type, uchar_type, NULL_TREE);
-
-  switch (builtin) {
-
-  case P10V_BUILTIN_XXEVAL:
-    gcc_assert ((mode_ret == V2DImode)
-		&& (mode_arg0 == V2DImode)
-		&& (mode_arg1 == V2DImode)
-		&& (mode_arg2 == V2DImode)
-		&& (mode_arg3 == QImode));
-    function_type = xxeval_type;
-    break;
-
-  case P10V_BUILTIN_VXXPERMX:
-    gcc_assert ((mode_ret == V2DImode)
-		&& (mode_arg0 == V2DImode)
-		&& (mode_arg1 == V2DImode)
-		&& (mode_arg2 == V16QImode)
-		&& (mode_arg3 == QImode));
-    function_type = xxpermx_type;
-    break;
-
-  default:
-    /* A case for each quaternary built-in must be provided above.  */
-    gcc_unreachable ();
-  }
+  tree result = build_vector_type (elt_type, num_elts);
+
+  /* Copy so we don't give the canonical type a name.  */
+  result = build_variant_type_copy (result);
+
+  add_builtin_type (name, result);
 
-  return function_type;
+  return result;
 }
 
-/* Map types for builtin functions with an explicit return type and up to 3
-   arguments.  Functions with fewer than 3 arguments use VOIDmode as the type
-   of the argument.  */
-static tree
-builtin_function_type (machine_mode mode_ret, machine_mode mode_arg0,
-		       machine_mode mode_arg1, machine_mode mode_arg2,
-		       enum rs6000_builtins builtin, const char *name)
+void
+rs6000_init_builtins (void)
 {
-  struct builtin_hash_struct h;
-  struct builtin_hash_struct *h2;
-  int num_args = 3;
-  int i;
-  tree ret_type = NULL_TREE;
-  tree arg_type[3] = { NULL_TREE, NULL_TREE, NULL_TREE };
-
-  /* Create builtin_hash_table.  */
-  if (builtin_hash_table == NULL)
-    builtin_hash_table = hash_table<builtin_hasher>::create_ggc (1500);
-
-  h.type = NULL_TREE;
-  h.mode[0] = mode_ret;
-  h.mode[1] = mode_arg0;
-  h.mode[2] = mode_arg1;
-  h.mode[3] = mode_arg2;
-  h.uns_p[0] = 0;
-  h.uns_p[1] = 0;
-  h.uns_p[2] = 0;
-  h.uns_p[3] = 0;
-
-  /* If the builtin is a type that produces unsigned results or takes unsigned
-     arguments, and it is returned as a decl for the vectorizer (such as
-     widening multiplies, permute), make sure the arguments and return value
-     are type correct.  */
-  switch (builtin)
-    {
-    /* unsigned 1 argument functions.  */
-    case CRYPTO_BUILTIN_VSBOX:
-    case CRYPTO_BUILTIN_VSBOX_BE:
-    case P8V_BUILTIN_VGBBD:
-    case MISC_BUILTIN_CDTBCD:
-    case MISC_BUILTIN_CBCDTD:
-    case P10V_BUILTIN_XVCVSPBF16:
-    case P10V_BUILTIN_XVCVBF16SPN:
-    case P10V_BUILTIN_MTVSRBM:
-    case P10V_BUILTIN_MTVSRHM:
-    case P10V_BUILTIN_MTVSRWM:
-    case P10V_BUILTIN_MTVSRDM:
-    case P10V_BUILTIN_MTVSRQM:
-    case P10V_BUILTIN_VCNTMBB:
-    case P10V_BUILTIN_VCNTMBH:
-    case P10V_BUILTIN_VCNTMBW:
-    case P10V_BUILTIN_VCNTMBD:
-    case P10V_BUILTIN_VEXPANDMB:
-    case P10V_BUILTIN_VEXPANDMH:
-    case P10V_BUILTIN_VEXPANDMW:
-    case P10V_BUILTIN_VEXPANDMD:
-    case P10V_BUILTIN_VEXPANDMQ:
-      h.uns_p[0] = 1;
-      h.uns_p[1] = 1;
-      break;
+  tree tdecl;
+  tree t;
 
-    /* unsigned 2 argument functions.  */
-    case ALTIVEC_BUILTIN_VMULEUB:
-    case ALTIVEC_BUILTIN_VMULEUH:
-    case P8V_BUILTIN_VMULEUW:
-    case ALTIVEC_BUILTIN_VMULOUB:
-    case ALTIVEC_BUILTIN_VMULOUH:
-    case P8V_BUILTIN_VMULOUW:
-    case CRYPTO_BUILTIN_VCIPHER:
-    case CRYPTO_BUILTIN_VCIPHER_BE:
-    case CRYPTO_BUILTIN_VCIPHERLAST:
-    case CRYPTO_BUILTIN_VCIPHERLAST_BE:
-    case CRYPTO_BUILTIN_VNCIPHER:
-    case CRYPTO_BUILTIN_VNCIPHER_BE:
-    case CRYPTO_BUILTIN_VNCIPHERLAST:
-    case CRYPTO_BUILTIN_VNCIPHERLAST_BE:
-    case CRYPTO_BUILTIN_VPMSUMB:
-    case CRYPTO_BUILTIN_VPMSUMH:
-    case CRYPTO_BUILTIN_VPMSUMW:
-    case CRYPTO_BUILTIN_VPMSUMD:
-    case CRYPTO_BUILTIN_VPMSUM:
-    case MISC_BUILTIN_ADDG6S:
-    case MISC_BUILTIN_DIVWEU:
-    case MISC_BUILTIN_DIVDEU:
-    case VSX_BUILTIN_UDIV_V2DI:
-    case ALTIVEC_BUILTIN_VMAXUB:
-    case ALTIVEC_BUILTIN_VMINUB:
-    case ALTIVEC_BUILTIN_VMAXUH:
-    case ALTIVEC_BUILTIN_VMINUH:
-    case ALTIVEC_BUILTIN_VMAXUW:
-    case ALTIVEC_BUILTIN_VMINUW:
-    case P8V_BUILTIN_VMAXUD:
-    case P8V_BUILTIN_VMINUD:
-    case ALTIVEC_BUILTIN_VAND_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VAND_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VANDC_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VNOR_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VOR_V2DI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V16QI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V8HI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V4SI_UNS:
-    case ALTIVEC_BUILTIN_VXOR_V2DI_UNS:
-    case P8V_BUILTIN_EQV_V16QI_UNS:
-    case P8V_BUILTIN_EQV_V8HI_UNS:
-    case P8V_BUILTIN_EQV_V4SI_UNS:
-    case P8V_BUILTIN_EQV_V2DI_UNS:
-    case P8V_BUILTIN_EQV_V1TI_UNS:
-    case P8V_BUILTIN_NAND_V16QI_UNS:
-    case P8V_BUILTIN_NAND_V8HI_UNS:
-    case P8V_BUILTIN_NAND_V4SI_UNS:
-    case P8V_BUILTIN_NAND_V2DI_UNS:
-    case P8V_BUILTIN_NAND_V1TI_UNS:
-    case P8V_BUILTIN_ORC_V16QI_UNS:
-    case P8V_BUILTIN_ORC_V8HI_UNS:
-    case P8V_BUILTIN_ORC_V4SI_UNS:
-    case P8V_BUILTIN_ORC_V2DI_UNS:
-    case P8V_BUILTIN_ORC_V1TI_UNS:
-    case P10_BUILTIN_CFUGED:
-    case P10_BUILTIN_CNTLZDM:
-    case P10_BUILTIN_CNTTZDM:
-    case P10_BUILTIN_PDEPD:
-    case P10_BUILTIN_PEXTD:
-    case P10V_BUILTIN_VCFUGED:
-    case P10V_BUILTIN_VCLZDM:
-    case P10V_BUILTIN_VCTZDM:
-    case P10V_BUILTIN_VGNB:
-    case P10V_BUILTIN_VPDEPD:
-    case P10V_BUILTIN_VPEXTD:
-    case P10V_BUILTIN_XXGENPCVM_V16QI:
-    case P10V_BUILTIN_XXGENPCVM_V8HI:
-    case P10V_BUILTIN_XXGENPCVM_V4SI:
-    case P10V_BUILTIN_XXGENPCVM_V2DI:
-    case P10V_BUILTIN_DIVEU_V4SI:
-    case P10V_BUILTIN_DIVEU_V2DI:
-    case P10V_BUILTIN_DIVEU_V1TI:
-    case P10V_BUILTIN_DIVU_V4SI:
-    case P10V_BUILTIN_DIVU_V2DI:
-    case P10V_BUILTIN_MODU_V1TI:
-    case P10V_BUILTIN_MODU_V2DI:
-    case P10V_BUILTIN_MODU_V4SI:
-    case P10V_BUILTIN_MULHU_V2DI:
-    case P10V_BUILTIN_MULHU_V4SI:
-    case P10V_BUILTIN_VMULEUD:
-    case P10V_BUILTIN_VMULOUD:
-      h.uns_p[0] = 1;
-      h.uns_p[1] = 1;
-      h.uns_p[2] = 1;
-      break;
+  if (TARGET_DEBUG_BUILTIN)
+    fprintf (stderr, "rs6000_init_builtins%s%s\n",
+	     (TARGET_ALTIVEC)	   ? ", altivec" : "",
+	     (TARGET_VSX)	   ? ", vsx"	 : "");
 
-    /* unsigned 3 argument functions.  */
-    case ALTIVEC_BUILTIN_VPERM_16QI_UNS:
-    case ALTIVEC_BUILTIN_VPERM_8HI_UNS:
-    case ALTIVEC_BUILTIN_VPERM_4SI_UNS:
-    case ALTIVEC_BUILTIN_VPERM_2DI_UNS:
-    case ALTIVEC_BUILTIN_VSEL_16QI_UNS:
-    case ALTIVEC_BUILTIN_VSEL_8HI_UNS:
-    case ALTIVEC_BUILTIN_VSEL_4SI_UNS:
-    case ALTIVEC_BUILTIN_VSEL_2DI_UNS:
-    case VSX_BUILTIN_VPERM_16QI_UNS:
-    case VSX_BUILTIN_VPERM_8HI_UNS:
-    case VSX_BUILTIN_VPERM_4SI_UNS:
-    case VSX_BUILTIN_VPERM_2DI_UNS:
-    case VSX_BUILTIN_XXSEL_16QI_UNS:
-    case VSX_BUILTIN_XXSEL_8HI_UNS:
-    case VSX_BUILTIN_XXSEL_4SI_UNS:
-    case VSX_BUILTIN_XXSEL_2DI_UNS:
-    case CRYPTO_BUILTIN_VPERMXOR:
-    case CRYPTO_BUILTIN_VPERMXOR_V2DI:
-    case CRYPTO_BUILTIN_VPERMXOR_V4SI:
-    case CRYPTO_BUILTIN_VPERMXOR_V8HI:
-    case CRYPTO_BUILTIN_VPERMXOR_V16QI:
-    case CRYPTO_BUILTIN_VSHASIGMAW:
-    case CRYPTO_BUILTIN_VSHASIGMAD:
-    case CRYPTO_BUILTIN_VSHASIGMA:
-    case P10V_BUILTIN_VEXTRACTBL:
-    case P10V_BUILTIN_VEXTRACTHL:
-    case P10V_BUILTIN_VEXTRACTWL:
-    case P10V_BUILTIN_VEXTRACTDL:
-    case P10V_BUILTIN_VEXTRACTBR:
-    case P10V_BUILTIN_VEXTRACTHR:
-    case P10V_BUILTIN_VEXTRACTWR:
-    case P10V_BUILTIN_VEXTRACTDR:
-    case P10V_BUILTIN_VINSERTGPRBL:
-    case P10V_BUILTIN_VINSERTGPRHL:
-    case P10V_BUILTIN_VINSERTGPRWL:
-    case P10V_BUILTIN_VINSERTGPRDL:
-    case P10V_BUILTIN_VINSERTVPRBL:
-    case P10V_BUILTIN_VINSERTVPRHL:
-    case P10V_BUILTIN_VINSERTVPRWL:
-    case P10V_BUILTIN_VREPLACE_ELT_UV4SI:
-    case P10V_BUILTIN_VREPLACE_ELT_UV2DI:
-    case P10V_BUILTIN_VREPLACE_UN_UV4SI:
-    case P10V_BUILTIN_VREPLACE_UN_UV2DI:
-    case P10V_BUILTIN_VXXBLEND_V16QI:
-    case P10V_BUILTIN_VXXBLEND_V8HI:
-    case P10V_BUILTIN_VXXBLEND_V4SI:
-    case P10V_BUILTIN_VXXBLEND_V2DI:
-      h.uns_p[0] = 1;
-      h.uns_p[1] = 1;
-      h.uns_p[2] = 1;
-      h.uns_p[3] = 1;
-      break;
+  V2DI_type_node = rs6000_vector_type ("__vector long long",
+				       long_long_integer_type_node, 2);
+  ptr_V2DI_type_node
+    = build_pointer_type (build_qualified_type (V2DI_type_node,
+						TYPE_QUAL_CONST));
 
-    /* signed permute functions with unsigned char mask.  */
-    case ALTIVEC_BUILTIN_VPERM_16QI:
-    case ALTIVEC_BUILTIN_VPERM_8HI:
-    case ALTIVEC_BUILTIN_VPERM_4SI:
-    case ALTIVEC_BUILTIN_VPERM_4SF:
-    case ALTIVEC_BUILTIN_VPERM_2DI:
-    case ALTIVEC_BUILTIN_VPERM_2DF:
-    case VSX_BUILTIN_VPERM_16QI:
-    case VSX_BUILTIN_VPERM_8HI:
-    case VSX_BUILTIN_VPERM_4SI:
-    case VSX_BUILTIN_VPERM_4SF:
-    case VSX_BUILTIN_VPERM_2DI:
-    case VSX_BUILTIN_VPERM_2DF:
-      h.uns_p[3] = 1;
-      break;
+  V2DF_type_node = rs6000_vector_type ("__vector double", double_type_node, 2);
+  ptr_V2DF_type_node
+    = build_pointer_type (build_qualified_type (V2DF_type_node,
+						TYPE_QUAL_CONST));
 
-    /* unsigned args, signed return.  */
-    case VSX_BUILTIN_XVCVUXDSP:
-    case VSX_BUILTIN_XVCVUXDDP_UNS:
-    case ALTIVEC_BUILTIN_UNSFLOAT_V4SI_V4SF:
-      h.uns_p[1] = 1;
-      break;
+  V4SI_type_node = rs6000_vector_type ("__vector signed int",
+				       intSI_type_node, 4);
+  ptr_V4SI_type_node
+    = build_pointer_type (build_qualified_type (V4SI_type_node,
+						TYPE_QUAL_CONST));
 
-    /* signed args, unsigned return.  */
-    case VSX_BUILTIN_XVCVDPUXDS_UNS:
-    case ALTIVEC_BUILTIN_FIXUNS_V4SF_V4SI:
-    case MISC_BUILTIN_UNPACK_TD:
-    case MISC_BUILTIN_UNPACK_V1TI:
-      h.uns_p[0] = 1;
-      break;
+  V4SF_type_node = rs6000_vector_type ("__vector float", float_type_node, 4);
+  ptr_V4SF_type_node
+    = build_pointer_type (build_qualified_type (V4SF_type_node,
+						TYPE_QUAL_CONST));
 
-    /* unsigned arguments, bool return (compares).  */
-    case ALTIVEC_BUILTIN_VCMPEQUB:
-    case ALTIVEC_BUILTIN_VCMPEQUH:
-    case ALTIVEC_BUILTIN_VCMPEQUW:
-    case P8V_BUILTIN_VCMPEQUD:
-    case VSX_BUILTIN_CMPGE_U16QI:
-    case VSX_BUILTIN_CMPGE_U8HI:
-    case VSX_BUILTIN_CMPGE_U4SI:
-    case VSX_BUILTIN_CMPGE_U2DI:
-    case P10V_BUILTIN_CMPGE_U1TI:
-    case ALTIVEC_BUILTIN_VCMPGTUB:
-    case ALTIVEC_BUILTIN_VCMPGTUH:
-    case ALTIVEC_BUILTIN_VCMPGTUW:
-    case P8V_BUILTIN_VCMPGTUD:
-    case P10V_BUILTIN_VCMPGTUT:
-    case P10V_BUILTIN_VCMPEQUT:
-      h.uns_p[1] = 1;
-      h.uns_p[2] = 1;
-      break;
+  V8HI_type_node = rs6000_vector_type ("__vector signed short",
+				       intHI_type_node, 8);
+  ptr_V8HI_type_node
+    = build_pointer_type (build_qualified_type (V8HI_type_node,
+						TYPE_QUAL_CONST));
 
-    /* unsigned arguments for 128-bit pack instructions.  */
-    case MISC_BUILTIN_PACK_TD:
-    case MISC_BUILTIN_PACK_V1TI:
-      h.uns_p[1] = 1;
-      h.uns_p[2] = 1;
-      break;
+  V16QI_type_node = rs6000_vector_type ("__vector signed char",
+					intQI_type_node, 16);
+  ptr_V16QI_type_node
+    = build_pointer_type (build_qualified_type (V16QI_type_node,
+						TYPE_QUAL_CONST));
 
-    /* unsigned second arguments (vector shift right).  */
-    case ALTIVEC_BUILTIN_VSRB:
-    case ALTIVEC_BUILTIN_VSRH:
-    case ALTIVEC_BUILTIN_VSRW:
-    case P8V_BUILTIN_VSRD:
-    /* Vector splat immediate insert */
-    case P10V_BUILTIN_VXXSPLTI32DX_V4SI:
-    case P10V_BUILTIN_VXXSPLTI32DX_V4SF:
-      h.uns_p[2] = 1;
-      break;
+  unsigned_V16QI_type_node = rs6000_vector_type ("__vector unsigned char",
+					unsigned_intQI_type_node, 16);
+  ptr_unsigned_V16QI_type_node
+    = build_pointer_type (build_qualified_type (unsigned_V16QI_type_node,
+						TYPE_QUAL_CONST));
 
-    case VSX_BUILTIN_LXVP:
-      h.uns_p[0] = 1;
-      h.uns_p[2] = 1;
-      break;
+  unsigned_V8HI_type_node = rs6000_vector_type ("__vector unsigned short",
+				       unsigned_intHI_type_node, 8);
+  ptr_unsigned_V8HI_type_node
+    = build_pointer_type (build_qualified_type (unsigned_V8HI_type_node,
+						TYPE_QUAL_CONST));
 
-    case VSX_BUILTIN_STXVP:
-      h.uns_p[1] = 1;
-      h.uns_p[3] = 1;
-      break;
+  unsigned_V4SI_type_node = rs6000_vector_type ("__vector unsigned int",
+				       unsigned_intSI_type_node, 4);
+  ptr_unsigned_V4SI_type_node
+    = build_pointer_type (build_qualified_type (unsigned_V4SI_type_node,
+						TYPE_QUAL_CONST));
 
-    default:
-      break;
+  unsigned_V2DI_type_node
+    = rs6000_vector_type ("__vector unsigned long long",
+			  long_long_unsigned_type_node, 2);
+
+  ptr_unsigned_V2DI_type_node
+    = build_pointer_type (build_qualified_type (unsigned_V2DI_type_node,
+						TYPE_QUAL_CONST));
+
+  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)
+    {
+      V1TI_type_node = rs6000_vector_type ("__vector __int128",
+					   intTI_type_node, 1);
+      ptr_V1TI_type_node
+	= build_pointer_type (build_qualified_type (V1TI_type_node,
+						    TYPE_QUAL_CONST));
+      unsigned_V1TI_type_node
+	= rs6000_vector_type ("__vector unsigned __int128",
+			      unsigned_intTI_type_node, 1);
+      ptr_unsigned_V1TI_type_node
+	= build_pointer_type (build_qualified_type (unsigned_V1TI_type_node,
+						    TYPE_QUAL_CONST));
     }
 
-  /* Figure out how many args are present.  */
-  while (num_args > 0 && h.mode[num_args] == VOIDmode)
-    num_args--;
+  /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
+     types, especially in C++ land.  Similarly, 'vector pixel' is distinct from
+     'vector unsigned short'.  */
+
+  bool_char_type_node = build_distinct_type_copy (unsigned_intQI_type_node);
+  bool_short_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
+  bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node);
+  bool_long_long_type_node = build_distinct_type_copy (unsigned_intDI_type_node);
+  pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
 
-  ret_type = builtin_mode_to_type[h.mode[0]][h.uns_p[0]];
-  if (!ret_type && h.uns_p[0])
-    ret_type = builtin_mode_to_type[h.mode[0]][0];
+  long_integer_type_internal_node = long_integer_type_node;
+  long_unsigned_type_internal_node = long_unsigned_type_node;
+  long_long_integer_type_internal_node = long_long_integer_type_node;
+  long_long_unsigned_type_internal_node = long_long_unsigned_type_node;
+  intQI_type_internal_node = intQI_type_node;
+  uintQI_type_internal_node = unsigned_intQI_type_node;
+  intHI_type_internal_node = intHI_type_node;
+  uintHI_type_internal_node = unsigned_intHI_type_node;
+  intSI_type_internal_node = intSI_type_node;
+  uintSI_type_internal_node = unsigned_intSI_type_node;
+  intDI_type_internal_node = intDI_type_node;
+  uintDI_type_internal_node = unsigned_intDI_type_node;
+  intTI_type_internal_node = intTI_type_node;
+  uintTI_type_internal_node = unsigned_intTI_type_node;
+  float_type_internal_node = float_type_node;
+  double_type_internal_node = double_type_node;
+  long_double_type_internal_node = long_double_type_node;
+  dfloat64_type_internal_node = dfloat64_type_node;
+  dfloat128_type_internal_node = dfloat128_type_node;
+  void_type_internal_node = void_type_node;
 
-  /* If the required decimal float type has been disabled,
-     then return NULL_TREE.  */
-  if (!ret_type && DECIMAL_FLOAT_MODE_P (h.mode[0]))
-    return NULL_TREE;
+  ptr_intQI_type_node
+    = build_pointer_type (build_qualified_type (intQI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_uintQI_type_node
+    = build_pointer_type (build_qualified_type (uintQI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_intHI_type_node
+    = build_pointer_type (build_qualified_type (intHI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_uintHI_type_node
+    = build_pointer_type (build_qualified_type (uintHI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_intSI_type_node
+    = build_pointer_type (build_qualified_type (intSI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_uintSI_type_node
+    = build_pointer_type (build_qualified_type (uintSI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_intDI_type_node
+    = build_pointer_type (build_qualified_type (intDI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_uintDI_type_node
+    = build_pointer_type (build_qualified_type (uintDI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_intTI_type_node
+    = build_pointer_type (build_qualified_type (intTI_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_uintTI_type_node
+    = build_pointer_type (build_qualified_type (uintTI_type_internal_node,
+						TYPE_QUAL_CONST));
 
-  if (!ret_type)
-    fatal_error (input_location,
-		 "internal error: builtin function %qs had an unexpected "
-		 "return type %qs", name, GET_MODE_NAME (h.mode[0]));
+  t = build_qualified_type (long_integer_type_internal_node, TYPE_QUAL_CONST);
+  ptr_long_integer_type_node = build_pointer_type (t);
 
-  for (i = 0; i < (int) ARRAY_SIZE (arg_type); i++)
-    arg_type[i] = NULL_TREE;
+  t = build_qualified_type (long_unsigned_type_internal_node, TYPE_QUAL_CONST);
+  ptr_long_unsigned_type_node = build_pointer_type (t);
 
-  for (i = 0; i < num_args; i++)
+  ptr_float_type_node
+    = build_pointer_type (build_qualified_type (float_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_double_type_node
+    = build_pointer_type (build_qualified_type (double_type_internal_node,
+						TYPE_QUAL_CONST));
+  ptr_long_double_type_node
+    = build_pointer_type (build_qualified_type (long_double_type_internal_node,
+						TYPE_QUAL_CONST));
+  if (dfloat64_type_node)
     {
-      int m = (int) h.mode[i+1];
-      int uns_p = h.uns_p[i+1];
-
-      arg_type[i] = builtin_mode_to_type[m][uns_p];
-      if (!arg_type[i] && uns_p)
-	arg_type[i] = builtin_mode_to_type[m][0];
-
-      /* If the required decimal float type has been disabled,
-	 then return NULL_TREE.  */
-      if (!arg_type[i] && DECIMAL_FLOAT_MODE_P (m))
-	return NULL_TREE;
-
-      if (!arg_type[i])
-	fatal_error (input_location,
-		     "internal error: builtin function %qs, argument %d "
-		     "had unexpected argument type %qs", name, i,
-		     GET_MODE_NAME (m));
+      t = build_qualified_type (dfloat64_type_internal_node, TYPE_QUAL_CONST);
+      ptr_dfloat64_type_node = build_pointer_type (t);
     }
+  else
+    ptr_dfloat64_type_node = NULL;
 
-  builtin_hash_struct **found = builtin_hash_table->find_slot (&h, INSERT);
-  if (*found == NULL)
+  if (dfloat128_type_node)
     {
-      h2 = ggc_alloc<builtin_hash_struct> ();
-      *h2 = h;
-      *found = h2;
-
-      h2->type = build_function_type_list (ret_type, arg_type[0], arg_type[1],
-					   arg_type[2], NULL_TREE);
+      t = build_qualified_type (dfloat128_type_internal_node, TYPE_QUAL_CONST);
+      ptr_dfloat128_type_node = build_pointer_type (t);
     }
+  else
+    ptr_dfloat128_type_node = NULL;
 
-  return (*found)->type;
-}
+  t = build_qualified_type (long_long_integer_type_internal_node,
+			    TYPE_QUAL_CONST);
+  ptr_long_long_integer_type_node  = build_pointer_type (t);
 
-static void
-rs6000_common_init_builtins (void)
-{
-  const struct builtin_description *d;
-  size_t i;
+  t = build_qualified_type (long_long_unsigned_type_internal_node,
+			    TYPE_QUAL_CONST);
+  ptr_long_long_unsigned_type_node = build_pointer_type (t);
 
-  tree opaque_ftype_opaque = NULL_TREE;
-  tree opaque_ftype_opaque_opaque = NULL_TREE;
-  tree opaque_ftype_opaque_opaque_opaque = NULL_TREE;
-  tree opaque_ftype_opaque_opaque_opaque_opaque = NULL_TREE;
-  HOST_WIDE_INT builtin_mask = rs6000_builtin_mask;
+  /* 128-bit floating point support.  KFmode is IEEE 128-bit floating point.
+     IFmode is the IBM extended 128-bit format that is a pair of doubles.
+     TFmode will be either IEEE 128-bit floating point or the IBM double-double
+     format that uses a pair of doubles, depending on the switches and
+     defaults.
 
-  /* Create Altivec and VSX builtins on machines with at least the
-     general purpose extensions (970 and newer) to allow the use of
-     the target attribute.  */
+     If we don't support for either 128-bit IBM double double or IEEE 128-bit
+     floating point, we need make sure the type is non-zero or else self-test
+     fails during bootstrap.
 
-  if (TARGET_EXTRA_BUILTINS)
-    builtin_mask |= RS6000_BTM_COMMON;
+     Always create __ibm128 as a separate type, even if the current long double
+     format is IBM extended double.
 
-  /* Add the quaternary operators.  */
-  d = bdesc_4arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_4arg); i++, d++)
+     For IEEE 128-bit floating point, always create the type __ieee128.  If the
+     user used -mfloat128, rs6000-c.c will create a define from __float128 to
+     __ieee128.  */
+  if (TARGET_FLOAT128_TYPE)
     {
-      tree type;
-      HOST_WIDE_INT mask = d->mask;
+      if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
+	ibm128_float_type_node = long_double_type_node;
+      else
+	{
+	  ibm128_float_type_node = make_node (REAL_TYPE);
+	  TYPE_PRECISION (ibm128_float_type_node) = 128;
+	  SET_TYPE_MODE (ibm128_float_type_node, IFmode);
+	  layout_type (ibm128_float_type_node);
+	}
+      t = build_qualified_type (ibm128_float_type_node, TYPE_QUAL_CONST);
+      ptr_ibm128_float_type_node = build_pointer_type (t);
+      lang_hooks.types.register_builtin_type (ibm128_float_type_node,
+					      "__ibm128");
+
+      if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
+	ieee128_float_type_node = long_double_type_node;
+      else
+	ieee128_float_type_node = float128_type_node;
+      t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
+      ptr_ieee128_float_type_node = build_pointer_type (t);
+      lang_hooks.types.register_builtin_type (ieee128_float_type_node,
+					      "__ieee128");
+    }
+
+  else
+    ieee128_float_type_node = ibm128_float_type_node = long_double_type_node;
+
+  /* Vector pair and vector quad support.  */
+  vector_pair_type_node = make_node (OPAQUE_TYPE);
+  SET_TYPE_MODE (vector_pair_type_node, OOmode);
+  TYPE_SIZE (vector_pair_type_node) = bitsize_int (GET_MODE_BITSIZE (OOmode));
+  TYPE_PRECISION (vector_pair_type_node) = GET_MODE_BITSIZE (OOmode);
+  TYPE_SIZE_UNIT (vector_pair_type_node) = size_int (GET_MODE_SIZE (OOmode));
+  SET_TYPE_ALIGN (vector_pair_type_node, 256);
+  TYPE_USER_ALIGN (vector_pair_type_node) = 0;
+  lang_hooks.types.register_builtin_type (vector_pair_type_node,
+					  "__vector_pair");
+  t = build_qualified_type (vector_pair_type_node, TYPE_QUAL_CONST);
+  ptr_vector_pair_type_node = build_pointer_type (t);
+
+  vector_quad_type_node = make_node (OPAQUE_TYPE);
+  SET_TYPE_MODE (vector_quad_type_node, XOmode);
+  TYPE_SIZE (vector_quad_type_node) = bitsize_int (GET_MODE_BITSIZE (XOmode));
+  TYPE_PRECISION (vector_quad_type_node) = GET_MODE_BITSIZE (XOmode);
+  TYPE_SIZE_UNIT (vector_quad_type_node) = size_int (GET_MODE_SIZE (XOmode));
+  SET_TYPE_ALIGN (vector_quad_type_node, 512);
+  TYPE_USER_ALIGN (vector_quad_type_node) = 0;
+  lang_hooks.types.register_builtin_type (vector_quad_type_node,
+					  "__vector_quad");
+  t = build_qualified_type (vector_quad_type_node, TYPE_QUAL_CONST);
+  ptr_vector_quad_type_node = build_pointer_type (t);
 
-      if ((mask & builtin_mask) != mask)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "rs6000_builtin, skip quaternary %s\n", d->name);
-	  continue;
-	}
+  /* Initialize the modes for builtin_function_type, mapping a machine mode to
+     tree type node.  */
+  builtin_mode_to_type[QImode][0] = integer_type_node;
+  builtin_mode_to_type[QImode][1] = unsigned_intSI_type_node;
+  builtin_mode_to_type[HImode][0] = integer_type_node;
+  builtin_mode_to_type[HImode][1] = unsigned_intSI_type_node;
+  builtin_mode_to_type[SImode][0] = intSI_type_node;
+  builtin_mode_to_type[SImode][1] = unsigned_intSI_type_node;
+  builtin_mode_to_type[DImode][0] = intDI_type_node;
+  builtin_mode_to_type[DImode][1] = unsigned_intDI_type_node;
+  builtin_mode_to_type[TImode][0] = intTI_type_node;
+  builtin_mode_to_type[TImode][1] = unsigned_intTI_type_node;
+  builtin_mode_to_type[SFmode][0] = float_type_node;
+  builtin_mode_to_type[DFmode][0] = double_type_node;
+  builtin_mode_to_type[IFmode][0] = ibm128_float_type_node;
+  builtin_mode_to_type[KFmode][0] = ieee128_float_type_node;
+  builtin_mode_to_type[TFmode][0] = long_double_type_node;
+  builtin_mode_to_type[DDmode][0] = dfloat64_type_node;
+  builtin_mode_to_type[TDmode][0] = dfloat128_type_node;
+  builtin_mode_to_type[V1TImode][0] = V1TI_type_node;
+  builtin_mode_to_type[V1TImode][1] = unsigned_V1TI_type_node;
+  builtin_mode_to_type[V2DImode][0] = V2DI_type_node;
+  builtin_mode_to_type[V2DImode][1] = unsigned_V2DI_type_node;
+  builtin_mode_to_type[V2DFmode][0] = V2DF_type_node;
+  builtin_mode_to_type[V4SImode][0] = V4SI_type_node;
+  builtin_mode_to_type[V4SImode][1] = unsigned_V4SI_type_node;
+  builtin_mode_to_type[V4SFmode][0] = V4SF_type_node;
+  builtin_mode_to_type[V8HImode][0] = V8HI_type_node;
+  builtin_mode_to_type[V8HImode][1] = unsigned_V8HI_type_node;
+  builtin_mode_to_type[V16QImode][0] = V16QI_type_node;
+  builtin_mode_to_type[V16QImode][1] = unsigned_V16QI_type_node;
+  builtin_mode_to_type[OOmode][1] = vector_pair_type_node;
+  builtin_mode_to_type[XOmode][1] = vector_quad_type_node;
 
-      if (rs6000_overloaded_builtin_p (d->code))
-	{
-	  type = opaque_ftype_opaque_opaque_opaque_opaque;
-	  if (!type)
-	    type = opaque_ftype_opaque_opaque_opaque_opaque
-	      = build_function_type_list (opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  NULL_TREE);
-	}
-      else
-	{
-	  enum insn_code icode = d->icode;
-	  if (d->name == 0)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, bdesc_4arg[%ld] no name\n",
-			 (long) i);
-	      continue;
-	    }
+  tdecl = add_builtin_type ("__bool char", bool_char_type_node);
+  TYPE_NAME (bool_char_type_node) = tdecl;
 
-	  if (icode == CODE_FOR_nothing)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr,
-			 "rs6000_builtin, skip quaternary %s (no code)\n",
-			 d->name);
-	      continue;
-	    }
+  tdecl = add_builtin_type ("__bool short", bool_short_type_node);
+  TYPE_NAME (bool_short_type_node) = tdecl;
 
-	  type =
-	    builtin_quaternary_function_type (insn_data[icode].operand[0].mode,
-					      insn_data[icode].operand[1].mode,
-					      insn_data[icode].operand[2].mode,
-					      insn_data[icode].operand[3].mode,
-					      insn_data[icode].operand[4].mode,
-					      d->code);
-	}
-      def_builtin (d->name, type, d->code);
-    }
+  tdecl = add_builtin_type ("__bool int", bool_int_type_node);
+  TYPE_NAME (bool_int_type_node) = tdecl;
 
-  /* Add the ternary operators.  */
-  d = bdesc_3arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
-    {
-      tree type;
-      HOST_WIDE_INT mask = d->mask;
+  tdecl = add_builtin_type ("__pixel", pixel_type_node);
+  TYPE_NAME (pixel_type_node) = tdecl;
 
-      if ((mask & builtin_mask) != mask)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "rs6000_builtin, skip ternary %s\n", d->name);
-	  continue;
-	}
+  bool_V16QI_type_node = rs6000_vector_type ("__vector __bool char",
+					     bool_char_type_node, 16);
+  ptr_bool_V16QI_type_node
+    = build_pointer_type (build_qualified_type (bool_V16QI_type_node,
+						TYPE_QUAL_CONST));
 
-      if (rs6000_overloaded_builtin_p (d->code))
-	{
-	  if (! (type = opaque_ftype_opaque_opaque_opaque))
-	    type = opaque_ftype_opaque_opaque_opaque
-	      = build_function_type_list (opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  NULL_TREE);
-	}
-      else
-	{
-	  enum insn_code icode = d->icode;
-	  if (d->name == 0)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, bdesc_3arg[%ld] no name\n",
-			 (long unsigned)i);
+  bool_V8HI_type_node = rs6000_vector_type ("__vector __bool short",
+					    bool_short_type_node, 8);
+  ptr_bool_V8HI_type_node
+    = build_pointer_type (build_qualified_type (bool_V8HI_type_node,
+						TYPE_QUAL_CONST));
 
-	      continue;
-	    }
+  bool_V4SI_type_node = rs6000_vector_type ("__vector __bool int",
+					    bool_int_type_node, 4);
+  ptr_bool_V4SI_type_node
+    = build_pointer_type (build_qualified_type (bool_V4SI_type_node,
+						TYPE_QUAL_CONST));
 
-	  if (icode == CODE_FOR_nothing)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, skip ternary %s (no code)\n",
-			 d->name);
+  bool_V2DI_type_node = rs6000_vector_type (TARGET_POWERPC64
+					    ? "__vector __bool long"
+					    : "__vector __bool long long",
+					    bool_long_long_type_node, 2);
+  ptr_bool_V2DI_type_node
+    = build_pointer_type (build_qualified_type (bool_V2DI_type_node,
+						TYPE_QUAL_CONST));
 
-	      continue;
-	    }
+  bool_V1TI_type_node = rs6000_vector_type ("__vector __bool __int128",
+					    intTI_type_node, 1);
+  ptr_bool_V1TI_type_node
+    = build_pointer_type (build_qualified_type (bool_V1TI_type_node,
+						TYPE_QUAL_CONST));
 
-	  type = builtin_function_type (insn_data[icode].operand[0].mode,
-					insn_data[icode].operand[1].mode,
-					insn_data[icode].operand[2].mode,
-					insn_data[icode].operand[3].mode,
-					d->code, d->name);
-	}
+  pixel_V8HI_type_node = rs6000_vector_type ("__vector __pixel",
+					     pixel_type_node, 8);
+  ptr_pixel_V8HI_type_node
+    = build_pointer_type (build_qualified_type (pixel_V8HI_type_node,
+						TYPE_QUAL_CONST));
+  pcvoid_type_node
+    = build_pointer_type (build_qualified_type (void_type_node,
+						TYPE_QUAL_CONST));
 
-      def_builtin (d->name, type, d->code);
-    }
+  /* Execute the autogenerated initialization code for builtins.  */
+  rs6000_init_generated_builtins ();
 
-  /* Add the binary operators.  */
-  d = bdesc_2arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+  if (TARGET_DEBUG_BUILTIN)
     {
-      machine_mode mode0, mode1, mode2;
-      tree type;
-      HOST_WIDE_INT mask = d->mask;
-
-      if ((mask & builtin_mask) != mask)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "rs6000_builtin, skip binary %s\n", d->name);
-	  continue;
-	}
-
-      if (rs6000_overloaded_builtin_p (d->code))
-	{
-	  const struct altivec_builtin_types *desc;
-
-	  /* Verify the builtin we are overloading has already been defined.  */
-	  type = NULL_TREE;
-	  for (desc = altivec_overloaded_builtins;
-	       desc->code != RS6000_BUILTIN_NONE; desc++)
-	    if (desc->code == d->code
-		&& rs6000_builtin_decls[(int)desc->overloaded_code])
-	      {
-		if (! (type = opaque_ftype_opaque_opaque))
-		  type = opaque_ftype_opaque_opaque
-		    = build_function_type_list (opaque_V4SI_type_node,
-						opaque_V4SI_type_node,
-						opaque_V4SI_type_node,
-						NULL_TREE);
-		break;
-	      }
-	}
-      else
+      fprintf (stderr, "\nAutogenerated built-in functions:\n\n");
+      for (int i = 1; i < (int) RS6000_BIF_MAX; i++)
 	{
-	  enum insn_code icode = d->icode;
-	  if (d->name == 0)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, bdesc_2arg[%ld] no name\n",
-			 (long unsigned)i);
-
-	      continue;
-	    }
-
-	  if (icode == CODE_FOR_nothing)
+	  bif_enable e = rs6000_builtin_info_x[i].enable;
+	  if (e == ENB_P5 && !TARGET_POPCNTB)
+	    continue;
+	  if (e == ENB_P6 && !TARGET_CMPB)
+	    continue;
+	  if (e == ENB_P6_64 && !(TARGET_CMPB && TARGET_POWERPC64))
+	    continue;
+	  if (e == ENB_ALTIVEC && !TARGET_ALTIVEC)
+	    continue;
+	  if (e == ENB_VSX && !TARGET_VSX)
+	    continue;
+	  if (e == ENB_P7 && !TARGET_POPCNTD)
+	    continue;
+	  if (e == ENB_P7_64 && !(TARGET_POPCNTD && TARGET_POWERPC64))
+	    continue;
+	  if (e == ENB_P8 && !TARGET_DIRECT_MOVE)
+	    continue;
+	  if (e == ENB_P8V && !TARGET_P8_VECTOR)
+	    continue;
+	  if (e == ENB_P9 && !TARGET_MODULO)
+	    continue;
+	  if (e == ENB_P9_64 && !(TARGET_MODULO && TARGET_POWERPC64))
+	    continue;
+	  if (e == ENB_P9V && !TARGET_P9_VECTOR)
+	    continue;
+	  if (e == ENB_IEEE128_HW && !TARGET_FLOAT128_HW)
+	    continue;
+	  if (e == ENB_DFP && !TARGET_DFP)
+	    continue;
+	  if (e == ENB_CRYPTO && !TARGET_CRYPTO)
+	    continue;
+	  if (e == ENB_HTM && !TARGET_HTM)
+	    continue;
+	  if (e == ENB_P10 && !TARGET_POWER10)
+	    continue;
+	  if (e == ENB_P10_64 && !(TARGET_POWER10 && TARGET_POWERPC64))
+	    continue;
+	  if (e == ENB_MMA && !TARGET_MMA)
+	    continue;
+	  tree fntype = rs6000_builtin_info_x[i].fntype;
+	  tree t = TREE_TYPE (fntype);
+	  fprintf (stderr, "%s %s (", rs6000_type_string (t),
+		   rs6000_builtin_info_x[i].bifname);
+	  t = TYPE_ARG_TYPES (fntype);
+	  while (t && TREE_VALUE (t) != void_type_node)
 	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, skip binary %s (no code)\n",
-			 d->name);
-
-	      continue;
+	      fprintf (stderr, "%s",
+		       rs6000_type_string (TREE_VALUE (t)));
+	      t = TREE_CHAIN (t);
+	      if (t && TREE_VALUE (t) != void_type_node)
+		fprintf (stderr, ", ");
 	    }
-
-	  mode0 = insn_data[icode].operand[0].mode;
-	  mode1 = insn_data[icode].operand[1].mode;
-	  mode2 = insn_data[icode].operand[2].mode;
-
-	  type = builtin_function_type (mode0, mode1, mode2, VOIDmode,
-					d->code, d->name);
+	  fprintf (stderr, "); %s [%4d]\n",
+		   rs6000_builtin_info_x[i].attr_string, (int) i);
 	}
+      fprintf (stderr, "\nEnd autogenerated built-in functions.\n\n\n");
+     }
 
-      def_builtin (d->name, type, d->code);
-    }
-
-  /* Add the simple unary operators.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+  if (TARGET_XCOFF)
     {
-      machine_mode mode0, mode1;
-      tree type;
-      HOST_WIDE_INT mask = d->mask;
-
-      if ((mask & builtin_mask) != mask)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "rs6000_builtin, skip unary %s\n", d->name);
-	  continue;
-	}
+      /* AIX libm provides clog as __clog.  */
+      if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
+	set_user_assembler_name (tdecl, "__clog");
 
-      if (rs6000_overloaded_builtin_p (d->code))
+      /* When long double is 64 bit, some long double builtins of libc
+	 functions (like __builtin_frexpl) must call the double version
+	 (frexp) not the long double version (frexpl) that expects a 128 bit
+	 argument.  */
+      if (! TARGET_LONG_DOUBLE_128)
 	{
-	  if (! (type = opaque_ftype_opaque))
-	    type = opaque_ftype_opaque
-	      = build_function_type_list (opaque_V4SI_type_node,
-					  opaque_V4SI_type_node,
-					  NULL_TREE);
+	  if ((tdecl = builtin_decl_explicit (BUILT_IN_FMODL)) != NULL_TREE)
+	    set_user_assembler_name (tdecl, "fmod");
+	  if ((tdecl = builtin_decl_explicit (BUILT_IN_FREXPL)) != NULL_TREE)
+	    set_user_assembler_name (tdecl, "frexp");
+	  if ((tdecl = builtin_decl_explicit (BUILT_IN_LDEXPL)) != NULL_TREE)
+	    set_user_assembler_name (tdecl, "ldexp");
+	  if ((tdecl = builtin_decl_explicit (BUILT_IN_MODFL)) != NULL_TREE)
+	    set_user_assembler_name (tdecl, "modf");
 	}
-      else
-	{
-	  enum insn_code icode = d->icode;
-	  if (d->name == 0)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, bdesc_1arg[%ld] no name\n",
-			 (long unsigned)i);
+    }
 
-	      continue;
-	    }
+  altivec_builtin_mask_for_load
+    = rs6000_builtin_decls_x[RS6000_BIF_MASK_FOR_LOAD];
 
-	  if (icode == CODE_FOR_nothing)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, skip unary %s (no code)\n",
-			 d->name);
+#ifdef SUBTARGET_INIT_BUILTINS
+  SUBTARGET_INIT_BUILTINS;
+#endif
 
-	      continue;
-	    }
+  return;
+}
 
-	  mode0 = insn_data[icode].operand[0].mode;
-	  mode1 = insn_data[icode].operand[1].mode;
+static tree
+rs6000_new_builtin_decl (unsigned code, bool /* initialize_p */)
+{
+  rs6000_gen_builtins fcode = (rs6000_gen_builtins) code;
 
-	  type = builtin_function_type (mode0, mode1, VOIDmode, VOIDmode,
-					d->code, d->name);
-	}
+  if (fcode >= RS6000_OVLD_MAX)
+    return error_mark_node;
 
-      def_builtin (d->name, type, d->code);
-    }
+  return rs6000_builtin_decls_x[code];
+}
 
-  /* Add the simple no-argument operators.  */
-  d = bdesc_0arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++)
-    {
-      machine_mode mode0;
-      tree type;
-      HOST_WIDE_INT mask = d->mask;
+/* Returns the rs6000 builtin decl for CODE.  Note that we don't check
+   the builtin mask here since there could be some #pragma/attribute
+   target functions and the rs6000_builtin_mask could be wrong when
+   this checking happens, though it will be updated properly later.  */
 
-      if ((mask & builtin_mask) != mask)
-	{
-	  if (TARGET_DEBUG_BUILTIN)
-	    fprintf (stderr, "rs6000_builtin, skip no-argument %s\n", d->name);
-	  continue;
-	}
-      if (rs6000_overloaded_builtin_p (d->code))
-	{
-	  if (!opaque_ftype_opaque)
-	    opaque_ftype_opaque
-	      = build_function_type_list (opaque_V4SI_type_node, NULL_TREE);
-	  type = opaque_ftype_opaque;
-	}
-      else
-	{
-	  enum insn_code icode = d->icode;
-	  if (d->name == 0)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr, "rs6000_builtin, bdesc_0arg[%lu] no name\n",
-			 (long unsigned) i);
-	      continue;
-	    }
-	  if (icode == CODE_FOR_nothing)
-	    {
-	      if (TARGET_DEBUG_BUILTIN)
-		fprintf (stderr,
-			 "rs6000_builtin, skip no-argument %s (no code)\n",
-			 d->name);
-	      continue;
-	    }
-	  mode0 = insn_data[icode].operand[0].mode;
-	  type = builtin_function_type (mode0, VOIDmode, VOIDmode, VOIDmode,
-					d->code, d->name);
-	}
-      def_builtin (d->name, type, d->code);
-    }
+tree
+rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  return rs6000_new_builtin_decl (code, initialize_p);
 }
 
 /* Return the internal arg pointer used for function incoming
diff --git a/gcc/config/rs6000/rs6000-gen-builtins.c b/gcc/config/rs6000/rs6000-gen-builtins.c
index 856770c1659..0034fe00111 100644
--- a/gcc/config/rs6000/rs6000-gen-builtins.c
+++ b/gcc/config/rs6000/rs6000-gen-builtins.c
@@ -2492,7 +2492,6 @@ write_header_file (void)
 
   fprintf (header_file, "#ifndef _RS6000_BUILTINS_H\n");
   fprintf (header_file, "#define _RS6000_BUILTINS_H 1\n\n");
-  fprintf (header_file, "extern int new_builtins_are_live;\n\n");
 
   write_decls ();
 
@@ -2691,68 +2690,64 @@ write_init_bif_table (void)
 		       || strstr (bifs[i].fndecl, "dd") != NULL
 		       || strstr (bifs[i].fndecl, "td") != NULL);
 
-      fprintf (init_file,
-	       "  if (new_builtins_are_live)\n");
-      fprintf (init_file, "    {\n");
-
       if (tf_found)
 	{
-	  fprintf (init_file, "      if (float128_type_node)\n");
-	  fprintf (init_file, "        {\n");
+	  fprintf (init_file, "  if (float128_type_node)\n");
+	  fprintf (init_file, "    {\n");
 	}
       else if (dfp_found)
 	{
-	  fprintf (init_file, "      if (dfloat64_type_node)\n");
-	  fprintf (init_file, "        {\n");
+	  fprintf (init_file, "  if (dfloat64_type_node)\n");
+	  fprintf (init_file, "    {\n");
 	}
 
       fprintf (init_file,
-	       "      rs6000_builtin_decls_x[(int)RS6000_BIF_%s] = t\n",
+	       "  rs6000_builtin_decls_x[(int)RS6000_BIF_%s] = t\n",
 	       bifs[i].idname);
       fprintf (init_file,
-	       "        = add_builtin_function (\"%s\",\n",
+	       "    = add_builtin_function (\"%s\",\n",
 	       bifs[i].proto.bifname);
       fprintf (init_file,
-	       "                                %s,\n",
+	       "                            %s,\n",
 	       bifs[i].fndecl);
       fprintf (init_file,
-	       "                                (int)RS6000_BIF_%s,"
+	       "                            (int)RS6000_BIF_%s,"
 	       " BUILT_IN_MD,\n",
 	       bifs[i].idname);
       fprintf (init_file,
-	       "                                NULL, NULL_TREE);\n");
+	       "                            NULL, NULL_TREE);\n");
       if (bifs[i].kind == FNK_CONST)
 	{
-	  fprintf (init_file, "      TREE_READONLY (t) = 1;\n");
-	  fprintf (init_file, "      TREE_NOTHROW (t) = 1;\n");
+	  fprintf (init_file, "  TREE_READONLY (t) = 1;\n");
+	  fprintf (init_file, "  TREE_NOTHROW (t) = 1;\n");
 	}
       else if (bifs[i].kind == FNK_PURE)
 	{
-	  fprintf (init_file, "      DECL_PURE_P (t) = 1;\n");
-	  fprintf (init_file, "      TREE_NOTHROW (t) = 1;\n");
+	  fprintf (init_file, "  DECL_PURE_P (t) = 1;\n");
+	  fprintf (init_file, "  TREE_NOTHROW (t) = 1;\n");
 	}
       else if (bifs[i].kind == FNK_FPMATH)
 	{
-	  fprintf (init_file, "      TREE_NOTHROW (t) = 1;\n");
-	  fprintf (init_file, "      if (flag_rounding_math)\n");
-	  fprintf (init_file, "        {\n");
-	  fprintf (init_file, "          DECL_PURE_P (t) = 1;\n");
-	  fprintf (init_file, "          DECL_IS_NOVOPS (t) = 1;\n");
-	  fprintf (init_file, "        }\n");
-	  fprintf (init_file, "      else\n");
-	  fprintf (init_file, "        TREE_READONLY (t) = 1;\n");
+	  fprintf (init_file, "  TREE_NOTHROW (t) = 1;\n");
+	  fprintf (init_file, "  if (flag_rounding_math)\n");
+	  fprintf (init_file, "    {\n");
+	  fprintf (init_file, "      DECL_PURE_P (t) = 1;\n");
+	  fprintf (init_file, "      DECL_IS_NOVOPS (t) = 1;\n");
+	  fprintf (init_file, "    }\n");
+	  fprintf (init_file, "  else\n");
+	  fprintf (init_file, "    TREE_READONLY (t) = 1;\n");
 	}
 
       if (tf_found || dfp_found)
 	{
-	  fprintf (init_file, "        }\n");
-	  fprintf (init_file, "      else\n");
-	  fprintf (init_file, "        {\n");
-	  fprintf (init_file, "          rs6000_builtin_decls_x"
+	  fprintf (init_file, "    }\n");
+	  fprintf (init_file, "  else\n");
+	  fprintf (init_file, "    {\n");
+	  fprintf (init_file, "      rs6000_builtin_decls_x"
 		   "[(int)RS6000_BIF_%s] = NULL_TREE;\n", bifs[i].idname);
-	  fprintf (init_file, "        }\n");
+	  fprintf (init_file, "    }\n");
 	}
-      fprintf (init_file, "    }\n\n");
+      fprintf (init_file, "\n");
     }
 }
 
@@ -2789,41 +2784,37 @@ write_init_ovld_table (void)
 			   || strstr (ovlds[i].fndecl, "dd") != NULL
 			   || strstr (ovlds[i].fndecl, "td") != NULL);
 
-	  fprintf (init_file,
-		   "  if (new_builtins_are_live)\n");
-	  fprintf (init_file, "    {\n");
-
 	  if (tf_found)
 	    {
-	      fprintf (init_file, "      if (float128_type_node)\n");
-	      fprintf (init_file, "        {\n");
+	      fprintf (init_file, "  if (float128_type_node)\n");
+	      fprintf (init_file, "    {\n");
 	    }
 	  else if (dfp_found)
 	    {
-	      fprintf (init_file, "      if (dfloat64_type_node)\n");
-	      fprintf (init_file, "        {\n");
+	      fprintf (init_file, "  if (dfloat64_type_node)\n");
+	      fprintf (init_file, "    {\n");
 	    }
 
 	  fprintf (init_file,
-		   "      rs6000_builtin_decls_x[(int)RS6000_OVLD_%s] = t\n",
+		   "  rs6000_builtin_decls_x[(int)RS6000_OVLD_%s] = t\n",
 		   stanza->stanza_id);
 	  fprintf (init_file,
-		   "        = add_builtin_function (\"%s\",\n",
+		   "    = add_builtin_function (\"%s\",\n",
 		   stanza->intern_name);
 	  fprintf (init_file,
-		   "                                %s,\n",
+		   "                            %s,\n",
 		   ovlds[i].fndecl);
 	  fprintf (init_file,
-		   "                                (int)RS6000_OVLD_%s,"
+		   "                            (int)RS6000_OVLD_%s,"
 		   " BUILT_IN_MD,\n",
 		   stanza->stanza_id);
 	  fprintf (init_file,
-		   "                                NULL, NULL_TREE);\n");
+		   "                            NULL, NULL_TREE);\n");
 
 	  if (tf_found || dfp_found)
-	    fprintf (init_file, "        }\n");
+	    fprintf (init_file, "    }\n");
 
-	  fprintf (init_file, "    }\n\n");
+	  fprintf (init_file, "\n");
 
 	  fprintf (init_file,
 		   "  rs6000_overload_info[RS6000_OVLD_%s - base]"
@@ -2854,8 +2845,6 @@ write_init_file (void)
   fprintf (init_file, "#include \"rs6000-builtins.h\"\n");
   fprintf (init_file, "\n");
 
-  fprintf (init_file, "int new_builtins_are_live = 1;\n\n");
-
   fprintf (init_file, "tree rs6000_builtin_decls_x[RS6000_OVLD_MAX];\n\n");
 
   write_bif_static_init ();
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 5e129986516..70df511ff98 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -5929,132 +5929,7 @@ static tree
 rs6000_builtin_vectorized_function (unsigned int fn, tree type_out,
 				    tree type_in)
 {
-  machine_mode in_mode, out_mode;
-  int in_n, out_n;
-
-  if (new_builtins_are_live)
-    return rs6000_new_builtin_vectorized_function (fn, type_out, type_in);
-
-  if (TARGET_DEBUG_BUILTIN)
-    fprintf (stderr, "rs6000_builtin_vectorized_function (%s, %s, %s)\n",
-	     combined_fn_name (combined_fn (fn)),
-	     GET_MODE_NAME (TYPE_MODE (type_out)),
-	     GET_MODE_NAME (TYPE_MODE (type_in)));
-
-  if (TREE_CODE (type_out) != VECTOR_TYPE
-      || TREE_CODE (type_in) != VECTOR_TYPE)
-    return NULL_TREE;
-
-  out_mode = TYPE_MODE (TREE_TYPE (type_out));
-  out_n = TYPE_VECTOR_SUBPARTS (type_out);
-  in_mode = TYPE_MODE (TREE_TYPE (type_in));
-  in_n = TYPE_VECTOR_SUBPARTS (type_in);
-
-  switch (fn)
-    {
-    CASE_CFN_COPYSIGN:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_CPSGNDP];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_CPSGNSP];
-      if (VECTOR_UNIT_ALTIVEC_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_COPYSIGN_V4SF];
-      break;
-    CASE_CFN_CEIL:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIP];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIP];
-      if (VECTOR_UNIT_ALTIVEC_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRFIP];
-      break;
-    CASE_CFN_FLOOR:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIM];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIM];
-      if (VECTOR_UNIT_ALTIVEC_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRFIM];
-      break;
-    CASE_CFN_FMA:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVMADDDP];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVMADDSP];
-      if (VECTOR_UNIT_ALTIVEC_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_VMADDFP];
-      break;
-    CASE_CFN_TRUNC:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIZ];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIZ];
-      if (VECTOR_UNIT_ALTIVEC_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRFIZ];
-      break;
-    CASE_CFN_NEARBYINT:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && flag_unsafe_math_optimizations
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRDPI];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && flag_unsafe_math_optimizations
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRSPI];
-      break;
-    CASE_CFN_RINT:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && !flag_trapping_math
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIC];
-      if (VECTOR_UNIT_VSX_P (V4SFmode)
-	  && !flag_trapping_math
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIC];
-      break;
-    default:
-      break;
-    }
-
-  /* Generate calls to libmass if appropriate.  */
-  if (rs6000_veclib_handler)
-    return rs6000_veclib_handler (combined_fn (fn), type_out, type_in);
-
-  return NULL_TREE;
+  return rs6000_new_builtin_vectorized_function (fn, type_out, type_in);
 }
 
 /* Implement TARGET_VECTORIZE_BUILTIN_MD_VECTORIZED_FUNCTION.  */
@@ -6063,113 +5938,7 @@ static tree
 rs6000_builtin_md_vectorized_function (tree fndecl, tree type_out,
 				       tree type_in)
 {
-  machine_mode in_mode, out_mode;
-  int in_n, out_n;
-
-  if (new_builtins_are_live)
-    return rs6000_new_builtin_md_vectorized_function (fndecl, type_out,
-						      type_in);
-
-  if (TARGET_DEBUG_BUILTIN)
-    fprintf (stderr, "rs6000_builtin_md_vectorized_function (%s, %s, %s)\n",
-	     IDENTIFIER_POINTER (DECL_NAME (fndecl)),
-	     GET_MODE_NAME (TYPE_MODE (type_out)),
-	     GET_MODE_NAME (TYPE_MODE (type_in)));
-
-  if (TREE_CODE (type_out) != VECTOR_TYPE
-      || TREE_CODE (type_in) != VECTOR_TYPE)
-    return NULL_TREE;
-
-  out_mode = TYPE_MODE (TREE_TYPE (type_out));
-  out_n = TYPE_VECTOR_SUBPARTS (type_out);
-  in_mode = TYPE_MODE (TREE_TYPE (type_in));
-  in_n = TYPE_VECTOR_SUBPARTS (type_in);
-
-  enum rs6000_builtins fn
-    = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
-  switch (fn)
-    {
-    case RS6000_BUILTIN_RSQRTF:
-      if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRSQRTFP];
-      break;
-    case RS6000_BUILTIN_RSQRT:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_2DF];
-      break;
-    case RS6000_BUILTIN_RECIPF:
-      if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)
-	  && out_mode == SFmode && out_n == 4
-	  && in_mode == SFmode && in_n == 4)
-	return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRECIPFP];
-      break;
-    case RS6000_BUILTIN_RECIP:
-      if (VECTOR_UNIT_VSX_P (V2DFmode)
-	  && out_mode == DFmode && out_n == 2
-	  && in_mode == DFmode && in_n == 2)
-	return rs6000_builtin_decls[VSX_BUILTIN_RECIP_V2DF];
-      break;
-    default:
-      break;
-    }
-
-  machine_mode in_vmode = TYPE_MODE (type_in);
-  machine_mode out_vmode = TYPE_MODE (type_out);
-
-  /* Power10 supported vectorized built-in functions.  */
-  if (TARGET_POWER10
-      && in_vmode == out_vmode
-      && VECTOR_UNIT_ALTIVEC_OR_VSX_P (in_vmode))
-    {
-      machine_mode exp_mode = DImode;
-      machine_mode exp_vmode = V2DImode;
-      enum rs6000_builtins bif;
-      switch (fn)
-	{
-	case MISC_BUILTIN_DIVWE:
-	case MISC_BUILTIN_DIVWEU:
-	  exp_mode = SImode;
-	  exp_vmode = V4SImode;
-	  if (fn == MISC_BUILTIN_DIVWE)
-	    bif = P10V_BUILTIN_DIVES_V4SI;
-	  else
-	    bif = P10V_BUILTIN_DIVEU_V4SI;
-	  break;
-	case MISC_BUILTIN_DIVDE:
-	case MISC_BUILTIN_DIVDEU:
-	  if (fn == MISC_BUILTIN_DIVDE)
-	    bif = P10V_BUILTIN_DIVES_V2DI;
-	  else
-	    bif = P10V_BUILTIN_DIVEU_V2DI;
-	  break;
-	case P10_BUILTIN_CFUGED:
-	  bif = P10V_BUILTIN_VCFUGED;
-	  break;
-	case P10_BUILTIN_CNTLZDM:
-	  bif = P10V_BUILTIN_VCLZDM;
-	  break;
-	case P10_BUILTIN_CNTTZDM:
-	  bif = P10V_BUILTIN_VCTZDM;
-	  break;
-	case P10_BUILTIN_PDEPD:
-	  bif = P10V_BUILTIN_VPDEPD;
-	  break;
-	case P10_BUILTIN_PEXTD:
-	  bif = P10V_BUILTIN_VPEXTD;
-	  break;
-	default:
-	  return NULL_TREE;
-	}
-
-      if (in_mode == exp_mode && in_vmode == exp_vmode)
-	return rs6000_builtin_decls[bif];
-    }
-
-  return NULL_TREE;
+  return rs6000_new_builtin_md_vectorized_function (fndecl, type_out, type_in);
 }
 \f
 /* Default CPU string for rs6000*_file_start functions.  */
@@ -22749,17 +22518,13 @@ rs6000_builtin_reciprocal (tree fndecl)
       if (!RS6000_RECIP_AUTO_RSQRTE_P (V2DFmode))
 	return NULL_TREE;
 
-      if (new_builtins_are_live)
-	return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_2DF];
-      return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_2DF];
+      return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_2DF];
 
     case RS6000_BIF_XVSQRTSP:
       if (!RS6000_RECIP_AUTO_RSQRTE_P (V4SFmode))
 	return NULL_TREE;
 
-      if (new_builtins_are_live)
-	return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_4SF];
-      return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_4SF];
+      return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_4SF];
 
     default:
       return NULL_TREE;
@@ -25381,10 +25146,7 @@ add_condition_to_bb (tree function_decl, tree version_decl,
 
   tree bool_zero = build_int_cst (bool_int_type_node, 0);
   tree cond_var = create_tmp_var (bool_int_type_node);
-  tree predicate_decl
-    = new_builtins_are_live
-	? rs6000_builtin_decls_x[(int) RS6000_BIF_CPU_SUPPORTS]
-	: rs6000_builtin_decls [(int) RS6000_BUILTIN_CPU_SUPPORTS];
+  tree predicate_decl = rs6000_builtin_decls_x[(int) RS6000_BIF_CPU_SUPPORTS];
   const char *arg_str = rs6000_clone_map[clone_isa].name;
   tree predicate_arg = build_string_literal (strlen (arg_str) + 1, arg_str);
   gimple *call_cond_stmt = gimple_build_call (predicate_decl, 1, predicate_arg);
@@ -28024,12 +27786,8 @@ rs6000_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
       return;
     }
 
-  tree mffs
-    = new_builtins_are_live ? rs6000_builtin_decls_x[RS6000_BIF_MFFS]
-			    : rs6000_builtin_decls[RS6000_BUILTIN_MFFS];
-  tree mtfsf
-    = new_builtins_are_live ? rs6000_builtin_decls_x[RS6000_BIF_MTFSF]
-			    : rs6000_builtin_decls[RS6000_BUILTIN_MTFSF];
+  tree mffs = rs6000_builtin_decls_x[RS6000_BIF_MFFS];
+  tree mtfsf = rs6000_builtin_decls_x[RS6000_BIF_MTFSF];
   tree call_mffs = build_call_expr (mffs, 0);
 
   /* Generates the equivalent of feholdexcept (&fenv_var)


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-12-14 17:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-14 17:23 [gcc r12-5965] rs6000: Remove new_builtins_are_live and dead code it was guarding William Schmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).