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; > }