re PR tree-optimization/56764 (vect_prune_runtime_alias_test_list not smart enough)
2013-11-07 Cong Hou <congh@google.com> PR tree-optimization/56764 * tree-vect-loop-manip.c (vect_create_cond_for_alias_checks): Combine alias checks if it is possible to amortize the runtime overhead. Return the number of alias checks after merging. * tree-vect-data-refs.c (vect_prune_runtime_alias_test_list): Use the function vect_create_cond_for_alias_checks () to check the number of alias checks. 2013-11-07 Cong Hou <congh@google.com> * gcc.dg/vect/vect-alias-check.c: New. From-SVN: r204538
This commit is contained in:
parent
6d0b710573
commit
a05a89fa70
@ -1,3 +1,13 @@
|
||||
2013-11-07 Cong Hou <congh@google.com>
|
||||
|
||||
PR tree-optimization/56764
|
||||
* tree-vect-loop-manip.c (vect_create_cond_for_alias_checks):
|
||||
Combine alias checks if it is possible to amortize the runtime
|
||||
overhead. Return the number of alias checks after merging.
|
||||
* tree-vect-data-refs.c (vect_prune_runtime_alias_test_list):
|
||||
Use the function vect_create_cond_for_alias_checks () to check
|
||||
the number of alias checks.
|
||||
|
||||
2013-11-07 Jeff Law <law@redhat.com>
|
||||
|
||||
* varpool.c (ctor_for_folding): Fix typo in comment.
|
||||
|
@ -1,3 +1,7 @@
|
||||
2013-11-07 Cong Hou <congh@google.com>
|
||||
|
||||
* gcc.dg/vect/vect-alias-check.c: New.
|
||||
|
||||
2013-11-07 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.dg/tree-ssa/loop-39.c: New test.
|
||||
|
18
gcc/testsuite/gcc.dg/vect/vect-alias-check.c
Normal file
18
gcc/testsuite/gcc.dg/vect/vect-alias-check.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* { dg-require-effective-target vect_int } */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -ftree-vectorize --param=vect-max-version-for-alias-checks=2 -fdump-tree-vect-details" } */
|
||||
|
||||
/* A test case showing three potential alias checks between
|
||||
a[i] and b[i], b[i+7], b[i+14]. With alias checks merging
|
||||
enabled, those tree checks can be merged into one, and the
|
||||
loop will be vectorized with vect-max-version-for-alias-checks=2. */
|
||||
|
||||
void foo (int *a, int *b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 1000; ++i)
|
||||
a[i] = b[i] + b[i+7] + b[i+14];
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
|
||||
/* { dg-final { cleanup-tree-dump "vect" } } */
|
@ -135,41 +135,6 @@ vect_get_smallest_scalar_type (gimple stmt, HOST_WIDE_INT *lhs_size_unit,
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
gimple stmt_i = DR_STMT (dr_i);
|
||||
gimple stmt_j = DR_STMT (dr_j);
|
||||
|
||||
if (operand_equal_p (DR_REF (dr_i), DR_REF (dr_j), 0)
|
||||
|| (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_i))
|
||||
&& GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_j))
|
||||
&& (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt_i))
|
||||
== GROUP_FIRST_ELEMENT (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. */
|
||||
@ -2654,69 +2619,320 @@ vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Operator == between two dr_addr_with_seg_len objects.
|
||||
|
||||
This equality operator is used to make sure two data refs
|
||||
are the same one so that we will consider to combine the
|
||||
aliasing checks of those two pairs of data dependent data
|
||||
refs. */
|
||||
|
||||
static bool
|
||||
operator == (const dr_addr_with_seg_len& d1,
|
||||
const dr_addr_with_seg_len& d2)
|
||||
{
|
||||
return operand_equal_p (d1.basic_addr, d2.basic_addr, 0)
|
||||
&& compare_tree (d1.offset, d2.offset) == 0
|
||||
&& compare_tree (d1.seg_len, d2.seg_len) == 0;
|
||||
}
|
||||
|
||||
/* Function comp_dr_addr_with_seg_len_pair.
|
||||
|
||||
Comparison function for sorting objects of dr_addr_with_seg_len_pair_t
|
||||
so that we can combine aliasing checks in one scan. */
|
||||
|
||||
static int
|
||||
comp_dr_addr_with_seg_len_pair (const void *p1_, const void *p2_)
|
||||
{
|
||||
const dr_addr_with_seg_len_pair_t* p1 =
|
||||
(const dr_addr_with_seg_len_pair_t *) p1_;
|
||||
const dr_addr_with_seg_len_pair_t* p2 =
|
||||
(const dr_addr_with_seg_len_pair_t *) p2_;
|
||||
|
||||
const dr_addr_with_seg_len &p11 = p1->first,
|
||||
&p12 = p1->second,
|
||||
&p21 = p2->first,
|
||||
&p22 = p2->second;
|
||||
|
||||
int comp_res = compare_tree (p11.basic_addr, p21.basic_addr);
|
||||
if (comp_res != 0)
|
||||
return comp_res;
|
||||
|
||||
comp_res = compare_tree (p12.basic_addr, p22.basic_addr);
|
||||
if (comp_res != 0)
|
||||
return comp_res;
|
||||
|
||||
if (TREE_CODE (p11.offset) != INTEGER_CST
|
||||
|| TREE_CODE (p21.offset) != INTEGER_CST)
|
||||
{
|
||||
comp_res = compare_tree (p11.offset, p21.offset);
|
||||
if (comp_res != 0)
|
||||
return comp_res;
|
||||
}
|
||||
if (tree_int_cst_compare (p11.offset, p21.offset) < 0)
|
||||
return -1;
|
||||
if (tree_int_cst_compare (p11.offset, p21.offset) > 0)
|
||||
return 1;
|
||||
if (TREE_CODE (p12.offset) != INTEGER_CST
|
||||
|| TREE_CODE (p22.offset) != INTEGER_CST)
|
||||
{
|
||||
comp_res = compare_tree (p12.offset, p22.offset);
|
||||
if (comp_res != 0)
|
||||
return comp_res;
|
||||
}
|
||||
if (tree_int_cst_compare (p12.offset, p22.offset) < 0)
|
||||
return -1;
|
||||
if (tree_int_cst_compare (p12.offset, p22.offset) > 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T> static void
|
||||
swap (T& a, T& b)
|
||||
{
|
||||
T c (a);
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
|
||||
/* Function vect_vfa_segment_size.
|
||||
|
||||
Create an expression that computes the size of segment
|
||||
that will be accessed for a data reference. The functions takes into
|
||||
account that realignment loads may access one more vector.
|
||||
|
||||
Input:
|
||||
DR: The data reference.
|
||||
LENGTH_FACTOR: segment length to consider.
|
||||
|
||||
Return an expression whose value is the size of segment which will be
|
||||
accessed by DR. */
|
||||
|
||||
static tree
|
||||
vect_vfa_segment_size (struct data_reference *dr, tree length_factor)
|
||||
{
|
||||
tree segment_length;
|
||||
|
||||
if (integer_zerop (DR_STEP (dr)))
|
||||
segment_length = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr)));
|
||||
else
|
||||
segment_length = size_binop (MULT_EXPR,
|
||||
fold_convert (sizetype, DR_STEP (dr)),
|
||||
fold_convert (sizetype, length_factor));
|
||||
|
||||
if (vect_supportable_dr_alignment (dr, false)
|
||||
== dr_explicit_realign_optimized)
|
||||
{
|
||||
tree vector_size = TYPE_SIZE_UNIT
|
||||
(STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr))));
|
||||
|
||||
segment_length = size_binop (PLUS_EXPR, segment_length, vector_size);
|
||||
}
|
||||
return segment_length;
|
||||
}
|
||||
|
||||
/* Function vect_prune_runtime_alias_test_list.
|
||||
|
||||
Prune a list of ddrs to be tested at run-time by versioning for alias.
|
||||
Merge several alias checks into one if possible.
|
||||
Return FALSE if resulting list of ddrs is longer then allowed by
|
||||
PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE. */
|
||||
|
||||
bool
|
||||
vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
|
||||
{
|
||||
vec<ddr_p> ddrs =
|
||||
vec<ddr_p> may_alias_ddrs =
|
||||
LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
|
||||
unsigned i, j;
|
||||
vec<dr_addr_with_seg_len_pair_t>& comp_alias_ddrs =
|
||||
LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
|
||||
int vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
|
||||
tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo);
|
||||
|
||||
ddr_p ddr;
|
||||
unsigned int i;
|
||||
tree length_factor;
|
||||
|
||||
if (dump_enabled_p ())
|
||||
dump_printf_loc (MSG_NOTE, vect_location,
|
||||
"=== vect_prune_runtime_alias_test_list ===\n");
|
||||
|
||||
for (i = 0; i < ddrs.length (); )
|
||||
if (may_alias_ddrs.is_empty ())
|
||||
return true;
|
||||
|
||||
/* Basically, for each pair of dependent data refs store_ptr_0
|
||||
and load_ptr_0, we create an expression:
|
||||
|
||||
((store_ptr_0 + store_segment_length_0) <= load_ptr_0)
|
||||
|| (load_ptr_0 + load_segment_length_0) <= store_ptr_0))
|
||||
|
||||
for aliasing checks. However, in some cases we can decrease
|
||||
the number of checks by combining two checks into one. For
|
||||
example, suppose we have another pair of data refs store_ptr_0
|
||||
and load_ptr_1, and if the following condition is satisfied:
|
||||
|
||||
load_ptr_0 < load_ptr_1 &&
|
||||
load_ptr_1 - load_ptr_0 - load_segment_length_0 < store_segment_length_0
|
||||
|
||||
(this condition means, in each iteration of vectorized loop,
|
||||
the accessed memory of store_ptr_0 cannot be between the memory
|
||||
of load_ptr_0 and load_ptr_1.)
|
||||
|
||||
we then can use only the following expression to finish the
|
||||
alising checks between store_ptr_0 & load_ptr_0 and
|
||||
store_ptr_0 & load_ptr_1:
|
||||
|
||||
((store_ptr_0 + store_segment_length_0) <= load_ptr_0)
|
||||
|| (load_ptr_1 + load_segment_length_1 <= store_ptr_0))
|
||||
|
||||
Note that we only consider that load_ptr_0 and load_ptr_1 have the
|
||||
same basic address. */
|
||||
|
||||
comp_alias_ddrs.create (may_alias_ddrs.length ());
|
||||
|
||||
/* First, we collect all data ref pairs for aliasing checks. */
|
||||
FOR_EACH_VEC_ELT (may_alias_ddrs, i, ddr)
|
||||
{
|
||||
bool found;
|
||||
ddr_p ddr_i;
|
||||
struct data_reference *dr_a, *dr_b;
|
||||
gimple dr_group_first_a, dr_group_first_b;
|
||||
tree segment_length_a, segment_length_b;
|
||||
gimple stmt_a, stmt_b;
|
||||
|
||||
ddr_i = ddrs[i];
|
||||
found = false;
|
||||
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
ddr_p ddr_j = ddrs[j];
|
||||
|
||||
if (vect_vfa_range_equal (ddr_i, ddr_j))
|
||||
{
|
||||
if (dump_enabled_p ())
|
||||
{
|
||||
dump_printf_loc (MSG_NOTE, vect_location,
|
||||
"found equal ranges ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (DDR_A (ddr_i)));
|
||||
dump_printf (MSG_NOTE, ", ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (DDR_B (ddr_i)));
|
||||
dump_printf (MSG_NOTE, " and ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (DDR_A (ddr_j)));
|
||||
dump_printf (MSG_NOTE, ", ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (DDR_B (ddr_j)));
|
||||
dump_printf (MSG_NOTE, "\n");
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
dr_a = DDR_A (ddr);
|
||||
stmt_a = DR_STMT (DDR_A (ddr));
|
||||
dr_group_first_a = GROUP_FIRST_ELEMENT (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));
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
ddrs.ordered_remove (i);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
dr_b = DDR_B (ddr);
|
||||
stmt_b = DR_STMT (DDR_B (ddr));
|
||||
dr_group_first_b = GROUP_FIRST_ELEMENT (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));
|
||||
}
|
||||
|
||||
if (!operand_equal_p (DR_STEP (dr_a), DR_STEP (dr_b), 0))
|
||||
length_factor = scalar_loop_iters;
|
||||
else
|
||||
length_factor = size_int (vect_factor);
|
||||
segment_length_a = vect_vfa_segment_size (dr_a, length_factor);
|
||||
segment_length_b = vect_vfa_segment_size (dr_b, length_factor);
|
||||
|
||||
dr_addr_with_seg_len_pair_t dr_with_seg_len_pair
|
||||
(dr_addr_with_seg_len
|
||||
(dr_a, DR_BASE_ADDRESS (dr_a),
|
||||
size_binop (PLUS_EXPR, DR_OFFSET (dr_a), DR_INIT (dr_a)),
|
||||
segment_length_a),
|
||||
dr_addr_with_seg_len
|
||||
(dr_b, DR_BASE_ADDRESS (dr_b),
|
||||
size_binop (PLUS_EXPR, DR_OFFSET (dr_b), DR_INIT (dr_b)),
|
||||
segment_length_b));
|
||||
|
||||
if (compare_tree (dr_with_seg_len_pair.first.basic_addr,
|
||||
dr_with_seg_len_pair.second.basic_addr) > 0)
|
||||
swap (dr_with_seg_len_pair.first, dr_with_seg_len_pair.second);
|
||||
|
||||
comp_alias_ddrs.safe_push (dr_with_seg_len_pair);
|
||||
}
|
||||
|
||||
if (ddrs.length () >
|
||||
(unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
|
||||
/* Second, we sort the collected data ref pairs so that we can scan
|
||||
them once to combine all possible aliasing checks. */
|
||||
comp_alias_ddrs.qsort (comp_dr_addr_with_seg_len_pair);
|
||||
|
||||
/* Third, we scan the sorted dr pairs and check if we can combine
|
||||
alias checks of two neighbouring dr pairs. */
|
||||
for (size_t i = 1; i < comp_alias_ddrs.length (); ++i)
|
||||
{
|
||||
/* Deal with two ddrs (dr_a1, dr_b1) and (dr_a2, dr_b2). */
|
||||
dr_addr_with_seg_len *dr_a1 = &comp_alias_ddrs[i-1].first,
|
||||
*dr_b1 = &comp_alias_ddrs[i-1].second,
|
||||
*dr_a2 = &comp_alias_ddrs[i].first,
|
||||
*dr_b2 = &comp_alias_ddrs[i].second;
|
||||
|
||||
/* Remove duplicate data ref pairs. */
|
||||
if (*dr_a1 == *dr_a2 && *dr_b1 == *dr_b2)
|
||||
{
|
||||
if (dump_enabled_p ())
|
||||
{
|
||||
dump_printf_loc (MSG_NOTE, vect_location,
|
||||
"found equal ranges ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (dr_a1->dr));
|
||||
dump_printf (MSG_NOTE, ", ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (dr_b1->dr));
|
||||
dump_printf (MSG_NOTE, " and ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (dr_a2->dr));
|
||||
dump_printf (MSG_NOTE, ", ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM,
|
||||
DR_REF (dr_b2->dr));
|
||||
dump_printf (MSG_NOTE, "\n");
|
||||
}
|
||||
|
||||
comp_alias_ddrs.ordered_remove (i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*dr_a1 == *dr_a2 || *dr_b1 == *dr_b2)
|
||||
{
|
||||
/* We consider the case that DR_B1 and DR_B2 are same memrefs,
|
||||
and DR_A1 and DR_A2 are two consecutive memrefs. */
|
||||
if (*dr_a1 == *dr_a2)
|
||||
{
|
||||
swap (dr_a1, dr_b1);
|
||||
swap (dr_a2, dr_b2);
|
||||
}
|
||||
|
||||
if (!operand_equal_p (dr_a1->basic_addr, dr_a2->basic_addr, 0)
|
||||
|| !host_integerp (dr_a1->offset, 0)
|
||||
|| !host_integerp (dr_a2->offset, 0))
|
||||
continue;
|
||||
|
||||
HOST_WIDE_INT diff = TREE_INT_CST_LOW (dr_a2->offset) -
|
||||
TREE_INT_CST_LOW (dr_a1->offset);
|
||||
|
||||
|
||||
/* Now we check if the following condition is satisfied:
|
||||
|
||||
DIFF - SEGMENT_LENGTH_A < SEGMENT_LENGTH_B
|
||||
|
||||
where DIFF = DR_A2->OFFSET - DR_A1->OFFSET. However,
|
||||
SEGMENT_LENGTH_A or SEGMENT_LENGTH_B may not be constant so we
|
||||
have to make a best estimation. We can get the minimum value
|
||||
of SEGMENT_LENGTH_B as a constant, represented by MIN_SEG_LEN_B,
|
||||
then either of the following two conditions can guarantee the
|
||||
one above:
|
||||
|
||||
1: DIFF <= MIN_SEG_LEN_B
|
||||
2: DIFF - SEGMENT_LENGTH_A < MIN_SEG_LEN_B
|
||||
|
||||
*/
|
||||
|
||||
HOST_WIDE_INT
|
||||
min_seg_len_b = (TREE_CODE (dr_b1->seg_len) == INTEGER_CST) ?
|
||||
TREE_INT_CST_LOW (dr_b1->seg_len) :
|
||||
vect_factor;
|
||||
|
||||
if (diff <= min_seg_len_b
|
||||
|| (TREE_CODE (dr_a1->seg_len) == INTEGER_CST
|
||||
&& diff - (HOST_WIDE_INT) TREE_INT_CST_LOW (dr_a1->seg_len) <
|
||||
min_seg_len_b))
|
||||
{
|
||||
dr_a1->seg_len = size_binop (PLUS_EXPR,
|
||||
dr_a2->seg_len, size_int (diff));
|
||||
comp_alias_ddrs.ordered_remove (i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((int) comp_alias_ddrs.length () >
|
||||
PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
|
||||
{
|
||||
if (dump_enabled_p ())
|
||||
{
|
||||
@ -2725,8 +2941,6 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
|
||||
"generated checks exceeded.\n");
|
||||
}
|
||||
|
||||
LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).truncate (0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2219,44 +2219,6 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
|
||||
*cond_expr = part_cond_expr;
|
||||
}
|
||||
|
||||
|
||||
/* Function vect_vfa_segment_size.
|
||||
|
||||
Create an expression that computes the size of segment
|
||||
that will be accessed for a data reference. The functions takes into
|
||||
account that realignment loads may access one more vector.
|
||||
|
||||
Input:
|
||||
DR: The data reference.
|
||||
LENGTH_FACTOR: segment length to consider.
|
||||
|
||||
Return an expression whose value is the size of segment which will be
|
||||
accessed by DR. */
|
||||
|
||||
static tree
|
||||
vect_vfa_segment_size (struct data_reference *dr, tree length_factor)
|
||||
{
|
||||
tree segment_length;
|
||||
|
||||
if (integer_zerop (DR_STEP (dr)))
|
||||
segment_length = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr)));
|
||||
else
|
||||
segment_length = size_binop (MULT_EXPR,
|
||||
fold_convert (sizetype, DR_STEP (dr)),
|
||||
fold_convert (sizetype, length_factor));
|
||||
|
||||
if (vect_supportable_dr_alignment (dr, false)
|
||||
== dr_explicit_realign_optimized)
|
||||
{
|
||||
tree vector_size = TYPE_SIZE_UNIT
|
||||
(STMT_VINFO_VECTYPE (vinfo_for_stmt (DR_STMT (dr))));
|
||||
|
||||
segment_length = size_binop (PLUS_EXPR, segment_length, vector_size);
|
||||
}
|
||||
return segment_length;
|
||||
}
|
||||
|
||||
|
||||
/* Function vect_create_cond_for_alias_checks.
|
||||
|
||||
Create a conditional expression that represents the run-time checks for
|
||||
@ -2265,28 +2227,24 @@ vect_vfa_segment_size (struct data_reference *dr, tree length_factor)
|
||||
|
||||
Input:
|
||||
COND_EXPR - input conditional expression. New conditions will be chained
|
||||
with logical AND operation.
|
||||
with logical AND operation. If it is NULL, then the function
|
||||
is used to return the number of alias checks.
|
||||
LOOP_VINFO - field LOOP_VINFO_MAY_ALIAS_STMTS contains the list of ddrs
|
||||
to be checked.
|
||||
|
||||
Output:
|
||||
COND_EXPR - conditional expression.
|
||||
|
||||
The returned value is the conditional expression to be used in the if
|
||||
The returned COND_EXPR is the conditional expression to be used in the if
|
||||
statement that controls which version of the loop gets executed at runtime.
|
||||
*/
|
||||
|
||||
static void
|
||||
void
|
||||
vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
|
||||
{
|
||||
vec<ddr_p> may_alias_ddrs =
|
||||
LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo);
|
||||
int vect_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
|
||||
tree scalar_loop_iters = LOOP_VINFO_NITERS (loop_vinfo);
|
||||
|
||||
ddr_p ddr;
|
||||
unsigned int i;
|
||||
tree part_cond_expr, length_factor;
|
||||
vec<dr_addr_with_seg_len_pair_t> comp_alias_ddrs =
|
||||
LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
|
||||
tree part_cond_expr;
|
||||
|
||||
/* Create expression
|
||||
((store_ptr_0 + store_segment_length_0) <= load_ptr_0)
|
||||
@ -2297,70 +2255,39 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
|
||||
((store_ptr_n + store_segment_length_n) <= load_ptr_n)
|
||||
|| (load_ptr_n + load_segment_length_n) <= store_ptr_n)) */
|
||||
|
||||
if (may_alias_ddrs.is_empty ())
|
||||
if (comp_alias_ddrs.is_empty ())
|
||||
return;
|
||||
|
||||
FOR_EACH_VEC_ELT (may_alias_ddrs, i, ddr)
|
||||
for (size_t i = 0, s = comp_alias_ddrs.length (); i < s; ++i)
|
||||
{
|
||||
struct data_reference *dr_a, *dr_b;
|
||||
gimple dr_group_first_a, dr_group_first_b;
|
||||
tree addr_base_a, addr_base_b;
|
||||
tree segment_length_a, segment_length_b;
|
||||
gimple stmt_a, stmt_b;
|
||||
tree seg_a_min, seg_a_max, seg_b_min, seg_b_max;
|
||||
const dr_addr_with_seg_len& dr_a = comp_alias_ddrs[i].first;
|
||||
const dr_addr_with_seg_len& dr_b = comp_alias_ddrs[i].second;
|
||||
tree segment_length_a = dr_a.seg_len;
|
||||
tree segment_length_b = dr_b.seg_len;
|
||||
|
||||
dr_a = DDR_A (ddr);
|
||||
stmt_a = DR_STMT (DDR_A (ddr));
|
||||
dr_group_first_a = GROUP_FIRST_ELEMENT (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 = GROUP_FIRST_ELEMENT (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
|
||||
= fold_build_pointer_plus (DR_BASE_ADDRESS (dr_a),
|
||||
size_binop (PLUS_EXPR, DR_OFFSET (dr_a),
|
||||
DR_INIT (dr_a)));
|
||||
addr_base_b
|
||||
= fold_build_pointer_plus (DR_BASE_ADDRESS (dr_b),
|
||||
size_binop (PLUS_EXPR, DR_OFFSET (dr_b),
|
||||
DR_INIT (dr_b)));
|
||||
|
||||
if (!operand_equal_p (DR_STEP (dr_a), DR_STEP (dr_b), 0))
|
||||
length_factor = scalar_loop_iters;
|
||||
else
|
||||
length_factor = size_int (vect_factor);
|
||||
segment_length_a = vect_vfa_segment_size (dr_a, length_factor);
|
||||
segment_length_b = vect_vfa_segment_size (dr_b, length_factor);
|
||||
tree addr_base_a
|
||||
= fold_build_pointer_plus (dr_a.basic_addr, dr_a.offset);
|
||||
tree addr_base_b
|
||||
= fold_build_pointer_plus (dr_b.basic_addr, dr_b.offset);
|
||||
|
||||
if (dump_enabled_p ())
|
||||
{
|
||||
dump_printf_loc (MSG_NOTE, vect_location,
|
||||
"create runtime check for data references ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_a));
|
||||
"create runtime check for data references ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_a.dr));
|
||||
dump_printf (MSG_NOTE, " and ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_b));
|
||||
dump_printf (MSG_NOTE, "\n");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_b.dr));
|
||||
dump_printf (MSG_NOTE, "\n");
|
||||
}
|
||||
|
||||
seg_a_min = addr_base_a;
|
||||
seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_a);
|
||||
if (tree_int_cst_compare (DR_STEP (dr_a), size_zero_node) < 0)
|
||||
tree seg_a_min = addr_base_a;
|
||||
tree seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_a);
|
||||
if (tree_int_cst_compare (DR_STEP (dr_a.dr), size_zero_node) < 0)
|
||||
seg_a_min = seg_a_max, seg_a_max = addr_base_a;
|
||||
|
||||
seg_b_min = addr_base_b;
|
||||
seg_b_max = fold_build_pointer_plus (addr_base_b, segment_length_b);
|
||||
if (tree_int_cst_compare (DR_STEP (dr_b), size_zero_node) < 0)
|
||||
tree seg_b_min = addr_base_b;
|
||||
tree seg_b_max = fold_build_pointer_plus (addr_base_b, segment_length_b);
|
||||
if (tree_int_cst_compare (DR_STEP (dr_b.dr), size_zero_node) < 0)
|
||||
seg_b_min = seg_b_max, seg_b_max = addr_base_b;
|
||||
|
||||
part_cond_expr =
|
||||
@ -2378,7 +2305,9 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
|
||||
if (dump_enabled_p ())
|
||||
dump_printf_loc (MSG_NOTE, vect_location,
|
||||
"created %u versioning for alias checks.\n",
|
||||
may_alias_ddrs.length ());
|
||||
comp_alias_ddrs.length ());
|
||||
|
||||
comp_alias_ddrs.release ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,6 +175,36 @@ typedef struct _slp_oprnd_info
|
||||
|
||||
|
||||
|
||||
/* This struct is used to store the information of a data reference,
|
||||
including the data ref itself, its basic address, the access offset
|
||||
and the segment length for aliasing checks. This is used to generate
|
||||
alias checks. */
|
||||
|
||||
struct dr_addr_with_seg_len
|
||||
{
|
||||
dr_addr_with_seg_len (data_reference* d, tree addr, tree off, tree len)
|
||||
: dr (d), basic_addr (addr), offset (off), seg_len (len) {}
|
||||
|
||||
data_reference *dr;
|
||||
tree basic_addr;
|
||||
tree offset;
|
||||
tree seg_len;
|
||||
};
|
||||
|
||||
/* This struct contains two dr_addr_with_seg_len objects with aliasing data
|
||||
refs. Two comparisons are generated from them. */
|
||||
|
||||
struct dr_addr_with_seg_len_pair_t
|
||||
{
|
||||
dr_addr_with_seg_len_pair_t (const dr_addr_with_seg_len& d1,
|
||||
const dr_addr_with_seg_len& d2)
|
||||
: first (d1), second (d2) {}
|
||||
|
||||
dr_addr_with_seg_len first;
|
||||
dr_addr_with_seg_len second;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _vect_peel_info
|
||||
{
|
||||
int npeel;
|
||||
@ -274,6 +304,10 @@ typedef struct _loop_vec_info {
|
||||
for a run-time aliasing check. */
|
||||
vec<ddr_p> may_alias_ddrs;
|
||||
|
||||
/* Data Dependence Relations defining address ranges together with segment
|
||||
lengths from which the run-time aliasing check is built. */
|
||||
vec<dr_addr_with_seg_len_pair_t> comp_alias_ddrs;
|
||||
|
||||
/* Statements in the loop that have data references that are candidates for a
|
||||
runtime (loop versioning) misalignment check. */
|
||||
vec<gimple> may_misalign_stmts;
|
||||
@ -336,6 +370,7 @@ typedef struct _loop_vec_info {
|
||||
#define LOOP_VINFO_MAY_MISALIGN_STMTS(L) (L)->may_misalign_stmts
|
||||
#define LOOP_VINFO_LOC(L) (L)->loop_line_number
|
||||
#define LOOP_VINFO_MAY_ALIAS_DDRS(L) (L)->may_alias_ddrs
|
||||
#define LOOP_VINFO_COMP_ALIAS_DDRS(L) (L)->comp_alias_ddrs
|
||||
#define LOOP_VINFO_GROUPED_STORES(L) (L)->grouped_stores
|
||||
#define LOOP_VINFO_SLP_INSTANCES(L) (L)->slp_instances
|
||||
#define LOOP_VINFO_SLP_UNROLLING_FACTOR(L) (L)->slp_unrolling_factor
|
||||
|
Loading…
Reference in New Issue
Block a user