Commit 42cbdeac by Victor Kaplansky Committed by Victor Kaplansky

re PR tree-optimization/33319 (g++.dg/tree-ssa/pr27549.C ICE with vectorization)


        PR tree-optimization/33319
        * tree-vect-analyze.c (vect_same_range_drs): New.
        (vect_vfa_range_equal): New.
        (vect_is_duplicate_ddr): Removed.
        (vect_mark_for_runtime_alias_test): Do not perform marking when
        optimizing for size or max_param for alias checking is zero.
        Move the function before vect_analyze_data_ref_dependence.
        (vect_analyze_data_ref_dependence): Add call to
        vect_mark_for_runtime_alias_test in two cases when dependence
        is not clear.
        (vect_analyze_data_ref_dependences): Do not call to
        vect_mark_for_runtime_alias_test.
        (vect_prune_runtime_alias_test_list): New.
        (vect_analyze_loop): Add call to vect_prune_runtime_alias_test_list.
        * tree-vect-transform.c (vect_estimate_min_profitable_iters):
        Update vec_outside_cost.
        (vect_vfa_segment_size): More compact code, use TYPE_SIZE_UNIT.
        (vect_create_cond_for_alias_checks): Build the base address of data
        reference from DR_GROUP_FIRST_DR.
        (vect_loop_versioning): New.
        (vect_transform_loop): Add a call to vect_loop_versioning.
        Remove factored out code.

