@@ -939,37 +939,25 @@ altivec_build_resolved_builtin (tree *args, int n, tree fntype, tree ret_type,
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
+ resolved call if successful. ARGS contains the arguments to the call.
+ TYPES contains their types. 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)
+resolve_vec_mul (resolution *res, tree *args, tree *types, location_t loc)
{
/* 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;
- }
-
- 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))
+ if (TREE_CODE (types[0]) != VECTOR_TYPE
+ || !lang_hooks.types_compatible_p (types[0], types[1]))
{
*res = resolved_bad;
return error_mark_node;
}
- switch (TYPE_MODE (TREE_TYPE (arg0_type)))
+ switch (TYPE_MODE (TREE_TYPE (types[0])))
{
case E_QImode:
case E_HImode:
@@ -978,21 +966,21 @@ resolve_vec_mul (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs,
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));
+ return fold_build2_loc (loc, MULT_EXPR, types[0], args[0],
+ fold_convert (types[0], args[1]));
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);
+ return build_call_expr (call, 2, args[0], args[1]);
}
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);
+ return build_call_expr (call, 2, args[0], args[1]);
}
/* Other types are errors. */
default:
@@ -1002,37 +990,25 @@ resolve_vec_mul (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs,
}
/* 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
+ resolved call if successful. ARGS contains the arguments to the call.
+ TYPES contains their types. RES must be set to indicate the status of
the resolution attempt. LOC contains statement location information. */
static tree
-resolve_vec_cmpne (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs,
- location_t loc)
+resolve_vec_cmpne (resolution *res, tree *args, tree *types, location_t loc)
{
/* 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");
- *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
- || !lang_hooks.types_compatible_p (arg0_type, arg1_type))
+ if (TREE_CODE (types[0]) != VECTOR_TYPE
+ || !lang_hooks.types_compatible_p (types[0], types[1]))
{
*res = resolved_bad;
return error_mark_node;
}
- machine_mode arg0_elt_mode = TYPE_MODE (TREE_TYPE (arg0_type));
+ machine_mode arg0_elt_mode = TYPE_MODE (TREE_TYPE (types[0]));
/* Power9 instructions provide the most efficient implementation of
ALTIVEC_BUILTIN_VEC_CMPNE if the mode is not DImode or TImode
@@ -1060,8 +1036,8 @@ resolve_vec_cmpne (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs,
/* 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);
+ vec_safe_push (params, args[0]);
+ vec_safe_push (params, args[1]);
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
@@ -1088,46 +1064,30 @@ resolve_vec_cmpne (resolution *res, vec<tree, va_gc> *arglist, unsigned nargs,
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. */
+/* Resolve an overloaded vec_adde or vec_sube call and return a tree expression
+ for the resolved call if successful. ARGS contains the arguments to the
+ call. TYPES contains their 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)
+ tree *args, tree *types, location_t loc)
{
/* 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);
- *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
- || !lang_hooks.types_compatible_p (arg0_type, arg1_type)
- || !lang_hooks.types_compatible_p (arg1_type, arg2_type))
+ if (TREE_CODE (types[0]) != VECTOR_TYPE
+ || !lang_hooks.types_compatible_p (types[0], types[1])
+ || !lang_hooks.types_compatible_p (types[1], types[2]))
{
*res = resolved_bad;
return error_mark_node;
}
- switch (TYPE_MODE (TREE_TYPE (arg0_type)))
+ switch (TYPE_MODE (TREE_TYPE (types[0])))
{
/* For {un}signed ints,
vec_adde (va, vb, carryv) == vec_add (vec_add (va, vb),
@@ -1137,8 +1097,8 @@ resolve_vec_adde_sube (resolution *res, rs6000_gen_builtins fcode,
case E_SImode:
{
vec<tree, va_gc> *params = make_tree_vector ();
- vec_safe_push (params, arg0);
- vec_safe_push (params, arg1);
+ vec_safe_push (params, args[0]);
+ vec_safe_push (params, args[1]);
tree add_sub_builtin;
if (fcode == RS6000_OVLD_VEC_ADDE)
@@ -1148,10 +1108,10 @@ resolve_vec_adde_sube (resolution *res, rs6000_gen_builtins fcode,
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);
+ tree const1 = build_int_cstu (TREE_TYPE (types[0]), 1);
+ tree ones_vector = build_vector_from_val (types[0], const1);
+ tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, types[0],
+ args[2], ones_vector);
params = make_tree_vector ();
vec_safe_push (params, call);
vec_safe_push (params, and_expr);
@@ -1175,45 +1135,29 @@ resolve_vec_adde_sube (resolution *res, rs6000_gen_builtins fcode,
}
/* 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. */
+ expression for the resolved call if successful. ARGS contains the arguments
+ to the call. TYPES contains their types. 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)
+ tree *args, tree *types, 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)
- {
- 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
- || !lang_hooks.types_compatible_p (arg0_type, arg1_type)
- || !lang_hooks.types_compatible_p (arg1_type, arg2_type))
+ if (TREE_CODE (types[0]) != VECTOR_TYPE
+ || !lang_hooks.types_compatible_p (types[0], types[1])
+ || !lang_hooks.types_compatible_p (types[1], types[2]))
{
*res = resolved_bad;
return error_mark_node;
}
- switch (TYPE_MODE (TREE_TYPE (arg0_type)))
+ switch (TYPE_MODE (TREE_TYPE (types[0])))
{
/* For {un}signed ints,
vec_addec (va, vb, carryv) ==
@@ -1224,11 +1168,11 @@ resolve_vec_addec_subec (resolution *res, rs6000_gen_builtins fcode,
{
/* 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);
+ args[0] = save_expr (args[0]);
+ args[1] = save_expr (args[1]);
vec<tree, va_gc> *params = make_tree_vector ();
- vec_safe_push (params, arg0);
- vec_safe_push (params, arg1);
+ vec_safe_push (params, args[0]);
+ vec_safe_push (params, args[1]);
tree as_c_builtin;
if (fcode == RS6000_OVLD_VEC_ADDEC)
@@ -1239,8 +1183,8 @@ resolve_vec_addec_subec (resolution *res, rs6000_gen_builtins fcode,
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);
+ vec_safe_push (params, args[0]);
+ vec_safe_push (params, args[1]);
tree as_builtin;
if (fcode == RS6000_OVLD_VEC_ADDEC)
@@ -1250,10 +1194,10 @@ resolve_vec_addec_subec (resolution *res, rs6000_gen_builtins fcode,
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);
+ tree const1 = build_int_cstu (TREE_TYPE (types[0]), 1);
+ tree ones_vector = build_vector_from_val (types[0], const1);
+ tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, types[0],
+ args[2], ones_vector);
params = make_tree_vector ();
vec_safe_push (params, call2);
vec_safe_push (params, and_expr);
@@ -1783,78 +1727,15 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
"%<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;
+ vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist);
+ unsigned int nargs = vec_safe_length (arglist);
+
for (n = 0;
!VOID_TYPE_P (TREE_VALUE (fnargs)) && n < nargs;
fnargs = TREE_CHAIN (fnargs), n++)
@@ -1915,10 +1796,79 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
}
/* If the number of arguments did not match the prototype, return NULL
- and the generic code will issue the appropriate error message. */
- if (!VOID_TYPE_P (TREE_VALUE (fnargs)) || n < nargs)
+ and the generic code will issue the appropriate error message. Skip
+ this test for functions where we don't fully describe all the possible
+ overload signatures in rs6000-overload.def (because they aren't relevant
+ to the expansion here). If we don't, we get confusing error messages. */
+ if (fcode != RS6000_OVLD_VEC_PROMOTE
+ && fcode != RS6000_OVLD_VEC_SPLATS
+ && fcode != RS6000_OVLD_VEC_EXTRACT
+ && fcode != RS6000_OVLD_VEC_INSERT
+ && fcode != RS6000_OVLD_VEC_STEP
+ && (!VOID_TYPE_P (TREE_VALUE (fnargs)) || n < nargs))
return NULL;
+ /* Some overloads require special handling. */
+ tree returned_expr = NULL;
+ resolution res = unresolved;
+
+ switch (fcode)
+ {
+ case RS6000_OVLD_VEC_MUL:
+ returned_expr = resolve_vec_mul (&res, args, types, loc);
+ break;
+
+ case RS6000_OVLD_VEC_CMPNE:
+ returned_expr = resolve_vec_cmpne (&res, args, types, loc);
+ break;
+
+ case RS6000_OVLD_VEC_ADDE:
+ case RS6000_OVLD_VEC_SUBE:
+ returned_expr = resolve_vec_adde_sube (&res, fcode, args, types, loc);
+ break;
+
+ case RS6000_OVLD_VEC_ADDEC:
+ case RS6000_OVLD_VEC_SUBEC:
+ returned_expr = resolve_vec_addec_subec (&res, fcode, args, types, 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;
+ }
+
bool unsupported_builtin = false;
rs6000_gen_builtins instance_code;
bool supported = false;