rs6000: Remove new_builtins_are_live and dead code it was guarding
authorBill Schmidt <wschmidt@linux.ibm.com>
Tue, 14 Dec 2021 17:23:32 +0000 (11:23 -0600)
committerBill Schmidt <wschmidt@linux.ibm.com>
Tue, 14 Dec 2021 17:23:32 +0000 (11:23 -0600)
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.

gcc/config/rs6000/darwin.h
gcc/config/rs6000/rs6000-c.c
gcc/config/rs6000/rs6000-call.c
gcc/config/rs6000/rs6000-gen-builtins.c
gcc/config/rs6000/rs6000.c

index 120b01f..7bc1009 100644 (file)
 #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
index 8e83d97..d44edf5 100644 (file)
@@ -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.
index 3a43a76..85aea9b 100644 (file)
@@ -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
index 856770c..0034fe0 100644 (file)
@@ -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 ();
index 5e12998..70df511 100644 (file)
@@ -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)