+2018-07-31 Richard Sandiford <richard.sandiford@arm.com>
+
+ * tree-vectorizer.h (vect_is_simple_use): Add an optional
+ stmt_vec_info * parameter before the optional gimple **.
+ * tree-vect-stmts.c (vect_is_simple_use): Likewise.
+ (process_use, vect_get_vec_def_for_operand_1): Update callers.
+ (vect_get_vec_def_for_operand, vectorizable_shift): Likewise.
+ * tree-vect-loop.c (vectorizable_reduction): Likewise.
+ (vectorizable_live_operation): Likewise.
+ * tree-vect-patterns.c (type_conversion_p): Likewise.
+ (vect_look_through_possible_promotion): Likewise.
+ (vect_recog_rotate_pattern): Likewise.
+ * tree-vect-slp.c (vect_get_and_check_slp_defs): Likewise.
+
2018-07-31 Richard Sandiford <richard.sandiford@arm.com>
* tree-vectorizer.h (stmt_vec_info): Temporarily change from
int op_type;
optab optab;
tree new_temp = NULL_TREE;
- gimple *def_stmt;
enum vect_def_type dt, cond_reduc_dt = vect_unknown_def_type;
gimple *cond_reduc_def_stmt = NULL;
enum tree_code cond_reduc_op_code = ERROR_MARK;
if (i == 0 && code == COND_EXPR)
continue;
- is_simple_use = vect_is_simple_use (ops[i], loop_vinfo,
- &dts[i], &tem, &def_stmt);
+ stmt_vec_info def_stmt_info;
+ is_simple_use = vect_is_simple_use (ops[i], loop_vinfo, &dts[i], &tem,
+ &def_stmt_info);
dt = dts[i];
gcc_assert (is_simple_use);
if (dt == vect_reduction_def)
{
- reduc_def_stmt = def_stmt;
+ reduc_def_stmt = def_stmt_info;
reduc_index = i;
continue;
}
return false;
if (dt == vect_nested_cycle)
- {
- found_nested_cycle_def = true;
- reduc_def_stmt = def_stmt;
- reduc_index = i;
- }
+ {
+ found_nested_cycle_def = true;
+ reduc_def_stmt = def_stmt_info;
+ reduc_index = i;
+ }
if (i == 1 && code == COND_EXPR)
{
cond_reduc_val = ops[i];
}
if (dt == vect_induction_def
- && def_stmt != NULL
- && is_nonwrapping_integer_induction (def_stmt, loop))
+ && def_stmt_info
+ && is_nonwrapping_integer_induction (def_stmt_info, loop))
{
cond_reduc_dt = dt;
- cond_reduc_def_stmt = def_stmt;
+ cond_reduc_def_stmt = def_stmt_info;
}
}
}
else
{
enum vect_def_type dt = STMT_VINFO_DEF_TYPE (stmt_info);
- vec_lhs = vect_get_vec_def_for_operand_1 (stmt, dt);
+ vec_lhs = vect_get_vec_def_for_operand_1 (stmt_info, dt);
gcc_checking_assert (ncopies == 1
|| !LOOP_VINFO_FULLY_MASKED_P (loop_vinfo));
enum vect_def_type dt;
stmt_vinfo = vinfo_for_stmt (use_stmt);
- if (!vect_is_simple_use (name, stmt_vinfo->vinfo, &dt, def_stmt))
+ stmt_vec_info def_stmt_info;
+ if (!vect_is_simple_use (name, stmt_vinfo->vinfo, &dt, &def_stmt_info,
+ def_stmt))
return false;
if (dt != vect_internal_def
while (TREE_CODE (op) == SSA_NAME && INTEGRAL_TYPE_P (op_type))
{
/* See whether OP is simple enough to vectorize. */
+ stmt_vec_info def_stmt_info;
gimple *def_stmt;
vect_def_type dt;
- if (!vect_is_simple_use (op, vinfo, &dt, &def_stmt))
+ if (!vect_is_simple_use (op, vinfo, &dt, &def_stmt_info, &def_stmt))
break;
/* If OP is the input of a demotion, skip over it to see whether
the cast is potentially vectorizable. */
if (!def_stmt)
break;
- if (dt == vect_internal_def)
- {
- caster = vinfo_for_stmt (def_stmt);
- /* Ignore pattern statements, since we don't link uses for them. */
- if (single_use_p
- && !STMT_VINFO_RELATED_STMT (caster)
- && !has_single_use (res))
- *single_use_p = false;
- }
- else
- caster = NULL;
+ caster = def_stmt_info;
+
+ /* Ignore pattern statements, since we don't link uses for them. */
+ if (caster
+ && single_use_p
+ && !STMT_VINFO_RELATED_STMT (caster)
+ && !has_single_use (res))
+ *single_use_p = false;
+
gassign *assign = dyn_cast <gassign *> (def_stmt);
if (!assign || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
break;
|| !TYPE_UNSIGNED (type))
return NULL;
- if (!vect_is_simple_use (oprnd1, vinfo, &dt, &def_stmt))
+ stmt_vec_info def_stmt_info;
+ if (!vect_is_simple_use (oprnd1, vinfo, &dt, &def_stmt_info, &def_stmt))
return NULL;
if (dt != vect_internal_def
gimple *stmt = stmts[stmt_num];
tree oprnd;
unsigned int i, number_of_oprnds;
- gimple *def_stmt;
enum vect_def_type dt = vect_uninitialized_def;
bool pattern = false;
slp_oprnd_info oprnd_info;
oprnd_info = (*oprnds_info)[i];
- if (!vect_is_simple_use (oprnd, vinfo, &dt, &def_stmt))
+ stmt_vec_info def_stmt_info;
+ if (!vect_is_simple_use (oprnd, vinfo, &dt, &def_stmt_info))
{
if (dump_enabled_p ())
{
return -1;
}
- /* Check if DEF_STMT is a part of a pattern in LOOP and get the def stmt
- from the pattern. Check that all the stmts of the node are in the
- pattern. */
- if (def_stmt && gimple_bb (def_stmt)
- && vect_stmt_in_region_p (vinfo, def_stmt)
- && vinfo_for_stmt (def_stmt)
- && is_pattern_stmt_p (vinfo_for_stmt (def_stmt)))
+ /* Check if DEF_STMT_INFO is a part of a pattern in LOOP and get
+ the def stmt from the pattern. Check that all the stmts of the
+ node are in the pattern. */
+ if (def_stmt_info && is_pattern_stmt_p (def_stmt_info))
{
pattern = true;
if (!first && !oprnd_info->first_pattern
return 1;
}
- dt = STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def_stmt));
+ dt = STMT_VINFO_DEF_TYPE (def_stmt_info);
if (dt == vect_unknown_def_type)
{
return -1;
}
- switch (gimple_code (def_stmt))
+ switch (gimple_code (def_stmt_info->stmt))
{
case GIMPLE_PHI:
case GIMPLE_ASSIGN:
case vect_reduction_def:
case vect_induction_def:
case vect_internal_def:
- oprnd_info->def_stmts.quick_push (def_stmt);
+ oprnd_info->def_stmts.quick_push (def_stmt_info);
break;
default:
enum vect_relevant relevant, vec<gimple *> *worklist,
bool force)
{
- struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
stmt_vec_info dstmt_vinfo;
basic_block bb, def_bb;
- gimple *def_stmt;
enum vect_def_type dt;
/* case 1: we are only interested in uses that need to be vectorized. Uses
if (!force && !exist_non_indexing_operands_for_use_p (use, stmt))
return true;
- if (!vect_is_simple_use (use, loop_vinfo, &dt, &def_stmt))
+ if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
return false;
}
- if (!def_stmt || gimple_nop_p (def_stmt))
+ if (!dstmt_vinfo)
return true;
- def_bb = gimple_bb (def_stmt);
- if (!flow_bb_inside_loop_p (loop, def_bb))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location, "def_stmt is out of loop.\n");
- return true;
- }
+ def_bb = gimple_bb (dstmt_vinfo->stmt);
- /* case 2: A reduction phi (STMT) defined by a reduction stmt (DEF_STMT).
- DEF_STMT must have already been processed, because this should be the
+ /* case 2: A reduction phi (STMT) defined by a reduction stmt (DSTMT_VINFO).
+ DSTMT_VINFO must have already been processed, because this should be the
only way that STMT, which is a reduction-phi, was put in the worklist,
- as there should be no other uses for DEF_STMT in the loop. So we just
+ as there should be no other uses for DSTMT_VINFO in the loop. So we just
check that everything is as expected, and we are done. */
- dstmt_vinfo = vinfo_for_stmt (def_stmt);
bb = gimple_bb (stmt);
if (gimple_code (stmt) == GIMPLE_PHI
&& STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_reduction_def
- && gimple_code (def_stmt) != GIMPLE_PHI
+ && gimple_code (dstmt_vinfo->stmt) != GIMPLE_PHI
&& STMT_VINFO_DEF_TYPE (dstmt_vinfo) == vect_reduction_def
&& bb->loop_father == def_bb->loop_father)
{
/* case 3a: outer-loop stmt defining an inner-loop stmt:
outer-loop-header-bb:
- d = def_stmt
+ d = dstmt_vinfo
inner-loop:
stmt # use (d)
outer-loop-tail-bb:
outer-loop-header-bb:
...
inner-loop:
- d = def_stmt
+ d = dstmt_vinfo
outer-loop-tail-bb (or outer-loop-exit-bb in double reduction):
stmt # use (d) */
else if (flow_loop_nested_p (bb->loop_father, def_bb->loop_father))
}
- vect_mark_relevant (worklist, def_stmt, relevant, false);
+ vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
return true;
}
dump_printf (MSG_NOTE, "\n");
}
- is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt, &def_stmt);
+ stmt_vec_info def_stmt_info;
+ is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt,
+ &def_stmt_info, &def_stmt);
gcc_assert (is_simple_use);
if (def_stmt && dump_enabled_p ())
{
return vect_init_vector (stmt, op, vector_type, NULL);
}
else
- return vect_get_vec_def_for_operand_1 (def_stmt, dt);
+ return vect_get_vec_def_for_operand_1 (def_stmt_info, dt);
}
return false;
op1 = gimple_assign_rhs2 (stmt);
- if (!vect_is_simple_use (op1, vinfo, &dt[1], &op1_vectype))
+ stmt_vec_info op1_def_stmt_info;
+ if (!vect_is_simple_use (op1, vinfo, &dt[1], &op1_vectype,
+ &op1_def_stmt_info))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
/* If the shift amount is computed by a pattern stmt we cannot
use the scalar amount directly thus give up and use a vector
shift. */
- if (dt[1] == vect_internal_def)
- {
- gimple *def = SSA_NAME_DEF_STMT (op1);
- if (is_pattern_stmt_p (vinfo_for_stmt (def)))
- scalar_shift_arg = false;
- }
+ if (op1_def_stmt_info && is_pattern_stmt_p (op1_def_stmt_info))
+ scalar_shift_arg = false;
}
else
{
VINFO - the vect info of the loop or basic block that is being vectorized.
OPERAND - operand in the loop or bb.
Output:
- DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME.
+ DEF_STMT_INFO_OUT (optional) - information about the defining stmt in
+ case OPERAND is an SSA_NAME that is defined in the vectorizable region
+ DEF_STMT_OUT (optional) - the defining stmt in case OPERAND is an SSA_NAME;
+ the definition could be anywhere in the function
DT - the type of definition
Returns whether a stmt with OPERAND can be vectorized.
bool
vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
- gimple **def_stmt_out)
+ stmt_vec_info *def_stmt_info_out, gimple **def_stmt_out)
{
+ if (def_stmt_info_out)
+ *def_stmt_info_out = NULL;
if (def_stmt_out)
*def_stmt_out = NULL;
*dt = vect_unknown_def_type;
*dt = vect_unknown_def_type;
break;
}
+ if (def_stmt_info_out)
+ *def_stmt_info_out = stmt_vinfo;
}
if (def_stmt_out)
*def_stmt_out = def_stmt;
bool
vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
- tree *vectype, gimple **def_stmt_out)
+ tree *vectype, stmt_vec_info *def_stmt_info_out,
+ gimple **def_stmt_out)
{
+ stmt_vec_info def_stmt_info;
gimple *def_stmt;
- if (!vect_is_simple_use (operand, vinfo, dt, &def_stmt))
+ if (!vect_is_simple_use (operand, vinfo, dt, &def_stmt_info, &def_stmt))
return false;
if (def_stmt_out)
*def_stmt_out = def_stmt;
+ if (def_stmt_info_out)
+ *def_stmt_info_out = def_stmt_info;
/* Now get a vector type if the def is internal, otherwise supply
NULL_TREE and leave it up to the caller to figure out a proper
|| *dt == vect_double_reduction_def
|| *dt == vect_nested_cycle)
{
- stmt_vec_info stmt_info = vinfo_for_stmt (def_stmt);
- *vectype = STMT_VINFO_VECTYPE (stmt_info);
+ *vectype = STMT_VINFO_VECTYPE (def_stmt_info);
gcc_assert (*vectype != NULL_TREE);
if (dump_enabled_p ())
{
extern tree get_same_sized_vectype (tree, tree);
extern bool vect_get_loop_mask_type (loop_vec_info);
extern bool vect_is_simple_use (tree, vec_info *, enum vect_def_type *,
- gimple ** = NULL);
+ stmt_vec_info * = NULL, gimple ** = NULL);
extern bool vect_is_simple_use (tree, vec_info *, enum vect_def_type *,
- tree *, gimple ** = NULL);
+ tree *, stmt_vec_info * = NULL,
+ gimple ** = NULL);
extern bool supportable_widening_operation (enum tree_code, gimple *, tree,
tree, enum tree_code *,
enum tree_code *, int *,