Commit 822f18cd by Bin Cheng Committed by Bin Cheng

tree-vect-loop-manip.c (create_intersect_range_checks_index): New.

	* tree-vect-loop-manip.c (create_intersect_range_checks_index): New.
	(create_intersect_range_checks): New.
	(vect_create_cond_for_alias_checks): Call above function.

From-SVN: r240412
parent d403b8d4
2016-09-23 Bin Cheng <bin.cheng@arm.com>
* tree-vect-loop-manip.c (create_intersect_range_checks_index): New.
(create_intersect_range_checks): New.
(vect_create_cond_for_alias_checks): Call above function.
2016-09-23 Matthew Wahab <matthew.wahab@arm.com> 2016-09-23 Matthew Wahab <matthew.wahab@arm.com>
* config/arm/iterators.md (Code iterators): Fix some white-space * config/arm/iterators.md (Code iterators): Fix some white-space
......
...@@ -2263,49 +2263,155 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo, ...@@ -2263,49 +2263,155 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo,
*cond_expr = part_cond_expr; *cond_expr = part_cond_expr;
} }
/* Function vect_create_cond_for_alias_checks. /* 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 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:
Create a conditional expression that represents the run-time checks for DR_A DR_B
overlapping of address ranges represented by a list of data references data-ref arr[i] arr[j]
relations passed as input. base_object arr arr
index {i_0, +, 1}_loop {j_0, +, 1}_loop
Input: The addresses and their index are like:
COND_EXPR - input conditional expression. New conditions will be chained
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: |<- ADDR_A ->| |<- ADDR_B ->|
COND_EXPR - conditional expression. ------------------------------------------------------->
| | | | | | | | | |
------------------------------------------------------->
i_0 ... i_0+4 j_0 ... j_0+4
The returned COND_EXPR is the conditional expression to be used in the if We can create expression based on index rather than address:
statement that controls which version of the loop gets executed at runtime.
*/
void (i_0 + 4 < j_0 || j_0 + 4 < i_0)
vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
Note evolution step of index needs to be considered in comparison. */
static bool
create_intersect_range_checks_index (loop_vec_info loop_vinfo, tree *cond_expr,
const dr_with_seg_len& dr_a,
const dr_with_seg_len& dr_b)
{ {
vec<dr_with_seg_len_pair_t> comp_alias_ddrs = if (integer_zerop (DR_STEP (dr_a.dr))
LOOP_VINFO_COMP_ALIAS_DDRS (loop_vinfo); || integer_zerop (DR_STEP (dr_b.dr))
tree part_cond_expr; || DR_NUM_DIMENSIONS (dr_a.dr) != DR_NUM_DIMENSIONS (dr_b.dr))
return false;
/* Create expression if (!tree_fits_uhwi_p (dr_a.seg_len) || !tree_fits_uhwi_p (dr_b.seg_len))
((store_ptr_0 + store_segment_length_0) <= load_ptr_0) return false;
|| (load_ptr_0 + load_segment_length_0) <= store_ptr_0))
&&
...
&&
((store_ptr_n + store_segment_length_n) <= load_ptr_n)
|| (load_ptr_n + load_segment_length_n) <= store_ptr_n)) */
if (comp_alias_ddrs.is_empty ()) 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 = tree_to_uhwi (DR_STEP (dr_a.dr));
if (neg_step)
abs_step = -abs_step;
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;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
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 index 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;
}
/* Two index 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_compare (idx_step, size_zero_node) < 0);
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 (loop_vec_info loop_vinfo, 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_vinfo, cond_expr, dr_a, dr_b))
return; return;
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;
tree segment_length_a = dr_a.seg_len; tree segment_length_a = dr_a.seg_len;
tree segment_length_b = dr_b.seg_len; tree segment_length_b = dr_b.seg_len;
tree addr_base_a = DR_BASE_ADDRESS (dr_a.dr); tree addr_base_a = DR_BASE_ADDRESS (dr_a.dr);
...@@ -2319,16 +2425,6 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr) ...@@ -2319,16 +2425,6 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
addr_base_a = fold_build_pointer_plus (addr_base_a, offset_a); addr_base_a = fold_build_pointer_plus (addr_base_a, offset_a);
addr_base_b = fold_build_pointer_plus (addr_base_b, offset_b); addr_base_b = fold_build_pointer_plus (addr_base_b, offset_b);
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");
}
tree seg_a_min = addr_base_a; tree seg_a_min = addr_base_a;
tree seg_a_max = fold_build_pointer_plus (addr_base_a, segment_length_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 /* For negative step, we need to adjust address range by TYPE_SIZE_UNIT
...@@ -2349,12 +2445,59 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr) ...@@ -2349,12 +2445,59 @@ vect_create_cond_for_alias_checks (loop_vec_info loop_vinfo, tree * cond_expr)
seg_b_min = fold_build_pointer_plus (seg_b_max, unit_size); seg_b_min = fold_build_pointer_plus (seg_b_max, unit_size);
seg_b_max = fold_build_pointer_plus (addr_base_b, unit_size); seg_b_max = fold_build_pointer_plus (addr_base_b, unit_size);
} }
*cond_expr
part_cond_expr = = fold_build2 (TRUTH_OR_EXPR, boolean_type_node,
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_a_max, seg_b_min),
fold_build2 (LE_EXPR, boolean_type_node, seg_b_max, seg_a_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
overlapping of address ranges represented by a list of data references
relations passed as input.
Input:
COND_EXPR - input conditional expression. New conditions will be chained
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 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
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;
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_vinfo, &part_cond_expr, dr_a, dr_b);
if (*cond_expr) if (*cond_expr)
*cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, *cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
*cond_expr, part_cond_expr); *cond_expr, part_cond_expr);
......
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