* tree-vect-loop-manip.c (create_intersect_range_checks_index)

(create_intersect_range_checks): Move from ...
	* tree-data-ref.c (create_intersect_range_checks_index)
	(create_intersect_range_checks): ... to here.
	(create_runtime_alias_checks): New function factored from ...
	* tree-vect-loop-manip.c (vect_create_cond_for_alias_checks): ...
	here.  Call above function.
	* tree-data-ref.h (create_runtime_alias_checks): New function.

From-SVN: r248726
This commit is contained in:
Bin Cheng 2017-05-31 09:03:27 +00:00 committed by Bin Cheng
parent c7d7e2227f
commit 9cbd2d979c
4 changed files with 240 additions and 214 deletions

View File

@ -1,3 +1,14 @@
2017-05-31 Bin Cheng <bin.cheng@arm.com>
* tree-vect-loop-manip.c (create_intersect_range_checks_index)
(create_intersect_range_checks): Move from ...
* tree-data-ref.c (create_intersect_range_checks_index)
(create_intersect_range_checks): ... to here.
(create_runtime_alias_checks): New function factored from ...
* tree-vect-loop-manip.c (vect_create_cond_for_alias_checks): ...
here. Call above function.
* tree-data-ref.h (create_runtime_alias_checks): New function.
2017-05-31 Bin Cheng <bin.cheng@arm.com>
* tree-data-ref.c (prune_runtime_alias_test_list): Relax minimal

View File