From-SVN: r128539
parent 2adde4ff
2007-09-17 Victor Kaplansky <victork@il.ibm.com>
PR tree-optimization/33319
* tree-vect-analyze.c (vect_same_range_drs): New.
(vect_vfa_range_equal): New.
(vect_is_duplicate_ddr): Removed.
(vect_mark_for_runtime_alias_test): Do not perform marking when
optimizing for size or max_param for alias checking is zero.
Move the function before vect_analyze_data_ref_dependence.
(vect_analyze_data_ref_dependence): Add call to
vect_mark_for_runtime_alias_test in two cases when dependence
is not clear.
(vect_analyze_data_ref_dependences): Do not call to
vect_mark_for_runtime_alias_test.
(vect_prune_runtime_alias_test_list): New.
(vect_analyze_loop): Add call to vect_prune_runtime_alias_test_list.
* tree-vect-transform.c (vect_estimate_min_profitable_iters):
Update vec_outside_cost.
(vect_vfa_segment_size): More compact code, use TYPE_SIZE_UNIT.
(vect_create_cond_for_alias_checks): Build the base address of data
reference from DR_GROUP_FIRST_DR.
(vect_loop_versioning): New.
(vect_transform_loop): Add a call to vect_loop_versioning.
Remove factored out code.
2007-09-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca> 2007-09-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR middle-end/33273 PR middle-end/33273
...@@ -1118,11 +1118,85 @@ vect_check_interleaving (struct data_reference *dra, ...@@ -1118,11 +1118,85 @@ vect_check_interleaving (struct data_reference *dra,
} }
} }
/* Check if data references pointed by DR_I and DR_J are same or
belong to same interleaving group. Return FALSE if drs are
different, otherwise return TRUE. */
static bool
vect_same_range_drs (data_reference_p dr_i, data_reference_p dr_j)
{
tree stmt_i = DR_STMT (dr_i);
tree stmt_j = DR_STMT (dr_j);
if (operand_equal_p (DR_REF (dr_i), DR_REF (dr_j), 0)
|| (DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_i))
&& DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_j))
&& (DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_i))
== DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_j)))))
return true;
else
return false;
}
/* If address ranges represented by DDR_I and DDR_J are equal,
return TRUE, otherwise return FALSE. */
static bool
vect_vfa_range_equal (ddr_p ddr_i, ddr_p ddr_j)
{
if ((vect_same_range_drs (DDR_A (ddr_i), DDR_A (ddr_j))
&& vect_same_range_drs (DDR_B (ddr_i), DDR_B (ddr_j)))
|| (vect_same_range_drs (DDR_A (ddr_i), DDR_B (ddr_j))
&& vect_same_range_drs (DDR_B (ddr_i), DDR_A (ddr_j))))
return true;
else
return false;
}
/* Insert DDR into LOOP_VINFO list of ddrs that may alias and need to be
tested at run-time. Return TRUE if DDR was successfully inserted.
Return false if versioning is not supported. */
static bool
vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
if ((unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS) == 0)
return false;
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump, "mark for run-time aliasing test between ");
print_generic_expr (vect_dump, DR_REF (DDR_A (ddr)), TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (DDR_B (ddr)), TDF_SLIM);
}
if (optimize_size)
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
fprintf (vect_dump, "versioning not supported when optimizing for size.");
return false;
}
/* FORNOW: We don't support versioning with outer-loop vectorization. */
if (loop->inner)
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
fprintf (vect_dump, "versioning not yet supported for outer-loops.");
return false;
}
VEC_safe_push (ddr_p, heap, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo), ddr);
return true;
}
/* Function vect_analyze_data_ref_dependence. /* Function vect_analyze_data_ref_dependence.
Return TRUE if there (might) exist a dependence between a memory-reference Return TRUE if there (might) exist a dependence between a memory-reference
DRA and a memory-reference DRB. */ DRA and a memory-reference DRB. When versioning for alias may check a
dependence at run-time, return FALSE. */
static bool static bool
vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
...@@ -1160,7 +1234,8 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, ...@@ -1160,7 +1234,8 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
fprintf (vect_dump, " and "); fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
} }
return true; /* Add to list of ddrs that need to be tested at run-time. */
return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
} }
if (DDR_NUM_DIST_VECTS (ddr) == 0) if (DDR_NUM_DIST_VECTS (ddr) == 0)
...@@ -1172,7 +1247,8 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, ...@@ -1172,7 +1247,8 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
fprintf (vect_dump, " and "); fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM); print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
} }
return true; /* Add to list of ddrs that need to be tested at run-time. */
return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
} }
loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr)); loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr));
...@@ -1224,10 +1300,10 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, ...@@ -1224,10 +1300,10 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
continue; continue;
} }
if (vect_print_dump_info (REPORT_DR_DETAILS)) if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
{ {
fprintf (vect_dump, fprintf (vect_dump,
"versioning for alias required: possible dependence " "not vectorized, possible dependence "
"between data-refs "); "between data-refs ");
print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM); print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
fprintf (vect_dump, " and "); fprintf (vect_dump, " and ");
...@@ -1240,88 +1316,6 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, ...@@ -1240,88 +1316,6 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
return false; return false;
} }
/* Return TRUE if DDR_NEW is already found in MAY_ALIAS_DDRS list. */
static bool
vect_is_duplicate_ddr (VEC (ddr_p, heap) * may_alias_ddrs, ddr_p ddr_new)
{
unsigned i;
ddr_p ddr;
for (i = 0; VEC_iterate (ddr_p, may_alias_ddrs, i, ddr); i++)
{
tree dref_A_i, dref_B_i, dref_A_j, dref_B_j;
dref_A_i = DR_REF (DDR_A (ddr));
dref_B_i = DR_REF (DDR_B (ddr));
dref_A_j = DR_REF (DDR_A (ddr_new));
dref_B_j = DR_REF (DDR_B (ddr_new));
if ((operand_equal_p (dref_A_i, dref_A_j, 0)
&& operand_equal_p (dref_B_i, dref_B_j, 0))
|| (operand_equal_p (dref_A_i, dref_B_j, 0)
&& operand_equal_p (dref_B_i, dref_A_j, 0)))
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump, "found same pair of data references ");
print_generic_expr (vect_dump, dref_A_i, TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, dref_B_i, TDF_SLIM);
}
return true;
}
}
return false;
}
/* Save DDR in LOOP_VINFO list of ddrs that may alias and need to be
tested at run-time. Returns false if number of run-time checks
inserted by vectorizer is greater than maximum defined by
PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS. */
static bool
vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump, "mark for run-time aliasing test between ");
print_generic_expr (vect_dump, DR_REF (DDR_A (ddr)), TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (DDR_B (ddr)), TDF_SLIM);
}
/* FORNOW: We don't support versioning with outer-loop vectorization. */
if (loop->inner)
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
fprintf (vect_dump, "versioning not yet supported for outer-loops.");
return false;
}
/* Do not add to the list duplicate ddrs. */
if (vect_is_duplicate_ddr (LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo), ddr))
return true;
if (VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo))
>= (unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump,
"disable versioning for alias - max number of generated "
"checks exceeded.");
}
VEC_truncate (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo), 0);
return false;
}
VEC_safe_push (ddr_p, heap, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo), ddr);
return true;
}
/* Function vect_analyze_data_ref_dependences. /* Function vect_analyze_data_ref_dependences.
Examine all the data references in the loop, and make sure there do not Examine all the data references in the loop, and make sure there do not
...@@ -1339,11 +1333,7 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo) ...@@ -1339,11 +1333,7 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo)
for (i = 0; VEC_iterate (ddr_p, ddrs, i, ddr); i++) for (i = 0; VEC_iterate (ddr_p, ddrs, i, ddr); i++)
if (vect_analyze_data_ref_dependence (ddr, loop_vinfo)) if (vect_analyze_data_ref_dependence (ddr, loop_vinfo))
{
/* Add to list of ddrs that need to be tested at run-time. */
if (!vect_mark_for_runtime_alias_test (ddr, loop_vinfo))
return false; return false;
}
return true; return true;
} }
...@@ -2381,6 +2371,77 @@ vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo) ...@@ -2381,6 +2371,77 @@ vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo)
return true; return true;
} }
/* Function vect_prune_runtime_alias_test_list.
Prune a list of ddrs to be tested at run-time by versioning for alias.
Return FALSE if resulting list of ddrs is longer then allowed by
PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE. */
static bool
vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
{
VEC (ddr_p, heap) * ddrs =
LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
unsigned i, j;
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_prune_runtime_alias_test_list ===");
for (i = 0; i < VEC_length (ddr_p, ddrs); )
{
bool found;
ddr_p ddr_i;
ddr_i = VEC_index (ddr_p, ddrs, i);
found = false;
for (j = 0; j < i; j++)
{
ddr_p ddr_j = VEC_index (ddr_p, ddrs, j);
if (vect_vfa_range_equal (ddr_i, ddr_j))
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump, "found equal ranges ");
print_generic_expr (vect_dump, DR_REF (DDR_A (ddr_i)), TDF_SLIM);
fprintf (vect_dump, ", ");
print_generic_expr (vect_dump, DR_REF (DDR_B (ddr_i)), TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (DDR_A (ddr_j)), TDF_SLIM);
fprintf (vect_dump, ", ");
print_generic_expr (vect_dump, DR_REF (DDR_B (ddr_j)), TDF_SLIM);
}
found = true;
break;
}
}
if (found)
{
VEC_ordered_remove (ddr_p, ddrs, i);
continue;
}
i++;
}
if (VEC_length (ddr_p, ddrs) >
(unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
{
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump,
"disable versioning for alias - max number of generated "
"checks exceeded.");
}
VEC_truncate (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo), 0);
return false;
}
return true;
}
/* Recursively free the memory allocated for the SLP tree rooted at NODE. */ /* Recursively free the memory allocated for the SLP tree rooted at NODE. */
...@@ -4231,6 +4292,19 @@ vect_analyze_loop (struct loop *loop) ...@@ -4231,6 +4292,19 @@ vect_analyze_loop (struct loop *loop)
return NULL; return NULL;
} }
/* Prune the list of ddrs to be tested at run-time by versioning for alias.
It is important to call pruning after vect_analyze_data_ref_accesses,
since we use grouping information gathered by interleaving analysis. */
ok = vect_prune_runtime_alias_test_list (loop_vinfo);
if (!ok)
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "too long list of versioning for alias "
"run-time tests.");
destroy_loop_vec_info (loop_vinfo, true);
return NULL;
}
/* Check the SLP opportunities in the loop, analyze and build SLP trees. */ /* Check the SLP opportunities in the loop, analyze and build SLP trees. */
ok = vect_analyze_slp (loop_vinfo); ok = vect_analyze_slp (loop_vinfo);
if (ok) if (ok)
......
...@@ -137,15 +137,32 @@ vect_estimate_min_profitable_iters (loop_vec_info loop_vinfo) ...@@ -137,15 +137,32 @@ vect_estimate_min_profitable_iters (loop_vec_info loop_vinfo)
return 0; return 0;
} }
/* Requires loop versioning tests to handle misalignment. /* Requires loop versioning tests to handle misalignment. */
FIXME: Make cost depend on number of stmts in may_misalign list. */
if (VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo))) if (VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)))
{ {
vec_outside_cost += TARG_COND_TAKEN_BRANCH_COST; /* FIXME: Make cost depend on complexity of individual check. */
vec_outside_cost +=
VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo));
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "cost model: Adding cost of checks for loop "
"versioning to treat misalignment.\n");
}
if (VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)))
{
/* FIXME: Make cost depend on complexity of individual check. */
vec_outside_cost +=
VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo));
if (vect_print_dump_info (REPORT_DETAILS)) if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "cost model: Adding cost of checks for loop " fprintf (vect_dump, "cost model: Adding cost of checks for loop "
"versioning.\n"); "versioning aliasing.\n");
}
if (VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo))
|| VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)))
{
vec_outside_cost += TARG_COND_TAKEN_BRANCH_COST;
} }
/* Count statements in scalar loop. Using this as scalar cost for a single /* Count statements in scalar loop. Using this as scalar cost for a single
...@@ -6864,31 +6881,18 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo, ...@@ -6864,31 +6881,18 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
static tree static tree
vect_vfa_segment_size (struct data_reference *dr, tree vect_factor) vect_vfa_segment_size (struct data_reference *dr, tree vect_factor)
{ {
tree segment_length; tree segment_length = fold_build2 (MULT_EXPR, integer_type_node,
DR_STEP (dr), vect_factor);
if (vect_supportable_dr_alignment (dr) == dr_explicit_realign_optimized) if (vect_supportable_dr_alignment (dr) == dr_explicit_realign_optimized)
{ {
tree vector_size = tree vector_size = TYPE_SIZE_UNIT
build_int_cst (integer_type_node, (STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr))));
GET_MODE_SIZE (TYPE_MODE (STMT_VINFO_VECTYPE
(vinfo_for_stmt (DR_STMT (dr))))));
segment_length = segment_length = fold_build2 (PLUS_EXPR, integer_type_node,
fold_convert (sizetype, segment_length, vector_size);
fold_build2 (PLUS_EXPR, integer_type_node,
fold_build2 (MULT_EXPR, integer_type_node, DR_STEP (dr),
vect_factor),
vector_size));
} }
else return fold_convert (sizetype, segment_length);
{
segment_length =
fold_convert (sizetype,
fold_build2 (MULT_EXPR, integer_type_node, DR_STEP (dr),
vect_factor));
}
return segment_length;
} }
/* Function vect_create_cond_for_alias_checks. /* Function vect_create_cond_for_alias_checks.
...@@ -6907,6 +6911,8 @@ vect_vfa_segment_size (struct data_reference *dr, tree vect_factor) ...@@ -6907,6 +6911,8 @@ vect_vfa_segment_size (struct data_reference *dr, tree vect_factor)
COND_EXPR - conditional expression. COND_EXPR - conditional expression.
COND_EXPR_STMT_LIST - statements needed to construct the conditional COND_EXPR_STMT_LIST - statements needed to construct the conditional
expression. expression.
The returned value is the conditional expression to be used in the if The returned value is the conditional expression to be used in the if
statement that controls which version of the loop gets executed at runtime. statement that controls which version of the loop gets executed at runtime.
*/ */
...@@ -6940,26 +6946,47 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, ...@@ -6940,26 +6946,47 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
for (i = 0; VEC_iterate (ddr_p, may_alias_ddrs, i, ddr); i++) for (i = 0; VEC_iterate (ddr_p, may_alias_ddrs, i, ddr); i++)
{ {
tree stmt_a = DR_STMT (DDR_A (ddr)); struct data_reference *dr_a, *dr_b;
tree stmt_b = DR_STMT (DDR_B (ddr)); tree dr_group_first_a, dr_group_first_b;
tree addr_base_a, addr_base_b;
tree segment_length_a, segment_length_b;
tree stmt_a, stmt_b;
tree addr_base_a = dr_a = DDR_A (ddr);
stmt_a = DR_STMT (DDR_A (ddr));
dr_group_first_a = DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_a));
if (dr_group_first_a)
{
stmt_a = dr_group_first_a;
dr_a = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt_a));
}
dr_b = DDR_B (ddr);
stmt_b = DR_STMT (DDR_B (ddr));
dr_group_first_b = DR_GROUP_FIRST_DR (vinfo_for_stmt (stmt_b));
if (dr_group_first_b)
{
stmt_b = dr_group_first_b;
dr_b = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt_b));
}
addr_base_a =
vect_create_addr_base_for_vector_ref (stmt_a, cond_expr_stmt_list, vect_create_addr_base_for_vector_ref (stmt_a, cond_expr_stmt_list,
NULL_TREE, loop); NULL_TREE, loop);
tree addr_base_b = addr_base_b =
vect_create_addr_base_for_vector_ref (stmt_b, cond_expr_stmt_list, vect_create_addr_base_for_vector_ref (stmt_b, cond_expr_stmt_list,
NULL_TREE, loop); NULL_TREE, loop);
tree segment_length_a = vect_vfa_segment_size (DDR_A (ddr), vect_factor); segment_length_a = vect_vfa_segment_size (dr_a, vect_factor);
tree segment_length_b = vect_vfa_segment_size (DDR_B (ddr), vect_factor); segment_length_b = vect_vfa_segment_size (dr_b, vect_factor);
if (vect_print_dump_info (REPORT_DR_DETAILS)) if (vect_print_dump_info (REPORT_DR_DETAILS))
{ {
fprintf (vect_dump, fprintf (vect_dump,
"create runtime check for data references "); "create runtime check for data references ");
print_generic_expr (vect_dump, DR_REF (DDR_A (ddr)), TDF_SLIM); print_generic_expr (vect_dump, DR_REF (dr_a), TDF_SLIM);
fprintf (vect_dump, " and "); fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (DDR_B (ddr)), TDF_SLIM); print_generic_expr (vect_dump, DR_REF (dr_b), TDF_SLIM);
} }
...@@ -6988,6 +7015,91 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, ...@@ -6988,6 +7015,91 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo,
} }
/* Function vect_loop_versioning.
If the loop has data references that may or may not be aligned or/and
has data reference relations whose independence was not proven then
two versions of the loop need to be generated, one which is vectorized
and one which isn't. A test is then generated to control which of the
loops is executed. The test checks for the alignment of all of the
data references that may or may not be aligned. An additional
sequence of runtime tests is generated for each pairs of DDRs whose
independence was not proven. The vectorized version of loop is
executed only if both alias and alignment tests are passed. */
static void
vect_loop_versioning (loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
struct loop *nloop;
tree cond_expr = NULL_TREE;
tree cond_expr_stmt_list = NULL_TREE;
basic_block condition_bb;
block_stmt_iterator cond_exp_bsi;
basic_block merge_bb;
basic_block new_exit_bb;
edge new_exit_e, e;
tree orig_phi, new_phi, arg;
unsigned prob = 4 * REG_BR_PROB_BASE / 5;
tree gimplify_stmt_list;
if (!VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo))
&& !VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)))
return;
if (VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)))
cond_expr =
vect_create_cond_for_align_checks (loop_vinfo, &cond_expr_stmt_list);
if (VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)))
vect_create_cond_for_alias_checks (loop_vinfo, &cond_expr, &cond_expr_stmt_list);
cond_expr =
fold_build2 (NE_EXPR, boolean_type_node, cond_expr, integer_zero_node);
cond_expr =
force_gimple_operand (cond_expr, &gimplify_stmt_list, true,
NULL_TREE);
append_to_statement_list (gimplify_stmt_list, &cond_expr_stmt_list);
initialize_original_copy_tables ();
nloop = loop_version (loop, cond_expr, &condition_bb,
prob, prob, REG_BR_PROB_BASE - prob, true);
free_original_copy_tables();
/* Loop versioning violates an assumption we try to maintain during
vectorization - that the loop exit block has a single predecessor.
After versioning, the exit block of both loop versions is the same
basic block (i.e. it has two predecessors). Just in order to simplify
following transformations in the vectorizer, we fix this situation
here by adding a new (empty) block on the exit-edge of the loop,
with the proper loop-exit phis to maintain loop-closed-form. */
merge_bb = single_exit (loop)->dest;
gcc_assert (EDGE_COUNT (merge_bb->preds) == 2);
new_exit_bb = split_edge (single_exit (loop));
new_exit_e = single_exit (loop);
e = EDGE_SUCC (new_exit_bb, 0);
for (orig_phi = phi_nodes (merge_bb); orig_phi;
orig_phi = PHI_CHAIN (orig_phi))
{
new_phi = create_phi_node (SSA_NAME_VAR (PHI_RESULT (orig_phi)),
new_exit_bb);
arg = PHI_ARG_DEF_FROM_EDGE (orig_phi, e);
add_phi_arg (new_phi, arg, new_exit_e);
SET_PHI_ARG_DEF (orig_phi, e->dest_idx, PHI_RESULT (new_phi));
}
/* End loop-exit-fixes after versioning. */
update_ssa (TODO_update_ssa);
if (cond_expr_stmt_list)
{
cond_exp_bsi = bsi_last (condition_bb);
bsi_insert_before (&cond_exp_bsi, cond_expr_stmt_list, BSI_SAME_STMT);
}
}
/* Remove a group of stores (for SLP or interleaving), free their /* Remove a group of stores (for SLP or interleaving), free their
stmt_vec_info. */ stmt_vec_info. */
...@@ -7096,7 +7208,6 @@ vect_schedule_slp (loop_vec_info loop_vinfo, unsigned int nunits) ...@@ -7096,7 +7208,6 @@ vect_schedule_slp (loop_vec_info loop_vinfo, unsigned int nunits)
return is_store; return is_store;
} }
/* Function vect_transform_loop. /* Function vect_transform_loop.
The analysis phase has determined that the loop is vectorizable. The analysis phase has determined that the loop is vectorizable.
...@@ -7119,82 +7230,7 @@ vect_transform_loop (loop_vec_info loop_vinfo) ...@@ -7119,82 +7230,7 @@ vect_transform_loop (loop_vec_info loop_vinfo)
if (vect_print_dump_info (REPORT_DETAILS)) if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vec_transform_loop ==="); fprintf (vect_dump, "=== vec_transform_loop ===");
vect_loop_versioning (loop_vinfo);
/* If the loop has data references that may or may not be aligned or/and
has data reference relations whose independence was not proven then
two versions of the loop need to be generated, one which is vectorized
and one which isn't. A test is then generated to control which of the
loops is executed. The test checks for the alignment of all of the
data references that may or may not be aligned. An additional
sequence of runtime tests is generated for each pairs of DDRs whose
independence was not proven. The vectorized version of loop is
executed only if both alias and alignment tests are passed. */
if (VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo))
|| VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)))
{
struct loop *nloop;
tree cond_expr = NULL_TREE;
tree cond_expr_stmt_list = NULL_TREE;
basic_block condition_bb;
block_stmt_iterator cond_exp_bsi;
basic_block merge_bb;
basic_block new_exit_bb;
edge new_exit_e, e;
tree orig_phi, new_phi, arg;
unsigned prob = 4 * REG_BR_PROB_BASE / 5;
tree gimplify_stmt_list;
if (VEC_length (tree, LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo)))
cond_expr =
vect_create_cond_for_align_checks (loop_vinfo, &cond_expr_stmt_list);
if (VEC_length (ddr_p, LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo)))
vect_create_cond_for_alias_checks (loop_vinfo, &cond_expr,
&cond_expr_stmt_list);
cond_expr =
fold_build2 (NE_EXPR, boolean_type_node, cond_expr, integer_zero_node);
cond_expr =
force_gimple_operand (cond_expr, &gimplify_stmt_list, true,
NULL_TREE);
append_to_statement_list (gimplify_stmt_list, &cond_expr_stmt_list);
initialize_original_copy_tables ();
nloop = loop_version (loop, cond_expr, &condition_bb,
prob, prob, REG_BR_PROB_BASE - prob, true);
free_original_copy_tables();
/** Loop versioning violates an assumption we try to maintain during
vectorization - that the loop exit block has a single predecessor.
After versioning, the exit block of both loop versions is the same
basic block (i.e. it has two predecessors). Just in order to simplify
following transformations in the vectorizer, we fix this situation
here by adding a new (empty) block on the exit-edge of the loop,
with the proper loop-exit phis to maintain loop-closed-form. **/
merge_bb = single_exit (loop)->dest;
gcc_assert (EDGE_COUNT (merge_bb->preds) == 2);
new_exit_bb = split_edge (single_exit (loop));
new_exit_e = single_exit (loop);
e = EDGE_SUCC (new_exit_bb, 0);
for (orig_phi = phi_nodes (merge_bb); orig_phi;
orig_phi = PHI_CHAIN (orig_phi))
{
new_phi = create_phi_node (SSA_NAME_VAR (PHI_RESULT (orig_phi)),
new_exit_bb);
arg = PHI_ARG_DEF_FROM_EDGE (orig_phi, e);
add_phi_arg (new_phi, arg, new_exit_e);
SET_PHI_ARG_DEF (orig_phi, e->dest_idx, PHI_RESULT (new_phi));
}
/** end loop-exit-fixes after versioning **/
update_ssa (TODO_update_ssa);
cond_exp_bsi = bsi_last (condition_bb);
bsi_insert_before (&cond_exp_bsi, cond_expr_stmt_list, BSI_SAME_STMT);
}
/* CHECKME: we wouldn't need this if we called update_ssa once /* CHECKME: we wouldn't need this if we called update_ssa once
for all loops. */ for all loops. */
......
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