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:
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:
}
/* 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
/* 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
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),
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)
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);
}
/* 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) ==
{
/* 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)
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)
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);
"%<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;
+ /* Count the number of expected arguments. */
+ unsigned expected_args = 0;
+ for (tree chain = fnargs;
+ chain && !VOID_TYPE_P (TREE_VALUE (chain));
+ chain = TREE_CHAIN (chain))
+ expected_args++;
+
+ 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++)
}
/* 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. */
+ /* As an example, for vec_splats we have:
+
+; There are no actual builtins for vec_splats. There is special handling for
+; this in altivec_resolve_overloaded_builtin in rs6000-c.cc, where the call
+; is replaced by a constructor. The single overload here causes
+; __builtin_vec_splats to be registered with the front end so that can happen.
+[VEC_SPLATS, vec_splats, __builtin_vec_splats]
+ vsi __builtin_vec_splats (vsi);
+ ABS_V4SI SPLATS_FAKERY
+
+ So even though __builtin_vec_splats accepts all vector types, the
+ infrastructure cheats and just records one prototype. We end up getting
+ an error message that refers to this specific prototype even when we
+ are handling a different argument type. That is completely confusing
+ to the user, so it's best to let these cases be handled individually
+ in the resolve_vec_splats, etc., helper functions. */
+
+ if (n != expected_args
+ && !(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))
return NULL;
+ /* Some overloads require special handling. */
+ tree returned_expr = NULL;
+ resolution res = unresolved;
+
+ if (fcode == RS6000_OVLD_VEC_MUL)
+ returned_expr = resolve_vec_mul (&res, args, types, loc);
+ else if (fcode == RS6000_OVLD_VEC_CMPNE)
+ returned_expr = resolve_vec_cmpne (&res, args, types, loc);
+ else if (fcode == RS6000_OVLD_VEC_ADDE || fcode == RS6000_OVLD_VEC_SUBE)
+ returned_expr = resolve_vec_adde_sube (&res, fcode, args, types, loc);
+ else if (fcode == RS6000_OVLD_VEC_ADDEC || fcode == RS6000_OVLD_VEC_SUBEC)
+ returned_expr = resolve_vec_addec_subec (&res, fcode, args, types, loc);
+ else if (fcode == RS6000_OVLD_VEC_SPLATS || fcode == RS6000_OVLD_VEC_PROMOTE)
+ returned_expr = resolve_vec_splats (&res, fcode, arglist, nargs);
+ else if (fcode == RS6000_OVLD_VEC_EXTRACT)
+ returned_expr = resolve_vec_extract (&res, arglist, nargs, loc);
+ else if (fcode == RS6000_OVLD_VEC_INSERT)
+ returned_expr = resolve_vec_insert (&res, arglist, nargs, loc);
+ else if (fcode == RS6000_OVLD_VEC_STEP)
+ returned_expr = resolve_vec_step (&res, arglist, nargs);
+
+ 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;