@ -1470,6 +1470,231 @@ prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *alias_pairs,
}
}
/* Given LOOP's two data references and segment lengths described by DR_A
and DR_B, create expression checking if the two addresses ranges intersect
with each other based on index of the two addresses. This can only be
done if DR_A and DR_B referring to the same (array) object and the index
is the only difference. For example:
DR_A DR_B
data-ref arr[i] arr[j]
base_object arr arr
index {i_0, +, 1}_loop {j_0, +, 1}_loop
The addresses and their index are like:
|<- ADDR_A ->| |<- ADDR_B ->|
------------------------------------------------------->
| | | | | | | | | |
------------------------------------------------------->
i_0 ... i_0+4 j_0 ... j_0+4
We can create expression based on index rather than address:
(i_0 + 4 < j_0 || j_0 + 4 < i_0)
Note evolution step of index needs to be considered in comparison. */
static bool
create_intersect_range_checks_index (struct loop *loop, tree *cond_expr,
const dr_with_seg_len& dr_a,
const dr_with_seg_len& dr_b)
{
if (integer_zerop (DR_STEP (dr_a.dr))
|| integer_zerop (DR_STEP (dr_b.dr))
|| DR_NUM_DIMENSIONS (dr_a.dr) != DR_NUM_DIMENSIONS (dr_b.dr))
return false;
if (!tree_fits_uhwi_p (dr_a.seg_len) || !tree_fits_uhwi_p (dr_b.seg_len))
return false;
if (!tree_fits_shwi_p (DR_STEP (dr_a.dr)))
return false;
if (!operand_equal_p (DR_BASE_OBJECT (dr_a.dr), DR_BASE_OBJECT (dr_b.dr), 0))
return false;
if (!operand_equal_p (DR_STEP (dr_a.dr), DR_STEP (dr_b.dr), 0))
return false;
gcc_assert (TREE_CODE (DR_STEP (dr_a.dr)) == INTEGER_CST);
bool neg_step = tree_int_cst_compare (DR_STEP (dr_a.dr), size_zero_node) < 0;
unsigned HOST_WIDE_INT abs_step
= absu_hwi (tree_to_shwi (DR_STEP (dr_a.dr)));
unsigned HOST_WIDE_INT seg_len1 = tree_to_uhwi (dr_a.seg_len);
unsigned HOST_WIDE_INT seg_len2 = tree_to_uhwi (dr_b.seg_len);
/* Infer the number of iterations with which the memory segment is accessed
by DR. In other words, alias is checked if memory segment accessed by
DR_A in some iterations intersect with memory segment accessed by DR_B
in the same amount iterations.
Note segnment length is a linear function of number of iterations with
DR_STEP as the coefficient. */
unsigned HOST_WIDE_INT niter_len1 = (seg_len1 + abs_step - 1) / abs_step;
unsigned HOST_WIDE_INT niter_len2 = (seg_len2 + abs_step - 1) / abs_step;
unsigned int i;
for (i = 0; i < DR_NUM_DIMENSIONS (dr_a.dr); i++)
{
tree access1 = DR_ACCESS_FN (dr_a.dr, i);
tree access2 = DR_ACCESS_FN (dr_b.dr, i);
/* Two indices must be the same if they are not scev, or not scev wrto
current loop being vecorized. */
if (TREE_CODE (access1) != POLYNOMIAL_CHREC
|| TREE_CODE (access2) != POLYNOMIAL_CHREC
|| CHREC_VARIABLE (access1) != (unsigned)loop->num
|| CHREC_VARIABLE (access2) != (unsigned)loop->num)
{
if (operand_equal_p (access1, access2, 0))
continue;
return false;
}
/* The two indices must have the same step. */
if (!operand_equal_p (CHREC_RIGHT (access1), CHREC_RIGHT (access2), 0))
return false;
tree idx_step = CHREC_RIGHT (access1);
/* Index must have const step, otherwise DR_STEP won't be constant. */
gcc_assert (TREE_CODE (idx_step) == INTEGER_CST);
/* Index must evaluate in the same direction as DR. */
gcc_assert (!neg_step || tree_int_cst_sign_bit (idx_step) == 1);
tree min1 = CHREC_LEFT (access1);
tree min2 = CHREC_LEFT (access2);
if (!types_compatible_p (TREE_TYPE (min1), TREE_TYPE (min2)))
return false;
/* Ideally, alias can be checked against loop's control IV, but we
need to prove linear mapping between control IV and reference
index. Although that should be true, we check against (array)
index of data reference. Like segment length, index length is
linear function of the number of iterations with index_step as
the coefficient, i.e, niter_len * idx_step. */
tree idx_len1 = fold_build2 (MULT_EXPR, TREE_TYPE (min1), idx_step,
build_int_cst (TREE_TYPE (min1),
niter_len1));
tree idx_len2 = fold_build2 (MULT_EXPR, TREE_TYPE (min2), idx_step,
build_int_cst (TREE_TYPE (min2),
niter_len2));
tree max1 = fold_build2 (PLUS_EXPR, TREE_TYPE (min1), min1, idx_len1);
tree max2 = fold_build2 (PLUS_EXPR, TREE_TYPE (min2), min2, idx_len2);
/* Adjust ranges for negative step. */
if (neg_step)
{
min1 = fold_build2 (MINUS_EXPR, TREE_TYPE (min1), max1, idx_step);
max1 = fold_build2 (MINUS_EXPR, TREE_TYPE (min1),
CHREC_LEFT (access1), idx_step);
min2 = fold_build2 (MINUS_EXPR, TREE_TYPE (min2), max2, idx_step);
max2 = fold_build2 (MINUS_EXPR, TREE_TYPE (min2),
CHREC_LEFT (access2), idx_step);
}
tree part_cond_expr
= fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
fold_build2 (LE_EXPR, boolean_type_node, max1, min2),
fold_build2 (LE_EXPR, boolean_type_node, max2, min1));
if (*cond_expr)
*cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
*cond_expr, part_cond_expr);
else
*cond_expr = part_cond_expr;
}
return true;
}
/* Given two data references and segment lengths described by DR_A and DR_B,
create expression checking if the two addresses ranges intersect with
each other:
((DR_A_addr_0 + DR_A_segment_length_0) <= DR_B_addr_0)
|| (DR_B_addr_0 + DER_B_segment_length_0) <= DR_A_addr_0)) */
static void
create_intersect_range_checks (struct loop *loop, tree *cond_expr,
const dr_with_seg_len& dr_a,
const dr_with_seg_len& dr_b)
{
*cond_expr = NULL_TREE;
if (create_intersect_range_checks_index (loop, cond_expr, dr_a, dr_b))
return;
tree segment_length_a = dr_a.seg_len;
tree segment_length_b = dr_b.seg_len;
tree addr_base_a = DR_BASE_ADDRESS (dr_a.dr);
tree addr_base_b = DR_BASE_ADDRESS (dr_b.dr);
tree offset_a = DR_OFFSET (dr_a.dr), offset_b = DR_OFFSET (dr_b.dr);
offset_a = fold_build2 (PLUS_EXPR, TREE_TYPE (offset_a),
offset_a, DR_INIT (dr_a.dr));
offset_b = fold_build2 (PLUS_EXPR, TREE_TYPE (offset_b),
offset_b, DR_INIT (dr_b.dr));
addr_base_a = fold_build_pointer_plus (addr_base_a, offset_a);
addr_base_b = fold_build_pointer_plus (addr_base_b, offset_b);
tree seg_a_min = addr_base_a;
tree seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_a);
/* For negative step, we need to adjust address range by TYPE_SIZE_UNIT
bytes, e.g., int a[3] -> a[1] range is [a+4, a+16) instead of
[a, a+12) */
if (tree_int_cst_compare (DR_STEP (dr_a.dr), size_zero_node) < 0)
{
tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_a.dr)));
seg_a_min = fold_build_pointer_plus (seg_a_max, unit_size);
seg_a_max = fold_build_pointer_plus (addr_base_a, unit_size);
}
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)
{
tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_b.dr)));
seg_b_min = fold_build_pointer_plus (seg_b_max, unit_size);
seg_b_max = fold_build_pointer_plus (addr_base_b, unit_size);
}
*cond_expr
= fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
fold_build2 (LE_EXPR, boolean_type_node, seg_a_max, seg_b_min),
fold_build2 (LE_EXPR, boolean_type_node, seg_b_max, seg_a_min));
}
/* Create a conditional expression that represents the run-time checks for
overlapping of address ranges represented by a list of data references
pairs passed in ALIAS_PAIRS. Data references are in LOOP. 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. */
void
create_runtime_alias_checks (struct loop *loop,
vec<dr_with_seg_len_pair_t> *alias_pairs,
tree * cond_expr)
{
tree part_cond_expr;
for (size_t i = 0, s = alias_pairs->length (); i < s; ++i)
{
const dr_with_seg_len& dr_a = (*alias_pairs)[i].first;
const dr_with_seg_len& dr_b = (*alias_pairs)[i].second;
if (dump_enabled_p ())
{
dump_printf (MSG_NOTE, "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.dr));
dump_printf (MSG_NOTE, "\n");
}
/* Create condition expression for each pair data references. */
create_intersect_range_checks (loop, &part_cond_expr, dr_a, dr_b);
if (*cond_expr)
*cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
*cond_expr, part_cond_expr);
else
*cond_expr = part_cond_expr;
}
}
/* Check if OFFSET1 and OFFSET2 (DR_OFFSETs of some data-refs) are identical
expressions. */
static bool

