Commit 2778a719 by Richard Biener Committed by Richard Biener

tree-vectorizer.h (vect_loop_vectorized_call): Declare.

2019-06-13  Richard Biener  <rguenther@suse.de>

	* tree-vectorizer.h (vect_loop_vectorized_call): Declare.
	* tree-vectorizer.c (vect_loop_vectorized_call): Export and
	also return the condition stmt.
	* tree-vect-loop-manip.c (vect_loop_versioning): Compute outermost
	loop we can version and version that, reusing the loop version
	created by if-conversion instead of versioning again.

	* gcc.dg/vect/vect-version-1.c: New testcase.
	* gcc.dg/vect/vect-version-2.c: Likewise.

From-SVN: r272239
parent fa8ba8b8
2019-06-13 Richard Biener <rguenther@suse.de>
* tree-vectorizer.h (vect_loop_vectorized_call): Declare.
* tree-vectorizer.c (vect_loop_vectorized_call): Export and
also return the condition stmt.
* tree-vect-loop-manip.c (vect_loop_versioning): Compute outermost
loop we can version and version that, reusing the loop version
created by if-conversion instead of versioning again.
2019-06-13 Aldy Hernandez <aldyh@redhat.com>
* gimple-loop-versioning.cc (prune_loop_conditions): Use
......
2019-06-13 Richard Biener <rguenther@suse.de>
* gcc.dg/vect/vect-version-1.c: New testcase.
* gcc.dg/vect/vect-version-2.c: Likewise.
2019-06-13 Paolo Carlini <paolo.carlini@oracle.com>
* g++.dg/diagnostic/variably-modified-type-1.C: New.
......
/* { dg-do compile } */
/* { dg-require-effective-target vect_double } */
/* { dg-require-effective-target vect_condition } */
void foo (double *x, double *y, int m, int n, int o, int p)
{
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < o; ++k)
for (int l = 0; l < p; ++l)
{
double tem = x[l] + y[l];
if (tem != 0.)
y[l] = x[l];
else
y[l] = 0.;
}
}
/* { dg-final { scan-tree-dump "applying loop versioning to outer loop 1" "vect" } } */
/* { dg-do compile } */
/* { dg-require-effective-target vect_double } */
/* { dg-require-effective-target vect_condition } */
void foo (double *x, double *y, int m, int n, int o, int p)
{
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k < o; ++k)
for (int l = 0; l < k; ++l)
{
double tem = x[l] + y[l];
if (tem != 0.)
y[l] = x[l];
else
y[l] = 0.;
}
}
/* { dg-final { scan-tree-dump "reusing loop version created by if conversion" "vect" } } */
......@@ -3016,7 +3016,8 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
vect_create_cond_for_niters_checks (loop_vinfo, &cond_expr);
if (cond_expr)
cond_expr = force_gimple_operand_1 (cond_expr, &cond_expr_stmt_list,
cond_expr = force_gimple_operand_1 (unshare_expr (cond_expr),
&cond_expr_stmt_list,
is_gimple_condexpr, NULL_TREE);
if (version_align)
......@@ -3060,72 +3061,101 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
is_gimple_condexpr, NULL_TREE);
gimple_seq_add_seq (&cond_expr_stmt_list, gimplify_stmt_list);
initialize_original_copy_tables ();
if (scalar_loop)
/* Compute the outermost loop cond_expr and cond_expr_stmt_list are
invariant in. */
struct loop *outermost = outermost_invariant_loop_for_expr (loop, cond_expr);
for (gimple_stmt_iterator gsi = gsi_start (cond_expr_stmt_list);
!gsi_end_p (gsi); gsi_next (&gsi))
{
edge scalar_e;
basic_block preheader, scalar_preheader;
gimple *stmt = gsi_stmt (gsi);
update_stmt (stmt);
ssa_op_iter iter;
use_operand_p use_p;
basic_block def_bb;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
if ((def_bb = gimple_bb (SSA_NAME_DEF_STMT (USE_FROM_PTR (use_p))))
&& flow_bb_inside_loop_p (outermost, def_bb))
outermost = superloop_at_depth (loop, bb_loop_depth (def_bb) + 1);
}
/* We don't want to scale SCALAR_LOOP's frequencies, we need to
scale LOOP's frequencies instead. */
nloop = loop_version (scalar_loop, cond_expr, &condition_bb,
prob, prob.invert (), prob, prob.invert (), true);
scale_loop_frequencies (loop, prob);
/* CONDITION_BB was created above SCALAR_LOOP's preheader,
while we need to move it above LOOP's preheader. */
e = loop_preheader_edge (loop);
scalar_e = loop_preheader_edge (scalar_loop);
/* The vector loop preheader might not be empty, since new
invariants could have been created while analyzing the loop. */
gcc_assert (single_pred_p (e->src));
gcc_assert (empty_block_p (scalar_e->src)
&& single_pred_p (scalar_e->src));
gcc_assert (single_pred_p (condition_bb));
preheader = e->src;
scalar_preheader = scalar_e->src;
scalar_e = find_edge (condition_bb, scalar_preheader);
e = single_pred_edge (preheader);
redirect_edge_and_branch_force (single_pred_edge (condition_bb),
scalar_preheader);
redirect_edge_and_branch_force (scalar_e, preheader);
redirect_edge_and_branch_force (e, condition_bb);
set_immediate_dominator (CDI_DOMINATORS, condition_bb,
single_pred (condition_bb));
set_immediate_dominator (CDI_DOMINATORS, scalar_preheader,
single_pred (scalar_preheader));
set_immediate_dominator (CDI_DOMINATORS, preheader,
condition_bb);
/* Search for the outermost loop we can version. Avoid versioning of
non-perfect nests but allow if-conversion versioned loops inside. */
struct loop *loop_to_version = loop;
if (flow_loop_nested_p (outermost, loop))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"trying to apply versioning to outer loop %d\n",
outermost->num);
if (outermost->num == 0)
outermost = superloop_at_depth (loop, 1);
/* And avoid applying versioning on non-perfect nests. */
while (loop_to_version != outermost
&& single_exit (loop_outer (loop_to_version))
&& (!loop_outer (loop_to_version)->inner->next
|| vect_loop_vectorized_call (loop_to_version))
&& (!loop_outer (loop_to_version)->inner->next
|| !loop_outer (loop_to_version)->inner->next->next))
loop_to_version = loop_outer (loop_to_version);
}
/* Apply versioning. If there is already a scalar version created by
if-conversion re-use that. */
gcond *cond;
if (gimple *call = vect_loop_vectorized_call (loop_to_version, &cond))
{
gcc_assert (scalar_loop);
condition_bb = gimple_bb (cond);
gimple_cond_set_condition_from_tree (cond, cond_expr);
update_stmt (cond);
if (cond_expr_stmt_list)
{
cond_exp_gsi = gsi_for_stmt (call);
gsi_insert_seq_before (&cond_exp_gsi, cond_expr_stmt_list,
GSI_SAME_STMT);
}
/* ??? if-conversion uses profile_probability::always () but
prob below is profile_probability::likely (). */
nloop = scalar_loop;
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"reusing %sloop version created by if conversion\n",
loop_to_version != loop ? "outer " : "");
}
else
nloop = loop_version (loop, cond_expr, &condition_bb,
{
if (loop_to_version != loop
&& dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"applying loop versioning to outer loop %d\n",
loop_to_version->num);
initialize_original_copy_tables ();
nloop = loop_version (loop_to_version, cond_expr, &condition_bb,
prob, prob.invert (), prob, prob.invert (), true);
gcc_assert (nloop);
nloop = get_loop_copy (loop);
if (version_niter)
/* Kill off IFN_LOOP_VECTORIZED_CALL in the copy, nobody will
reap those otherwise; they also refer to the original
loops. */
struct loop *l = loop;
while (gimple *call = vect_loop_vectorized_call (l))
{
/* The versioned loop could be infinite, we need to clear existing
niter information which is copied from the original loop. */
gcc_assert (loop_constraint_set_p (loop, LOOP_C_FINITE));
vect_free_loop_info_assumptions (nloop);
/* And set constraint LOOP_C_INFINITE for niter analyzer. */
loop_constraint_set (loop, LOOP_C_INFINITE);
call = SSA_NAME_DEF_STMT (get_current_def (gimple_call_lhs (call)));
fold_loop_internal_call (call, boolean_false_node);
l = loop_outer (l);
}
free_original_copy_tables ();
if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION
&& dump_enabled_p ())
if (cond_expr_stmt_list)
{
if (version_alias)
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
vect_location,
"loop versioned for vectorization because of "
"possible aliasing\n");
if (version_align)
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
vect_location,
"loop versioned for vectorization to enhance "
"alignment\n");
cond_exp_gsi = gsi_last_bb (condition_bb);
gsi_insert_seq_before (&cond_exp_gsi, cond_expr_stmt_list,
GSI_SAME_STMT);
}
free_original_copy_tables ();
/* Loop versioning violates an assumption we try to maintain during
vectorization - that the loop exit block has a single predecessor.
......@@ -3137,15 +3167,16 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
If loop versioning wasn't done from loop, but scalar_loop instead,
merge_bb will have already just a single successor. */
merge_bb = single_exit (loop)->dest;
if (scalar_loop == NULL || EDGE_COUNT (merge_bb->preds) >= 2)
merge_bb = single_exit (loop_to_version)->dest;
if (EDGE_COUNT (merge_bb->preds) >= 2)
{
gcc_assert (EDGE_COUNT (merge_bb->preds) >= 2);
new_exit_bb = split_edge (single_exit (loop));
new_exit_e = single_exit (loop);
new_exit_bb = split_edge (single_exit (loop_to_version));
new_exit_e = single_exit (loop_to_version);
e = EDGE_SUCC (new_exit_bb, 0);
for (gsi = gsi_start_phis (merge_bb); !gsi_end_p (gsi); gsi_next (&gsi))
for (gsi = gsi_start_phis (merge_bb); !gsi_end_p (gsi);
gsi_next (&gsi))
{
tree new_res;
orig_phi = gsi.phi ();
......@@ -3158,15 +3189,34 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
}
}
/* End loop-exit-fixes after versioning. */
update_ssa (TODO_update_ssa);
}
if (cond_expr_stmt_list)
if (version_niter)
{
cond_exp_gsi = gsi_last_bb (condition_bb);
gsi_insert_seq_before (&cond_exp_gsi, cond_expr_stmt_list,
GSI_SAME_STMT);
/* The versioned loop could be infinite, we need to clear existing
niter information which is copied from the original loop. */
gcc_assert (loop_constraint_set_p (loop, LOOP_C_FINITE));
vect_free_loop_info_assumptions (nloop);
/* And set constraint LOOP_C_INFINITE for niter analyzer. */
loop_constraint_set (loop, LOOP_C_INFINITE);
}
if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION
&& dump_enabled_p ())
{
if (version_alias)
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
vect_location,
"loop versioned for vectorization because of "
"possible aliasing\n");
if (version_align)
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
vect_location,
"loop versioned for vectorization to enhance "
"alignment\n");
}
update_ssa (TODO_update_ssa);
return nloop;
}
......@@ -727,8 +727,8 @@ vect_free_loop_info_assumptions (struct loop *loop)
/* If LOOP has been versioned during ifcvt, return the internal call
guarding it. */
static gimple *
vect_loop_vectorized_call (struct loop *loop)
gimple *
vect_loop_vectorized_call (struct loop *loop, gcond **cond)
{
basic_block bb = loop_preheader_edge (loop)->src;
gimple *g;
......@@ -744,6 +744,8 @@ vect_loop_vectorized_call (struct loop *loop)
while (1);
if (g && gimple_code (g) == GIMPLE_COND)
{
if (cond)
*cond = as_a <gcond *> (g);
gimple_stmt_iterator gsi = gsi_for_stmt (g);
gsi_prev (&gsi);
if (!gsi_end_p (gsi))
......
......@@ -1656,5 +1656,7 @@ void vect_pattern_recog (vec_info *);
/* In tree-vectorizer.c. */
unsigned vectorize_loops (void);
void vect_free_loop_info_assumptions (struct loop *);
gimple *vect_loop_vectorized_call (struct loop *, gcond **cond = NULL);
#endif /* GCC_TREE_VECTORIZER_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment