mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
Add helpers to test whether an optab can be implemented
The vectoriser and vector lowering passes both had tests of the form: if (op && (optab_handler (op, compute_mode) != CODE_FOR_nothing || optab_libfunc (op, compute_mode))) ...success... if (code == MULT_HIGHPART_EXPR && can_mult_highpart_p (compute_mode, TYPE_UNSIGNED (compute_type))) ...success... This patch adds helper routines for this kind of test, so that it's easier to handle other optab alternatives in a similar way. gcc/ * optabs-query.cc (can_open_code_p, can_implement_p): Declare. * optabs-query.h (can_open_code_p, can_implement_p): New functions. * optabs-tree.cc (target_supports_op_p): Use can_implement_p. * tree-vect-stmts.cc (vectorizable_operation): Likewise. * tree-vect-generic.cc (get_compute_type): Likewise. Remove code parameter. (expand_vector_scalar_condition, expand_vector_conversion) (expand_vector_operations_1): Update calls accordingly.
This commit is contained in:
parent
3ec0b7cd7c
commit
485ab50c20
@ -781,3 +781,33 @@ can_vec_extract (machine_mode mode, machine_mode extr_mode)
|
||||
/* We assume we can pun mode to vmode and imode to extr_mode. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return true if we can implement OP for mode MODE directly, without resorting
|
||||
to a libfunc. This usually means that OP will be implemented inline.
|
||||
|
||||
Note that this function cannot tell whether the target pattern chooses to
|
||||
use libfuncs internally. */
|
||||
|
||||
bool
|
||||
can_open_code_p (optab op, machine_mode mode)
|
||||
{
|
||||
if (optab_handler (op, mode) != CODE_FOR_nothing)
|
||||
return true;
|
||||
|
||||
if (op == umul_highpart_optab)
|
||||
return can_mult_highpart_p (mode, true);
|
||||
|
||||
if (op == smul_highpart_optab)
|
||||
return can_mult_highpart_p (mode, false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if we can implement OP for mode MODE in some way, either by
|
||||
open-coding it or by calling a libfunc. */
|
||||
|
||||
bool
|
||||
can_implement_p (optab op, machine_mode mode)
|
||||
{
|
||||
return can_open_code_p (op, mode) || optab_libfunc (op, mode);
|
||||
}
|
||||
|
@ -172,6 +172,8 @@ bool supports_vec_gather_load_p (machine_mode = E_VOIDmode,
|
||||
vec<int> * = nullptr);
|
||||
bool supports_vec_scatter_store_p (machine_mode = E_VOIDmode);
|
||||
bool can_vec_extract (machine_mode, machine_mode);
|
||||
bool can_open_code_p (optab, machine_mode);
|
||||
bool can_implement_p (optab, machine_mode);
|
||||
|
||||
/* Version of find_widening_optab_handler_and_mode that operates on
|
||||
specific mode types. */
|
||||
|
@ -504,8 +504,7 @@ target_supports_op_p (tree type, enum tree_code code,
|
||||
enum optab_subtype ot_subtype)
|
||||
{
|
||||
optab ot = optab_for_tree_code (code, type, ot_subtype);
|
||||
return (ot != unknown_optab
|
||||
&& optab_handler (ot, TYPE_MODE (type)) != CODE_FOR_nothing);
|
||||
return ot != unknown_optab && can_implement_p (ot, TYPE_MODE (type));
|
||||
}
|
||||
|
||||
/* Return true if the target has support for masked load/store.
|
||||
|
@ -1602,49 +1602,29 @@ ssa_uniform_vector_p (tree op)
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Return type in which CODE operation with optab OP can be
|
||||
computed. */
|
||||
/* Return the type that should be used to implement OP on type TYPE.
|
||||
This is TYPE itself if the target can do the operation directly,
|
||||
otherwise it is a scalar type or a smaller vector type. */
|
||||
|
||||
static tree
|
||||
get_compute_type (enum tree_code code, optab op, tree type)
|
||||
get_compute_type (optab op, tree type)
|
||||
{
|
||||
/* For very wide vectors, try using a smaller vector mode. */
|
||||
tree compute_type = type;
|
||||
if (op
|
||||
&& (!VECTOR_MODE_P (TYPE_MODE (type))
|
||||
|| optab_handler (op, TYPE_MODE (type)) == CODE_FOR_nothing))
|
||||
if (op)
|
||||
{
|
||||
tree vector_compute_type
|
||||
= type_for_widest_vector_mode (type, op);
|
||||
if (VECTOR_MODE_P (TYPE_MODE (type))
|
||||
&& can_implement_p (op, TYPE_MODE (type)))
|
||||
return type;
|
||||
|
||||
/* For very wide vectors, try using a smaller vector mode. */
|
||||
tree vector_compute_type = type_for_widest_vector_mode (type, op);
|
||||
if (vector_compute_type != NULL_TREE
|
||||
&& maybe_ne (TYPE_VECTOR_SUBPARTS (vector_compute_type), 1U)
|
||||
&& (optab_handler (op, TYPE_MODE (vector_compute_type))
|
||||
!= CODE_FOR_nothing))
|
||||
compute_type = vector_compute_type;
|
||||
&& can_implement_p (op, TYPE_MODE (vector_compute_type)))
|
||||
return vector_compute_type;
|
||||
}
|
||||
|
||||
/* If we are breaking a BLKmode vector into smaller pieces,
|
||||
type_for_widest_vector_mode has already looked into the optab,
|
||||
so skip these checks. */
|
||||
if (compute_type == type)
|
||||
{
|
||||
machine_mode compute_mode = TYPE_MODE (compute_type);
|
||||
if (VECTOR_MODE_P (compute_mode))
|
||||
{
|
||||
if (op
|
||||
&& (optab_handler (op, compute_mode) != CODE_FOR_nothing
|
||||
|| optab_libfunc (op, compute_mode)))
|
||||
return compute_type;
|
||||
if (code == MULT_HIGHPART_EXPR
|
||||
&& can_mult_highpart_p (compute_mode,
|
||||
TYPE_UNSIGNED (compute_type)))
|
||||
return compute_type;
|
||||
}
|
||||
/* There is no operation in hardware, so fall back to scalars. */
|
||||
compute_type = TREE_TYPE (type);
|
||||
}
|
||||
|
||||
return compute_type;
|
||||
return TREE_TYPE (type);
|
||||
}
|
||||
|
||||
static tree
|
||||
@ -1667,7 +1647,7 @@ expand_vector_scalar_condition (gimple_stmt_iterator *gsi)
|
||||
gassign *stmt = as_a <gassign *> (gsi_stmt (*gsi));
|
||||
tree lhs = gimple_assign_lhs (stmt);
|
||||
tree type = TREE_TYPE (lhs);
|
||||
tree compute_type = get_compute_type (COND_EXPR, mov_optab, type);
|
||||
tree compute_type = get_compute_type (mov_optab, type);
|
||||
machine_mode compute_mode = TYPE_MODE (compute_type);
|
||||
gcc_assert (compute_mode != BLKmode);
|
||||
tree rhs2 = gimple_assign_rhs2 (stmt);
|
||||
@ -1850,7 +1830,7 @@ expand_vector_conversion (gimple_stmt_iterator *gsi)
|
||||
}
|
||||
|
||||
if (optab1)
|
||||
compute_type = get_compute_type (code1, optab1, arg_type);
|
||||
compute_type = get_compute_type (optab1, arg_type);
|
||||
enum insn_code icode1;
|
||||
if (VECTOR_TYPE_P (compute_type)
|
||||
&& ((icode1 = optab_handler (optab1, TYPE_MODE (compute_type)))
|
||||
@ -1931,7 +1911,7 @@ expand_vector_conversion (gimple_stmt_iterator *gsi)
|
||||
}
|
||||
|
||||
if (optab1 && optab2)
|
||||
compute_type = get_compute_type (code1, optab1, arg_type);
|
||||
compute_type = get_compute_type (optab1, arg_type);
|
||||
|
||||
enum insn_code icode1, icode2;
|
||||
if (VECTOR_TYPE_P (compute_type)
|
||||
@ -2184,12 +2164,12 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
op = optab_for_tree_code (code, type, optab_scalar);
|
||||
|
||||
compute_type = get_compute_type (code, op, type);
|
||||
compute_type = get_compute_type (op, type);
|
||||
if (compute_type == type)
|
||||
return;
|
||||
/* The rtl expander will expand vector/scalar as vector/vector
|
||||
if necessary. Pick one with wider vector type. */
|
||||
tree compute_vtype = get_compute_type (code, opv, type);
|
||||
tree compute_vtype = get_compute_type (opv, type);
|
||||
if (subparts_gt (compute_vtype, compute_type))
|
||||
{
|
||||
compute_type = compute_vtype;
|
||||
@ -2200,7 +2180,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
|
||||
if (code == LROTATE_EXPR || code == RROTATE_EXPR)
|
||||
{
|
||||
if (compute_type == NULL_TREE)
|
||||
compute_type = get_compute_type (code, op, type);
|
||||
compute_type = get_compute_type (op, type);
|
||||
if (compute_type == type)
|
||||
return;
|
||||
/* Before splitting vector rotates into scalar rotates,
|
||||
@ -2213,11 +2193,11 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
|
||||
{
|
||||
optab oplv = vashl_optab, opl = ashl_optab;
|
||||
optab oprv = vlshr_optab, opr = lshr_optab, opo = ior_optab;
|
||||
tree compute_lvtype = get_compute_type (LSHIFT_EXPR, oplv, type);
|
||||
tree compute_rvtype = get_compute_type (RSHIFT_EXPR, oprv, type);
|
||||
tree compute_otype = get_compute_type (BIT_IOR_EXPR, opo, type);
|
||||
tree compute_ltype = get_compute_type (LSHIFT_EXPR, opl, type);
|
||||
tree compute_rtype = get_compute_type (RSHIFT_EXPR, opr, type);
|
||||
tree compute_lvtype = get_compute_type (oplv, type);
|
||||
tree compute_rvtype = get_compute_type (oprv, type);
|
||||
tree compute_otype = get_compute_type (opo, type);
|
||||
tree compute_ltype = get_compute_type (opl, type);
|
||||
tree compute_rtype = get_compute_type (opr, type);
|
||||
/* The rtl expander will expand vector/scalar as vector/vector
|
||||
if necessary. Pick one with wider vector type. */
|
||||
if (subparts_gt (compute_lvtype, compute_ltype))
|
||||
@ -2263,7 +2243,7 @@ expand_vector_operations_1 (gimple_stmt_iterator *gsi)
|
||||
op = optab_for_tree_code (MINUS_EXPR, type, optab_default);
|
||||
|
||||
if (compute_type == NULL_TREE)
|
||||
compute_type = get_compute_type (code, op, type);
|
||||
compute_type = get_compute_type (op, type);
|
||||
if (compute_type == type)
|
||||
return;
|
||||
|
||||
|
@ -6904,10 +6904,6 @@ vectorizable_operation (vec_info *vinfo,
|
||||
/* Supportable by target? */
|
||||
|
||||
vec_mode = TYPE_MODE (vectype);
|
||||
if (code == MULT_HIGHPART_EXPR)
|
||||
target_support_p = can_mult_highpart_p (vec_mode, TYPE_UNSIGNED (vectype));
|
||||
else
|
||||
{
|
||||
optab = optab_for_tree_code (code, vectype, optab_default);
|
||||
if (!optab)
|
||||
{
|
||||
@ -6916,9 +6912,7 @@ vectorizable_operation (vec_info *vinfo,
|
||||
"no optab.\n");
|
||||
return false;
|
||||
}
|
||||
target_support_p = (optab_handler (optab, vec_mode) != CODE_FOR_nothing
|
||||
|| optab_libfunc (optab, vec_mode));
|
||||
}
|
||||
target_support_p = can_implement_p (optab, vec_mode);
|
||||
|
||||
bool using_emulated_vectors_p = vect_emulated_vector_p (vectype);
|
||||
if (!target_support_p || using_emulated_vectors_p)
|
||||
|
Loading…
Reference in New Issue
Block a user