(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
+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
}
}
+/* 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
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. */
*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
{
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",