View File

@ -371,6 +371,8 @@ extern bool dr_equal_offsets_p (struct data_reference *,
extern int data_ref_compare_tree (tree, tree);
extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
unsigned HOST_WIDE_INT);
extern void create_runtime_alias_checks (struct loop *,
vec<dr_with_seg_len_pair_t> *, tree*);
/* Return true when the base objects of data references A and B are
the same memory object. */

View File

@ -2044,194 +2044,6 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
*cond_expr = part_cond_expr;
}
/* Given LOOP's two data references and segment lengths described by DR_A
and DR_B, create expression checking if the two addresses ranges intersect
with each other based on index of the two addresses. This can only be
done if DR_A and DR_B referring to the same (array) object and the index
is the only difference. For example:
DR_A DR_B
data-ref arr[i] arr[j]
base_object arr arr
index {i_0, +, 1}_loop {j_0, +, 1}_loop
The addresses and their index are like:
|<- ADDR_A ->| |<- ADDR_B ->|
------------------------------------------------------->
| | | | | | | | | |
------------------------------------------------------->
i_0 ... i_0+4 j_0 ... j_0+4
We can create expression based on index rather than address:
(i_0 + 4 < j_0 || j_0 + 4 < i_0)
Note evolution step of index needs to be considered in comparison. */
static bool
create_intersect_range_checks_index (struct loop *loop, tree *cond_expr,
const dr_with_seg_len& dr_a,
const dr_with_seg_len& dr_b)
{
if (integer_zerop (DR_STEP (dr_a.dr))
|| integer_zerop (DR_STEP (dr_b.dr))
|| DR_NUM_DIMENSIONS (dr_a.dr) != DR_NUM_DIMENSIONS (dr_b.dr))
return false;
if (!tree_fits_uhwi_p (dr_a.seg_len) || !tree_fits_uhwi_p (dr_b.seg_len))
return false;
if (!tree_fits_shwi_p (DR_STEP (dr_a.dr)))
return false;
if (!operand_equal_p (DR_BASE_OBJECT (dr_a.dr), DR_BASE_OBJECT (dr_b.dr), 0))
return false;
if (!operand_equal_p (DR_STEP (dr_a.dr), DR_STEP (dr_b.dr), 0))
return false;
gcc_assert (TREE_CODE (DR_STEP (dr_a.dr)) == INTEGER_CST);
bool neg_step = tree_int_cst_compare (DR_STEP (dr_a.dr), size_zero_node) < 0;
unsigned HOST_WIDE_INT abs_step
= absu_hwi (tree_to_shwi (DR_STEP (dr_a.dr)));
unsigned HOST_WIDE_INT seg_len1 = tree_to_uhwi (dr_a.seg_len);
unsigned HOST_WIDE_INT seg_len2 = tree_to_uhwi (dr_b.seg_len);
/* Infer the number of iterations with which the memory segment is accessed
by DR. In other words, alias is checked if memory segment accessed by
DR_A in some iterations intersect with memory segment accessed by DR_B
in the same amount iterations.
Note segnment length is a linear function of number of iterations with
DR_STEP as the coefficient. */
unsigned HOST_WIDE_INT niter_len1 = (seg_len1 + abs_step - 1) / abs_step;
unsigned HOST_WIDE_INT niter_len2 = (seg_len2 + abs_step - 1) / abs_step;
unsigned int i;
for (i = 0; i < DR_NUM_DIMENSIONS (dr_a.dr); i++)
{
tree access1 = DR_ACCESS_FN (dr_a.dr, i);
tree access2 = DR_ACCESS_FN (dr_b.dr, i);
/* Two indices must be the same if they are not scev, or not scev wrto
current loop being vecorized. */
if (TREE_CODE (access1) != POLYNOMIAL_CHREC
|| TREE_CODE (access2) != POLYNOMIAL_CHREC
|| CHREC_VARIABLE (access1) != (unsigned)loop->num
|| CHREC_VARIABLE (access2) != (unsigned)loop->num)
{
if (operand_equal_p (access1, access2, 0))
continue;
return false;
}
/* The two indices must have the same step. */
if (!operand_equal_p (CHREC_RIGHT (access1), CHREC_RIGHT (access2), 0))
return false;
tree idx_step = CHREC_RIGHT (access1);
/* Index must have const step, otherwise DR_STEP won't be constant. */
gcc_assert (TREE_CODE (idx_step) == INTEGER_CST);
/* Index must evaluate in the same direction as DR. */
gcc_assert (!neg_step || tree_int_cst_sign_bit (idx_step) == 1);
tree min1 = CHREC_LEFT (access1);
tree min2 = CHREC_LEFT (access2);
if (!types_compatible_p (TREE_TYPE (min1), TREE_TYPE (min2)))
return false;
/* Ideally, alias can be checked against loop's control IV, but we
need to prove linear mapping between control IV and reference
index. Although that should be true, we check against (array)
index of data reference. Like segment length, index length is
linear function of the number of iterations with index_step as
the coefficient, i.e, niter_len * idx_step. */
tree idx_len1 = fold_build2 (MULT_EXPR, TREE_TYPE (min1), idx_step,
build_int_cst (TREE_TYPE (min1),
niter_len1));
tree idx_len2 = fold_build2 (MULT_EXPR, TREE_TYPE (min2), idx_step,
build_int_cst (TREE_TYPE (min2),
niter_len2));
tree max1 = fold_build2 (PLUS_EXPR, TREE_TYPE (min1), min1, idx_len1);
tree max2 = fold_build2 (PLUS_EXPR, TREE_TYPE (min2), min2, idx_len2);
/* Adjust ranges for negative step. */
if (neg_step)
{
min1 = fold_build2 (MINUS_EXPR, TREE_TYPE (min1), max1, idx_step);
max1 = fold_build2 (MINUS_EXPR, TREE_TYPE (min1),
CHREC_LEFT (access1), idx_step);
min2 = fold_build2 (MINUS_EXPR, TREE_TYPE (min2), max2, idx_step);
max2 = fold_build2 (MINUS_EXPR, TREE_TYPE (min2),
CHREC_LEFT (access2), idx_step);
}
tree part_cond_expr
= fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
fold_build2 (LE_EXPR, boolean_type_node, max1, min2),
fold_build2 (LE_EXPR, boolean_type_node, max2, min1));
if (*cond_expr)
*cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
*cond_expr, part_cond_expr);
else
*cond_expr = part_cond_expr;
}
return true;
}
/* Given two data references and segment lengths described by DR_A and DR_B,
create expression checking if the two addresses ranges intersect with
each other:
((DR_A_addr_0 + DR_A_segment_length_0) <= DR_B_addr_0)
|| (DR_B_addr_0 + DER_B_segment_length_0) <= DR_A_addr_0)) */
static void
create_intersect_range_checks (struct loop *loop, tree *cond_expr,
const dr_with_seg_len& dr_a,
const dr_with_seg_len& dr_b)
{
*cond_expr = NULL_TREE;
if (create_intersect_range_checks_index (loop, cond_expr, dr_a, dr_b))
return;
tree segment_length_a = dr_a.seg_len;
tree segment_length_b = dr_b.seg_len;
tree addr_base_a = DR_BASE_ADDRESS (dr_a.dr);
tree addr_base_b = DR_BASE_ADDRESS (dr_b.dr);
tree offset_a = DR_OFFSET (dr_a.dr), offset_b = DR_OFFSET (dr_b.dr);
offset_a = fold_build2 (PLUS_EXPR, TREE_TYPE (offset_a),
offset_a, DR_INIT (dr_a.dr));
offset_b = fold_build2 (PLUS_EXPR, TREE_TYPE (offset_b),
offset_b, DR_INIT (dr_b.dr));
addr_base_a = fold_build_pointer_plus (addr_base_a, offset_a);
addr_base_b = fold_build_pointer_plus (addr_base_b, offset_b);
tree seg_a_min = addr_base_a;
tree seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_a);
/* For negative step, we need to adjust address range by TYPE_SIZE_UNIT
bytes, e.g., int a[3] -> a[1] range is [a+4, a+16) instead of
[a, a+12) */
if (tree_int_cst_compare (DR_STEP (dr_a.dr), size_zero_node) < 0)
{
tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_a.dr)));
seg_a_min = fold_build_pointer_plus (seg_a_max, unit_size);
seg_a_max = fold_build_pointer_plus (addr_base_a, unit_size);
}
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)
{
tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_b.dr)));
seg_b_min = fold_build_pointer_plus (seg_b_max, unit_size);
seg_b_max = fold_build_pointer_plus (addr_base_b, unit_size);
}
*cond_expr
= fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
fold_build2 (LE_EXPR, boolean_type_node, seg_a_max, seg_b_min),
fold_build2 (LE_EXPR, boolean_type_node, seg_b_max, seg_a_min));
}
/* Function vect_create_cond_for_alias_checks.
Create a conditional expression that represents the run-time checks for
@ -2257,36 +2069,12 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
{
vec<dr_with_seg_len_pair_t> comp_alias_ddrs =
LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo);
tree part_cond_expr;
if (comp_alias_ddrs.is_empty ())
return;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
for (size_t i = 0, s = comp_alias_ddrs.length (); i < s; ++i)
{
const dr_with_seg_len& dr_a = comp_alias_ddrs[i].first;
const dr_with_seg_len& dr_b = comp_alias_ddrs[i].second;
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.dr));
dump_printf (MSG_NOTE, " and ");
dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_b.dr));
dump_printf (MSG_NOTE, "\n");
}
/* Create condition expression for each pair data references. */
create_intersect_range_checks (loop, &part_cond_expr, dr_a, dr_b);
if (*cond_expr)
*cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
*cond_expr, part_cond_expr);
else
*cond_expr = part_cond_expr;
}
create_runtime_alias_checks (LOOP_VINFO_LOOP (loop_vinfo),
&comp_alias_ddrs, cond_expr);
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"created %u versioning for alias checks.\n",