I forgot to point out that this patch is dependent on the pending patches
to remove the old builtins code.

Thanks,
Bill

On 12/9/21 12:33 PM, Bill Schmidt via Gcc-patches wrote:
> Hi!
>
> While replacing the built-in machinery, we agreed to defer some necessary
> refactoring of the overload processing.  This patch cleans it up considerably.
>
> I've put in one FIXME for an additional level of cleanup that should be done
> independently.  The various helper functions (resolve_VEC_*) can be simplified
> if we move the argument processing in altivec_resolve_overloaded_builtin
> earlier.  But this requires making nontrivial changes to those functions that
> will need careful review.  Let's do that in a later patch.
>
> Bootstrapped and tested on powerpc64le-linux-gnu with no regressions.  Is this
> okay for trunk?
>
> Thanks!
> Bill
>
>
> 2021-12-09  Bill Schmidt  <wschm...@linux.ibm.com>
>
> gcc/
>       * config/rs6000/rs6000-c.c (resolution): New enum.
>       (resolve_VEC_MUL): New function.
>       (resolve_VEC_CMPNE): Likewise.
>       (resolve_VEC_ADDE_SUBE): Likewise.
>       (resolve_VEC_ADDEC_SUBEC): Likewise.
>       (resolve_VEC_SPLATS): Likewise.
>       (resolve_VEC_EXTRACT): Likewise.
>       (resolve_VEC_INSERT): Likewise.
>       (resolve_VEC_STEP): Likewise.
>       (find_instance): Likewise.
>       (altivec_resolve_overloaded_builtin): Many cleanups:  Call factored-out
>       functions.  Move variable declarations closer to uses.  Add commentary.
>       Remove unnecessary levels of braces.  Avoid use of gotos.  Change
>       misleading variable names.  Use switches over if-else-if chains.
> ---
>  gcc/config/rs6000/rs6000-c.c | 1717 +++++++++++++++++++---------------
>  1 file changed, 945 insertions(+), 772 deletions(-)
>
> diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
> index e0ebdeed548..45f485aab44 100644
> --- a/gcc/config/rs6000/rs6000-c.c
> +++ b/gcc/config/rs6000/rs6000-c.c
> @@ -928,710 +928,939 @@ altivec_build_resolved_builtin (tree *args, int n, 
> tree fntype, tree ret_type,
>    return fold_convert (ret_type, call);
>  }
>
> -/* Implementation of the resolve_overloaded_builtin target hook, to
> -   support Altivec's overloaded builtins.  FIXME: This code needs
> -   to be brutally factored.  */
> +/* Enumeration of possible results from attempted overload resolution.
> +   This is used by special-case helper functions to tell their caller
> +   whether they succeeded and what still needs to be done.
>
> -tree
> -altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
> -                                 void *passed_arglist)
> +     unresolved = Still needs processing
> +       resolved = Resolved (but may be an error_mark_node)
> +      resolved_bad = An error that needs handling by the caller.  */
> +
> +enum resolution { unresolved, resolved, resolved_bad };
> +
> +/* Resolve an overloaded vec_mul call and return a tree expression for the
> +   resolved call if successful.  NARGS is the number of arguments to the 
> call.
> +   ARGLIST contains the arguments.  RES must be set to indicate the status of
> +   the resolution attempt.  LOC contains statement location information.  */
> +
> +static tree
> +resolve_VEC_MUL (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs,
> +              location_t loc)
>  {
> -  vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> 
> (passed_arglist);
> -  unsigned int nargs = vec_safe_length (arglist);
> -  enum rs6000_gen_builtins fcode
> -    = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
> -  tree fnargs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> -  tree types[MAX_OVLD_ARGS];
> -  tree args[MAX_OVLD_ARGS];
> +  /* 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");
> +      *res = resolved;
> +      return error_mark_node;
> +    }
>
> -  /* Return immediately if this isn't an overload.  */
> -  if (fcode <= RS6000_OVLD_NONE)
> -    return NULL_TREE;
> +  tree arg0 = (*arglist)[0];
> +  tree arg0_type = TREE_TYPE (arg0);
> +  tree arg1 = (*arglist)[1];
> +  tree arg1_type = TREE_TYPE (arg1);
>
> -  unsigned int adj_fcode = fcode - RS6000_OVLD_NONE;
> +  /* Both arguments must be vectors and the types must be compatible.  */
> +  if (TREE_CODE (arg0_type) != VECTOR_TYPE
> +      || !lang_hooks.types_compatible_p (arg0_type, arg1_type))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -  if (TARGET_DEBUG_BUILTIN)
> -    fprintf (stderr, "altivec_resolve_overloaded_builtin, code = %4d, %s\n",
> -          (int) fcode, IDENTIFIER_POINTER (DECL_NAME (fndecl)));
> +  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.  */
> +      *res = resolved;
> +      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.  */
> +     *res = resolved;
> +     tree call = rs6000_builtin_decls[RS6000_BIF_XVMULSP];
> +     return build_call_expr (call, 2, arg0, arg1);
> +      }
> +    case E_DFmode:
> +      {
> +     /* For doubles use the xvmuldp instruction directly.  */
> +     *res = resolved;
> +     tree call = rs6000_builtin_decls[RS6000_BIF_XVMULDP];
> +     return build_call_expr (call, 2, arg0, arg1);
> +      }
> +    /* Other types are errors.  */
> +    default:
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
> +}
>
> -  /* vec_lvsl and vec_lvsr are deprecated for use with LE element order.  */
> -  if (fcode == RS6000_OVLD_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 == RS6000_OVLD_VEC_LVSR && !BYTES_BIG_ENDIAN)
> -    warning (OPT_Wdeprecated,
> -          "%<vec_lvsr%> is deprecated for little endian; use "
> -          "assignment for unaligned loads and stores");
> +/* Resolve an overloaded vec_cmpne call and return a tree expression for the
> +   resolved call if successful.  NARGS is the number of arguments to the 
> call.
> +   ARGLIST contains the arguments.  RES must be set to indicate the status of
> +   the resolution attempt.  LOC contains statement location information.  */
>
> -  if (fcode == RS6000_OVLD_VEC_MUL)
> +static tree
> +resolve_VEC_CMPNE (resolution *res, vec<tree, va_gc> *arglist, unsigned 
> nargs,
> +                location_t loc)
> +{
> +  /* vec_cmpne needs to be special cased because there are no instructions
> +     for it (prior to power 9).  */
> +  if (nargs != 2)
>      {
> -      /* 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;
> -     }
> +      error ("builtin %qs only accepts 2 arguments", "vec_cmpne");
> +      *res = resolved;
> +      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 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
> +      || !lang_hooks.types_compatible_p (arg0_type, arg1_type))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -      /* 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;
> +  machine_mode arg0_elt_mode = TYPE_MODE (TREE_TYPE (arg0_type));
>
> -      switch (TYPE_MODE (TREE_TYPE (arg0_type)))
> +  /* 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
> +      || arg0_elt_mode == DImode
> +      || arg0_elt_mode == TImode
> +      || arg0_elt_mode == SFmode
> +      || arg0_elt_mode == DFmode)
> +    {
> +      switch (arg0_elt_mode)
>       {
> -       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[RS6000_BIF_XVMULSP];
> -           return build_call_expr (call, 2, arg0, arg1);
> -         }
> -       case E_DFmode:
> -         {
> -           /* For doubles use the xvmuldp instruction directly.  */
> -           tree call = rs6000_builtin_decls[RS6000_BIF_XVMULDP];
> -           return build_call_expr (call, 2, arg0, arg1);
> -         }
> +       /* 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 decl = rs6000_builtin_decls[RS6000_OVLD_VEC_CMPEQ];
> +         tree call = altivec_resolve_overloaded_builtin (loc, decl, 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);
> +         decl= rs6000_builtin_decls[RS6000_OVLD_VEC_NOR];
> +         *res = resolved;
> +         return altivec_resolve_overloaded_builtin (loc, decl, params);
> +       }
>         /* Other types are errors.  */
> -       default:
> -         goto bad;
> +     default:
> +       *res = resolved_bad;
> +       return error_mark_node;
>       }
>      }
>
> -  if (fcode == RS6000_OVLD_VEC_CMPNE)
> +  /* Otherwise this call is unresolved, and 
> altivec_resolve_overloaded_builtin
> +     will later process the Power9 alternative.  */
> +  *res = unresolved;
> +  return error_mark_node;
> +}
> +
> +/* Resolve an overloaded vec_adde or vec_sube call and return a tree
> +   expression for the resolved call if successful.  NARGS is the number of
> +   arguments to the call.  ARGLIST contains the arguments.  RES must be set
> +   to indicate the status of the resolution attempt.  LOC contains statement
> +   location information.  */
> +
> +static tree
> +resolve_VEC_ADDE_SUBE (resolution *res, rs6000_gen_builtins fcode,
> +                    vec<tree, va_gc> *arglist, unsigned nargs,
> +                    location_t loc)
> +{
> +  /* vec_adde needs to be special cased because there is no instruction
> +     for the {un}signed int version.  */
> +  if (nargs != 3)
>      {
> -      /* 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;
> -     }
> +      const char *name;
> +      name = fcode == RS6000_OVLD_VEC_ADDE ? "vec_adde" : "vec_sube";
> +      error ("builtin %qs only accepts 3 arguments", name);
> +      *res = resolved;
> +      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[RS6000_OVLD_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[RS6000_OVLD_VEC_NOR], params);
> -           }
> -           /* Other types are errors.  */
> -         default:
> -           goto bad;
> -         }
> -     }
> -      /* else, fall through and process the Power9 alternative below */
> +  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
> +      || !lang_hooks.types_compatible_p (arg0_type, arg1_type)
> +      || !lang_hooks.types_compatible_p (arg1_type, arg2_type))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
>      }
>
> -  if (fcode == RS6000_OVLD_VEC_ADDE || fcode == RS6000_OVLD_VEC_SUBE)
> +  switch (TYPE_MODE (TREE_TYPE (arg0_type)))
>      {
> -      /* vec_adde needs to be special cased because there is no instruction
> -       for the {un}signed int version.  */
> -      if (nargs != 3)
> -     {
> -       const char *name;
> -       name = fcode == RS6000_OVLD_VEC_ADDE ? "vec_adde" : "vec_sube";
> -       error ("builtin %qs only accepts 3 arguments", name);
> -       return error_mark_node;
> -     }
> +      /* 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:
> +      {
> +     vec<tree, va_gc> *params = make_tree_vector ();
> +     vec_safe_push (params, arg0);
> +     vec_safe_push (params, arg1);
>
> -      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;
> +     tree add_sub_builtin;
> +     if (fcode == RS6000_OVLD_VEC_ADDE)
> +       add_sub_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_ADD];
> +     else
> +       add_sub_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_SUB];
>
> -           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, 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);
> +     *res = resolved;
> +     return altivec_resolve_overloaded_builtin (loc, add_sub_builtin,
> +                                                params);
> +      }
> +      /* For {un}signed __int128s use the vaddeuqm/vsubeuqm instruction
> +      directly using the standard machinery.  */
> +    case E_TImode:
> +      *res = unresolved;
> +      break;
>
> -           if (fcode == RS6000_OVLD_VEC_ADDE)
> -             add_sub_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_ADD];
> -           else
> -             add_sub_builtin = rs6000_builtin_decls[RS6000_OVLD_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/vsubeuqm instruction
> -          directly.  */
> -       case E_TImode:
> -         break;
> -
> -       /* Types other than {un}signed int and {un}signed __int128
> -             are errors.  */
> -       default:
> -         goto bad;
> -     }
> +      /* Types other than {un}signed int and {un}signed __int128
> +      are errors.  */
> +    default:
> +      *res = resolved_bad;
>      }
>
> -  if (fcode == RS6000_OVLD_VEC_ADDEC || fcode == RS6000_OVLD_VEC_SUBEC)
> +  return error_mark_node;
> +}
> +
> +/* Resolve an overloaded vec_addec or vec_subec call and return a tree
> +   expression for the resolved call if successful.  NARGS is the number of
> +   arguments to the call.  ARGLIST contains the arguments.  RES must be set
> +   to indicate the status of the resolution attempt.  LOC contains statement
> +   location information.  */
> +
> +static tree
> +resolve_VEC_ADDEC_SUBEC (resolution *res, rs6000_gen_builtins fcode,
> +                      vec<tree, va_gc> *arglist, unsigned nargs,
> +                      location_t loc)
> +{
> +  /* vec_addec and vec_subec needs to be special cased because there is
> +     no instruction for the (un)signed int version.  */
> +  if (nargs != 3)
>      {
> -      /* 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;
> -       name = fcode == RS6000_OVLD_VEC_ADDEC ? "vec_addec" : "vec_subec";
> -       error ("builtin %qs only accepts 3 arguments", name);
> -       return error_mark_node;
> -     }
> +      const char *name;
> +      name = fcode == RS6000_OVLD_VEC_ADDEC ? "vec_addec" : "vec_subec";
> +      error ("builtin %qs only accepts 3 arguments", name);
> +      *res = resolved;
> +      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;
> +  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
> +      || !lang_hooks.types_compatible_p (arg0_type, arg1_type)
> +      || !lang_hooks.types_compatible_p (arg1_type, arg2_type))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -         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);
> +  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.  */
> +     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);
> +
> +     tree as_c_builtin;
> +     if (fcode == RS6000_OVLD_VEC_ADDEC)
> +       as_c_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_ADDC];
> +     else
> +       as_c_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_SUBC];
>
> -         if (fcode == RS6000_OVLD_VEC_ADDEC)
> -           as_c_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_ADDC];
> -         else
> -           as_c_builtin = rs6000_builtin_decls[RS6000_OVLD_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);
>
> -         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);
> +     tree as_builtin;
> +     if (fcode == RS6000_OVLD_VEC_ADDEC)
> +       as_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_ADD];
> +     else
> +       as_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_SUB];
>
> -         if (fcode == RS6000_OVLD_VEC_ADDEC)
> -           as_builtin = rs6000_builtin_decls[RS6000_OVLD_VEC_ADD];
> -         else
> -           as_builtin = rs6000_builtin_decls[RS6000_OVLD_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[RS6000_OVLD_VEC_OR];
> -         return altivec_resolve_overloaded_builtin (loc, or_builtin,
> -                                                    params);
> -         }
> -       /* For {un}signed __int128s use the vaddecuq/vsubbecuq
> -          instructions.  This occurs through normal processing.  */
> -       case E_TImode:
> -         break;
> -
> -       /* Types other than {un}signed int and {un}signed __int128
> -             are errors.  */
> -       default:
> -         goto bad;
> -     }
> +     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[RS6000_OVLD_VEC_OR];
> +     *res = resolved;
> +     return altivec_resolve_overloaded_builtin (loc, or_builtin, params);
> +      }
> +      /* For {un}signed __int128s use the vaddecuq/vsubbecuq
> +      instructions.  This occurs through normal processing.  */
> +    case E_TImode:
> +      *res = unresolved;
> +      break;
> +
> +      /* Types other than {un}signed int and {un}signed __int128
> +      are errors.  */
> +    default:
> +      *res = resolved_bad;
>      }
>
> -  /* For now treat vec_splats and vec_promote as the same.  */
> -  if (fcode == RS6000_OVLD_VEC_SPLATS || fcode == RS6000_OVLD_VEC_PROMOTE)
> -    {
> -      tree type, arg;
> -      int size;
> -      int i;
> -      bool unsigned_p;
> -      vec<constructor_elt, va_gc> *vec;
> -      const char *name;
> -      name = fcode == RS6000_OVLD_VEC_SPLATS ? "vec_splats" : "vec_promote";
> +  return error_mark_node;
> +}
>
> -      if (fcode == RS6000_OVLD_VEC_SPLATS && nargs != 1)
> -     {
> -       error ("builtin %qs only accepts 1 argument", name);
> -       return error_mark_node;
> -     }
> -      if (fcode == RS6000_OVLD_VEC_PROMOTE && nargs != 2)
> -     {
> -       error ("builtin %qs only accepts 2 arguments", name);
> -       return error_mark_node;
> -     }
> -      /* Ignore promote's element argument.  */
> -      if (fcode == RS6000_OVLD_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);
> +/* Resolve an overloaded vec_splats or vec_promote call and return a tree
> +   expression for the resolved call if successful.  NARGS is the number of
> +   arguments to the call.  ARGLIST contains the arguments.  RES must be set
> +   to indicate the status of the resolution attempt.  */
> +
> +static tree
> +resolve_VEC_SPLATS (resolution *res, rs6000_gen_builtins fcode,
> +                 vec<tree, va_gc> *arglist, unsigned nargs)
> +{
> +  const char *name;
> +  name = fcode == RS6000_OVLD_VEC_SPLATS ? "vec_splats" : "vec_promote";
> +
> +  if (fcode == RS6000_OVLD_VEC_SPLATS && nargs != 1)
> +    {
> +      error ("builtin %qs only accepts 1 argument", name);
> +      *res = resolved;
> +      return error_mark_node;
>      }
>
> -  /* For now use pointer tricks to do the extraction, unless we are on VSX
> -     extracting a double from a constant offset.  */
> -  if (fcode == RS6000_OVLD_VEC_EXTRACT)
> +  if (fcode == RS6000_OVLD_VEC_PROMOTE && nargs != 2)
>      {
> -      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;
> -     }
> +      error ("builtin %qs only accepts 2 arguments", name);
> +      *res = resolved;
> +      return error_mark_node;
> +    }
>
> -      arg2 = (*arglist)[1];
> -      arg1 = (*arglist)[0];
> -      arg1_type = TREE_TYPE (arg1);
> +  /* Ignore promote's element argument.  */
> +  if (fcode == RS6000_OVLD_VEC_PROMOTE
> +      && !INTEGRAL_TYPE_P (TREE_TYPE ((*arglist)[1])))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -      if (TREE_CODE (arg1_type) != VECTOR_TYPE)
> -     goto bad;
> -      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
> -     goto bad;
> +  tree arg = (*arglist)[0];
> +  tree type = TREE_TYPE (arg);
>
> -      /* See if we can optimize vec_extracts with the current VSX instruction
> -      set.  */
> -      mode = TYPE_MODE (arg1_type);
> -      if (VECTOR_MEM_VSX_P (mode))
> +  if (!SCALAR_FLOAT_TYPE_P (type) && !INTEGRAL_TYPE_P (type))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -     {
> -       tree call = NULL_TREE;
> -       int nunits = GET_MODE_NUNITS (mode);
> +  bool unsigned_p = TYPE_UNSIGNED (type);
> +  int size;
>
> -       arg2 = fold_for_warn (arg2);
> +  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:
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -       /* 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;
> +  arg = save_expr (fold_convert (TREE_TYPE (type), arg));
> +  vec<constructor_elt, va_gc> *vec;
> +  vec_alloc (vec, size);
>
> -             case E_V1TImode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V1TI];
> -               break;
> +  for (int i = 0; i < size; i++)
> +    {
> +      constructor_elt elt = {NULL_TREE, arg};
> +      vec->quick_push (elt);
> +    }
>
> -             case E_V2DFmode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DF];
> -               break;
> +  *res = resolved;
> +  return build_constructor (type, vec);
> +}
>
> -             case E_V2DImode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DI];
> -               break;
> +/* Resolve an overloaded vec_extract call and return a tree expression for
> +   the resolved call if successful.  NARGS is the number of arguments to
> +   the call.  ARGLIST contains the arguments.  RES must be set to indicate
> +   the status of the resolution attempt.  LOC contains statement location
> +   information.  */
>
> -             case E_V4SFmode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SF];
> -               break;
> +static tree
> +resolve_VEC_EXTRACT (resolution *res, vec<tree, va_gc> *arglist,
> +                  unsigned nargs, location_t loc)
> +{
> +  if (nargs != 2)
> +    {
> +      error ("builtin %qs only accepts 2 arguments", "vec_extract");
> +      *res = resolved;
> +      return error_mark_node;
> +    }
>
> -             case E_V4SImode:
> -               if (TARGET_DIRECT_MOVE_64BIT)
> -                 call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SI];
> -               break;
> +  tree arg1 = (*arglist)[0];
> +  tree arg1_type = TREE_TYPE (arg1);
> +  tree arg2 = (*arglist)[1];
>
> -             case E_V8HImode:
> -               if (TARGET_DIRECT_MOVE_64BIT)
> -                 call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V8HI];
> -               break;
> +  if (TREE_CODE (arg1_type) != VECTOR_TYPE
> +      || !INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -             case E_V16QImode:
> -               if (TARGET_DIRECT_MOVE_64BIT)
> -                 call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V16QI];
> -               break;
> -             }
> -         }
> +  /* See if we can optimize vec_extract with the current VSX instruction
> +     set.  */
> +  machine_mode mode = TYPE_MODE (arg1_type);
> +  tree arg1_inner_type;
>
> -       /* 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)
> +  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)
>           {
> -           switch (mode)
> -             {
> -             default:
> -               break;
> +         case E_V1TImode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V1TI];
> +           break;
>
> -             case E_V2DFmode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DF];
> -               break;
> +         case E_V2DFmode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DF];
> +           break;
>
> -             case E_V2DImode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DI];
> -               break;
> +         case E_V2DImode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DI];
> +           break;
>
> -             case E_V4SFmode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SF];
> -               break;
> +         case E_V4SFmode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SF];
> +           break;
>
> -             case E_V4SImode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SI];
> -               break;
> +         case E_V4SImode:
> +           if (TARGET_DIRECT_MOVE_64BIT)
> +             call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SI];
> +           break;
>
> -             case E_V8HImode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V8HI];
> -               break;
> +         case E_V8HImode:
> +           if (TARGET_DIRECT_MOVE_64BIT)
> +             call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V8HI];
> +           break;
>
> -             case E_V16QImode:
> -               call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V16QI];
> -               break;
> -             }
> +         case E_V16QImode:
> +           if (TARGET_DIRECT_MOVE_64BIT)
> +             call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V16QI];
> +           break;
> +
> +         default:
> +           break;
>           }
> +     }
>
> -       if (call)
> +      /* 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)
>           {
> -           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;
> +         case E_V2DFmode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DF];
> +           break;
> +
> +         case E_V2DImode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V2DI];
> +           break;
> +
> +         case E_V4SFmode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SF];
> +           break;
> +
> +         case E_V4SImode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V4SI];
> +           break;
> +
> +         case E_V8HImode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V8HI];
> +           break;
> +
> +         case E_V16QImode:
> +           call = rs6000_builtin_decls[RS6000_BIF_VEC_EXT_V16QI];
> +           break;
> +
> +         default:
> +           break;
>           }
>       }
>
> -      /* Build *(((arg1_inner_type*)&(vector type){arg1})+arg2). */
> -      arg1_inner_type = TREE_TYPE (arg1_type);
> -      tree subp = build_int_cst (TREE_TYPE (arg2),
> -                              TYPE_VECTOR_SUBPARTS (arg1_type) - 1);
> -      arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2, subp, 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 ())
> +      if (call)
>       {
> -       stmt = build4 (TARGET_EXPR, arg1_type, decl, arg1,
> -                      NULL_TREE, NULL_TREE);
> -       SET_EXPR_LOCATION (stmt, loc);
> +       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);
> +       *res = resolved;
> +       return result;
>       }
> -      else
> +    }
> +
> +  /* Build *(((arg1_inner_type*) & (vector type){arg1}) + arg2). */
> +  arg1_inner_type = TREE_TYPE (arg1_type);
> +  tree subp = build_int_cst (TREE_TYPE (arg2),
> +                          TYPE_VECTOR_SUBPARTS (arg1_type) - 1);
> +  arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2, subp, 0);
> +
> +  tree 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 stmt;
> +  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);
> +    }
> +
> +  tree 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 there actually is no
> +     side effect.  */
> +  if (c_dialect_cxx ())
> +    TREE_SIDE_EFFECTS (stmt) = 1;
> +
> +  *res = resolved;
> +  return stmt;
> +}
> +
> +/* Resolve an overloaded vec_insert call and return a tree expression for
> +   the resolved call if successful.  NARGS is the number of arguments to
> +   the call.  ARGLIST contains the arguments.  RES must be set to indicate
> +   the status of the resolution attempt.  LOC contains statement location
> +   information.  */
> +
> +static tree
> +resolve_VEC_INSERT (resolution *res, vec<tree, va_gc> *arglist,
> +                 unsigned nargs, location_t loc)
> +{
> +  if (nargs != 3)
> +    {
> +      error ("builtin %qs only accepts 3 arguments", "vec_insert");
> +      *res = resolved;
> +      return error_mark_node;
> +    }
> +
> +  tree arg0 = (*arglist)[0];
> +  tree arg1 = (*arglist)[1];
> +  tree arg1_type = TREE_TYPE (arg1);
> +  tree arg2 = fold_for_warn ((*arglist)[2]);
> +
> +  if (TREE_CODE (arg1_type) != VECTOR_TYPE
> +      || !INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
> +
> +  /* If we can use the VSX xxpermdi instruction, use that for insert.  */
> +  machine_mode 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);
> +      arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector);
> +
> +      tree call = NULL_TREE;
> +      if (mode == V2DFmode)
> +     call = rs6000_builtin_decls[RS6000_BIF_VEC_SET_V2DF];
> +      else if (mode == V2DImode)
> +     call = rs6000_builtin_decls[RS6000_BIF_VEC_SET_V2DI];
> +
> +      /* Note, __builtin_vec_insert_<xxx> has vector and scalar types
> +      reversed.  */
> +      if (call)
>       {
> -       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);
> +       *res = resolved;
> +       return build_call_expr (call, 3, arg1, arg0, arg2);
>       }
> +    }
>
> -      innerptrtype = build_pointer_type (arg1_inner_type);
> +  else if (mode == V1TImode
> +        && VECTOR_UNIT_VSX_P (mode)
> +        && TREE_CODE (arg2) == INTEGER_CST)
> +    {
> +      tree call = rs6000_builtin_decls[RS6000_BIF_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.  */
> +      *res = resolved;
> +      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
> +    {
> +      tree c = build_int_cst (TREE_TYPE (arg2),
> +                           TYPE_VECTOR_SUBPARTS (arg1_type) - 1);
> +      arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2, c, 0);
> +    }
> +
> +  tree 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;
> +
> +  tree stmt;
> +  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_TYPE (arg1_type);
> +      tree 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);
> +    }
>
> -      /* 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 there actually is no side
> -      effect.  */
> -      if (c_dialect_cxx ())
> -     TREE_SIDE_EFFECTS (stmt) = 1;
> +  *res = resolved;
> +  return stmt;
> +}
>
> -      return stmt;
> -    }
> +/* Resolve an overloaded vec_step call and return a tree expression for
> +   the resolved call if successful.  NARGS is the number of arguments to
> +   the call.  ARGLIST contains the arguments.  RES must be set to indicate
> +   the status of the resolution attempt.  */
>
> -  /* For now use pointer tricks to do the insertion, unless we are on VSX
> -     inserting a double to a constant offset.  */
> -  if (fcode == RS6000_OVLD_VEC_INSERT)
> +static tree
> +resolve_VEC_STEP (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs)
> +{
> +  if (nargs != 1)
>      {
> -      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;
> -     }
> +      error ("builtin %qs only accepts 1 argument", "vec_step");
> +      *res = resolved;
> +      return error_mark_node;
> +    }
>
> -      arg0 = (*arglist)[0];
> -      arg1 = (*arglist)[1];
> -      arg1_type = TREE_TYPE (arg1);
> -      arg2 = fold_for_warn ((*arglist)[2]);
> +  tree arg0 = (*arglist)[0];
> +  tree arg0_type = TREE_TYPE (arg0);
>
> -      if (TREE_CODE (arg1_type) != VECTOR_TYPE)
> -     goto bad;
> -      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2)))
> -     goto bad;
> +  if (TREE_CODE (arg0_type) != VECTOR_TYPE)
> +    {
> +      *res = resolved_bad;
> +      return error_mark_node;
> +    }
>
> -      /* 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;
> +  *res = resolved;
> +  return build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (arg0_type));
> +}
>
> -       arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector);
> -       if (mode == V2DFmode)
> -         call = rs6000_builtin_decls[RS6000_BIF_VEC_SET_V2DF];
> -       else if (mode == V2DImode)
> -         call = rs6000_builtin_decls[RS6000_BIF_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[RS6000_BIF_VEC_SET_V1TI];
> -       wide_int selector = wi::zero(32);
> +/* Look for a matching instance in a chain of instances.  INSTANCE points to
> +   the chain of instances; INSTANCE_CODE is the code identifying the specific
> +   built-in being searched for; FCODE is the overloaded function code; TYPES
> +   contains an array of two types that must match the types of the instance's
> +   parameters; and ARGS contains an array of two arguments to be passed to
> +   the instance.  If found, resolve the built-in and return it, unless the
> +   built-in is not supported in context.  In that case, set
> +   UNSUPPORTED_BUILTIN to true.  If we don't match, return error_mark_node
> +   and leave UNSUPPORTED_BUILTIN alone.  */
>
> -       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);
> -     }
> +tree
> +find_instance (bool *unsupported_builtin, ovlddata **instance,
> +            rs6000_gen_builtins instance_code,
> +            rs6000_gen_builtins fcode,
> +            tree *types, tree *args)
> +{
> +  while (*instance && (*instance)->bifid != instance_code)
> +    *instance = (*instance)->next;
>
> -      /* 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);
> -     }
> +  ovlddata *inst = *instance;
> +  gcc_assert (inst != NULL);
> +  tree fntype = rs6000_builtin_info[inst->bifid].fntype;
> +  tree parmtype0 = TREE_VALUE (TYPE_ARG_TYPES (fntype));
> +  tree parmtype1 = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
>
> -      if (TARGET_VSX)
> +  if (rs6000_builtin_type_compatible (types[0], parmtype0)
> +      && rs6000_builtin_type_compatible (types[1], parmtype1))
> +    {
> +      if (rs6000_builtin_decl (inst->bifid, false) != error_mark_node
> +       && rs6000_builtin_is_supported (inst->bifid))
>       {
> -       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);
> +       tree ret_type = TREE_TYPE (inst->fntype);
> +       return altivec_build_resolved_builtin (args, 2, fntype, ret_type,
> +                                              inst->bifid, fcode);
>       }
>        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;
> +     *unsupported_builtin = true;
> +    }
> +
> +  return error_mark_node;
> +}
> +
> +/* Implementation of the resolve_overloaded_builtin target hook, to
> +   support Altivec's overloaded builtins.  */
> +
> +tree
> +altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
> +                                 void *passed_arglist)
> +{
> +  /* Return immediately if this isn't an overload.  */
> +  rs6000_gen_builtins fcode
> +    = (rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl);
> +
> +  if (fcode <= RS6000_OVLD_NONE)
> +    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 == RS6000_OVLD_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 == RS6000_OVLD_VEC_LVSR && !BYTES_BIG_ENDIAN)
> +    warning (OPT_Wdeprecated,
> +          "%<vec_lvsr%> is deprecated for little endian; use "
> +          "assignment for unaligned loads and stores");
> +
> +  /* Some overloads require special handling.  */
> +  /* FIXME: Could we simplify the helper functions if we gathered arguments
> +     and types into arrays first?  */
> +  tree returned_expr = NULL;
> +  resolution res = unresolved;
> +  vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> 
> (passed_arglist);
> +  unsigned int nargs = vec_safe_length (arglist);
> +
> +  switch (fcode)
> +    {
> +    case RS6000_OVLD_VEC_MUL:
> +      returned_expr = resolve_VEC_MUL (&res, arglist, nargs, loc);
> +      break;
> +
> +    case RS6000_OVLD_VEC_CMPNE:
> +      returned_expr = resolve_VEC_CMPNE (&res, arglist, nargs, loc);
> +      break;
> +
> +    case RS6000_OVLD_VEC_ADDE:
> +    case RS6000_OVLD_VEC_SUBE:
> +      returned_expr = resolve_VEC_ADDE_SUBE (&res, fcode, arglist, nargs, 
> loc);
> +      break;
> +
> +    case RS6000_OVLD_VEC_ADDEC:
> +    case RS6000_OVLD_VEC_SUBEC:
> +      returned_expr = resolve_VEC_ADDEC_SUBEC (&res, fcode, arglist, nargs,
> +                                            loc);
> +      break;
> +
> +    case RS6000_OVLD_VEC_SPLATS:
> +    case RS6000_OVLD_VEC_PROMOTE:
> +      returned_expr = resolve_VEC_SPLATS (&res, fcode, arglist, nargs);
> +      break;
> +
> +    case RS6000_OVLD_VEC_EXTRACT:
> +      returned_expr = resolve_VEC_EXTRACT (&res, arglist, nargs, loc);
> +      break;
> +
> +    case RS6000_OVLD_VEC_INSERT:
> +      returned_expr = resolve_VEC_INSERT (&res, arglist, nargs, loc);
> +      break;
> +
> +    case RS6000_OVLD_VEC_STEP:
> +      returned_expr = resolve_VEC_STEP (&res, arglist, nargs);
> +      break;
> +
> +    default:
> +      ;
>      }
>
> +  if (res == resolved)
> +    return returned_expr;
> +
> +  /* "Regular" built-in functions and overloaded functions share a namespace
> +     for some arrays, like rs6000_builtin_decls.  But rs6000_overload_info
> +     only has information for the overloaded functions, so we need an
> +     adjusted index for that.  */
> +  unsigned int adj_fcode = fcode - RS6000_OVLD_NONE;
> +
> +  if (res == resolved_bad)
> +    {
> +      const char *name = rs6000_overload_info[adj_fcode].ovld_name;
> +      error ("invalid parameter combination for AltiVec intrinsic %qs", 
> name);
> +      return error_mark_node;
> +    }
> +
> +  /* Gather the arguments and their types into arrays for easier handling.  
> */
> +  tree fnargs = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> +  tree types[MAX_OVLD_ARGS];
> +  tree args[MAX_OVLD_ARGS];
>    unsigned int n;
> +
>    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;
> @@ -1640,10 +1869,10 @@ altivec_resolve_overloaded_builtin (location_t loc, 
> tree fndecl,
>       abort ();
>
>        arg = default_conversion (arg);
> +      tree type = TREE_TYPE (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),
> @@ -1672,15 +1901,13 @@ altivec_resolve_overloaded_builtin (location_t loc, 
> tree fndecl,
>
>        /* For RS6000_OVLD_VEC_LXVL, convert any const * to its non constant
>        equivalent to simplify the overload matching below.  */
> -      if (fcode == RS6000_OVLD_VEC_LXVL)
> +      if (fcode == RS6000_OVLD_VEC_LXVL
> +       && POINTER_TYPE_P (type)
> +       && TYPE_READONLY (TREE_TYPE (type)))
>       {
> -       if (POINTER_TYPE_P (type)
> -           && TYPE_READONLY (TREE_TYPE (type)))
> -         {
> -           type = build_qualified_type (TREE_TYPE (type), 0);
> -           type = build_pointer_type (type);
> -           arg = fold_convert (type, arg);
> -         }
> +       type = build_qualified_type (TREE_TYPE (type), 0);
> +       type = build_pointer_type (type);
> +       arg = fold_convert (type, arg);
>       }
>
>        args[n] = arg;
> @@ -1692,85 +1919,54 @@ altivec_resolve_overloaded_builtin (location_t loc, 
> tree fndecl,
>    if (!VOID_TYPE_P (TREE_VALUE (fnargs)) || n < nargs)
>      return NULL;
>
> -  if (fcode == RS6000_OVLD_VEC_STEP)
> -    {
> -      if (TREE_CODE (types[0]) != VECTOR_TYPE)
> -     goto bad;
> +  bool unsupported_builtin = false;
> +  rs6000_gen_builtins instance_code;
> +  bool supported = false;
> +  ovlddata *instance = rs6000_overload_info[adj_fcode].first_instance;
> +  gcc_assert (instance != NULL);
>
> -      return build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (types[0]));
> -    }
> +  /* Functions with no arguments can have only one overloaded instance.  */
> +  gcc_assert (nargs > 0 || !instance->next);
>
> -  {
> -    bool unsupported_builtin = false;
> -    enum rs6000_gen_builtins overloaded_code;
> -    bool supported = false;
> -    ovlddata *instance = rs6000_overload_info[adj_fcode].first_instance;
> -    gcc_assert (instance != NULL);
> -
> -    /* Need to special case __builtin_cmpb 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 == RS6000_OVLD_SCAL_CMPB)
> +  /* Standard overload processing involves determining whether an instance
> +     exists that is type-compatible with the overloaded function call.  In
> +     a couple of cases, we need to do some extra processing to disambiguate
> +     between multiple compatible instances.  */
> +  switch (fcode)
> +    {
> +      /* Need to special case __builtin_cmpb 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.  */
> +    case RS6000_OVLD_SCAL_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 RS6000_BIF_CMPB.  */
> -       overloaded_code = RS6000_BIF_CMPB;
> +       instance_code = RS6000_BIF_CMPB;
>       else
>         /* Assure all argument and result types are compatible with
>            the built-in function represented by RS6000_BIF_CMPB_32.  */
> -       overloaded_code = RS6000_BIF_CMPB_32;
> +       instance_code = RS6000_BIF_CMPB_32;
>
> -     while (instance && instance->bifid != overloaded_code)
> -       instance = instance->next;
> -
> -     gcc_assert (instance != NULL);
> -     tree fntype = rs6000_builtin_info[instance->bifid].fntype;
> -     tree parmtype0 = TREE_VALUE (TYPE_ARG_TYPES (fntype));
> -     tree parmtype1 = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
> -
> -     if (rs6000_builtin_type_compatible (types[0], parmtype0)
> -         && rs6000_builtin_type_compatible (types[1], parmtype1))
> -       {
> -         if (rs6000_builtin_decl (instance->bifid, false) != error_mark_node
> -             && rs6000_builtin_is_supported (instance->bifid))
> -           {
> -             tree ret_type = TREE_TYPE (instance->fntype);
> -             return altivec_build_resolved_builtin (args, n, fntype,
> -                                                    ret_type,
> -                                                    instance->bifid,
> -                                                    fcode);
> -           }
> -         else
> -           unsupported_builtin = true;
> -       }
> +     tree call = find_instance (&unsupported_builtin, &instance,
> +                                instance_code, fcode, types, args);
> +     if (call != error_mark_node)
> +       return call;
> +     break;
>        }
> -    else if (fcode == RS6000_OVLD_VEC_VSIE)
> +    case RS6000_OVLD_VEC_VSIE:
>        {
>       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)
> @@ -1779,9 +1975,9 @@ altivec_resolve_overloaded_builtin (location_t loc, 
> tree fndecl,
>              that expects __ieee128 argument.  Otherwise, expect
>              __int128 argument.  */
>           if (GET_MODE_CLASS (arg1_mode) == MODE_FLOAT)
> -           overloaded_code = RS6000_BIF_VSIEQPF;
> +           instance_code = RS6000_BIF_VSIEQPF;
>           else
> -           overloaded_code = RS6000_BIF_VSIEQP;
> +           instance_code = RS6000_BIF_VSIEQP;
>         }
>       else
>         {
> @@ -1789,109 +1985,86 @@ altivec_resolve_overloaded_builtin (location_t loc, 
> tree fndecl,
>              that expects double argument.  Otherwise, expect
>              long long int argument.  */
>           if (GET_MODE_CLASS (arg1_mode) == MODE_FLOAT)
> -           overloaded_code = RS6000_BIF_VSIEDPF;
> +           instance_code = RS6000_BIF_VSIEDPF;
>           else
> -           overloaded_code = RS6000_BIF_VSIEDP;
> +           instance_code = RS6000_BIF_VSIEDP;
>         }
>
> -     while (instance && instance->bifid != overloaded_code)
> -       instance = instance->next;
> +     tree call = find_instance (&unsupported_builtin, &instance,
> +                                instance_code, fcode, types, args);
> +     if (call != error_mark_node)
> +       return call;
> +     break;
> +      }
> +    default:
> +      /* Standard overload processing.  Look for an instance with compatible
> +      parameter types.  If it is supported in the current context, resolve
> +      the overloaded call to that instance.  */
> +      for (; instance != NULL; instance = instance->next)
> +     {
> +       bool mismatch = false;
> +       tree nextparm = TYPE_ARG_TYPES (instance->fntype);
>
> -     gcc_assert (instance != NULL);
> -     tree fntype = rs6000_builtin_info[instance->bifid].fntype;
> -     tree parmtype0 = TREE_VALUE (TYPE_ARG_TYPES (fntype));
> -     tree parmtype1 = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
> +       for (unsigned int arg_i = 0;
> +            arg_i < nargs && nextparm != NULL;
> +            arg_i++)
> +         {
> +           tree parmtype = TREE_VALUE (nextparm);
> +           if (!rs6000_builtin_type_compatible (types[arg_i], parmtype))
> +             {
> +               mismatch = true;
> +               break;
> +             }
> +           nextparm = TREE_CHAIN (nextparm);
> +         }
>
> -     if (rs6000_builtin_type_compatible (types[0], parmtype0)
> -         && rs6000_builtin_type_compatible (types[1], parmtype1))
> -       {
> -         if (rs6000_builtin_decl (instance->bifid, false) != error_mark_node
> -             && rs6000_builtin_is_supported (instance->bifid))
> -           {
> -             tree ret_type = TREE_TYPE (instance->fntype);
> -             return altivec_build_resolved_builtin (args, n, fntype,
> -                                                    ret_type,
> -                                                    instance->bifid,
> -                                                    fcode);
> -           }
> -         else
> +       if (mismatch)
> +         continue;
> +
> +       supported = rs6000_builtin_is_supported (instance->bifid);
> +       if (rs6000_builtin_decl (instance->bifid, false) != error_mark_node
> +           && supported)
> +         {
> +           tree fntype = rs6000_builtin_info[instance->bifid].fntype;
> +           tree ret_type = TREE_TYPE (instance->fntype);
> +           return altivec_build_resolved_builtin (args, nargs, fntype,
> +                                                  ret_type, instance->bifid,
> +                                                  fcode);
> +         }
> +       else
> +         {
>             unsupported_builtin = true;
> -       }
> -      }
> -    else
> -      {
> -     /* Functions with no arguments can have only one overloaded
> -        instance.  */
> -     gcc_assert (n > 0 || !instance->next);
> +           break;
> +         }
> +     }
> +    }
>
> -     for (; instance != NULL; instance = instance->next)
> -       {
> -         bool mismatch = false;
> -         tree nextparm = TYPE_ARG_TYPES (instance->fntype);
> -
> -         for (unsigned int arg_i = 0;
> -              arg_i < nargs && nextparm != NULL;
> -              arg_i++)
> -           {
> -             tree parmtype = TREE_VALUE (nextparm);
> -             if (!rs6000_builtin_type_compatible (types[arg_i], parmtype))
> -               {
> -                 mismatch = true;
> -                 break;
> -               }
> -             nextparm = TREE_CHAIN (nextparm);
> -           }
> -
> -         if (mismatch)
> -           continue;
> -
> -         supported = rs6000_builtin_is_supported (instance->bifid);
> -         if (rs6000_builtin_decl (instance->bifid, false) != error_mark_node
> -             && supported)
> -           {
> -             tree fntype = rs6000_builtin_info[instance->bifid].fntype;
> -             tree ret_type = TREE_TYPE (instance->fntype);
> -             return altivec_build_resolved_builtin (args, n, fntype,
> -                                                    ret_type,
> -                                                    instance->bifid,
> -                                                    fcode);
> -           }
> -         else
> -           {
> -             unsupported_builtin = true;
> -             break;
> -           }
> -       }
> -      }
> +  if (unsupported_builtin)
> +    {
> +      const char *name = rs6000_overload_info[adj_fcode].ovld_name;
> +      if (!supported)
> +     {
> +       /* Indicate that the instantiation of the overloaded builtin
> +          name is not available with the target flags in effect.  */
> +       rs6000_gen_builtins fcode = (rs6000_gen_builtins) instance->bifid;
> +       rs6000_invalid_builtin (fcode);
> +       /* Provide clarity of the relationship between the overload
> +          and the instantiation.  */
> +       const char *internal_name
> +         = rs6000_builtin_info[instance->bifid].bifname;
> +       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 (unsupported_builtin)
> -      {
> -     const char *name = rs6000_overload_info[adj_fcode].ovld_name;
> -     if (!supported)
> -       {
> -         /* Indicate that the instantiation of the overloaded builtin
> -            name is not available with the target flags in effect.  */
> -         rs6000_gen_builtins fcode = (rs6000_gen_builtins) instance->bifid;
> -         rs6000_invalid_builtin (fcode);
> -         /* Provide clarity of the relationship between the overload
> -            and the instantiation.  */
> -         const char *internal_name
> -           = rs6000_builtin_info[instance->bifid].bifname;
> -         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);
> +      return error_mark_node;
> +    }
>
> -     return error_mark_node;
> -      }
> -  }
> - bad:
> -  {
> -    const char *name = rs6000_overload_info[adj_fcode].ovld_name;
> -    error ("invalid parameter combination for AltiVec intrinsic %qs", name);
> -    return error_mark_node;
> -  }
> +  /* If we fall through to here, there were no compatible instances.  */
> +  const char *name = rs6000_overload_info[adj_fcode].ovld_name;
> +  error ("invalid parameter combination for AltiVec intrinsic %qs", name);
> +  return error_mark_node;
>  }

Reply via email to