return segment_length;
}
+/* Function vect_no_alias_p.
+
+ Given data references A and B with equal base and offset, the alias
+ relation can be decided at compilation time, return TRUE if they do
+ not alias to each other; return FALSE otherwise. SEGMENT_LENGTH_A
+ and SEGMENT_LENGTH_B are the memory lengths accessed by A and B
+ respectively. */
+
+static bool
+vect_no_alias_p (struct data_reference *a, struct data_reference *b,
+ tree segment_length_a, tree segment_length_b)
+{
+ gcc_assert (TREE_CODE (DR_INIT (a)) == INTEGER_CST
+ && TREE_CODE (DR_INIT (b)) == INTEGER_CST);
+ if (tree_int_cst_equal (DR_INIT (a), DR_INIT (b)))
+ return false;
+
+ tree seg_a_min = DR_INIT (a);
+ tree seg_a_max = fold_build2 (PLUS_EXPR, TREE_TYPE (seg_a_min),
+ seg_a_min, 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 (a), size_zero_node) < 0)
+ {
+ tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (a)));
+ seg_a_min = fold_build2 (PLUS_EXPR, TREE_TYPE (seg_a_max),
+ seg_a_max, unit_size);
+ seg_a_max = fold_build2 (PLUS_EXPR, TREE_TYPE (DR_INIT (a)),
+ DR_INIT (a), unit_size);
+ }
+ tree seg_b_min = DR_INIT (b);
+ tree seg_b_max = fold_build2 (PLUS_EXPR, TREE_TYPE (seg_b_min),
+ seg_b_min, segment_length_b);
+ if (tree_int_cst_compare (DR_STEP (b), size_zero_node) < 0)
+ {
+ tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (b)));
+ seg_b_min = fold_build2 (PLUS_EXPR, TREE_TYPE (seg_b_max),
+ seg_b_max, unit_size);
+ seg_b_max = fold_build2 (PLUS_EXPR, TREE_TYPE (DR_INIT (b)),
+ DR_INIT (b), unit_size);
+ }
+
+ if (tree_int_cst_le (seg_a_max, seg_b_min)
+ || tree_int_cst_le (seg_b_max, seg_a_min))
+ return true;
+
+ return false;
+}
+
/* Function vect_prune_runtime_alias_test_list.
Prune a list of ddrs to be tested at run-time by versioning for alias.
segment_length_a = vect_vfa_segment_size (dr_a, length_factor);
segment_length_b = vect_vfa_segment_size (dr_b, length_factor);
+ comp_res = compare_tree (DR_BASE_ADDRESS (dr_a), DR_BASE_ADDRESS (dr_b));
+ if (comp_res == 0)
+ comp_res = compare_tree (DR_OFFSET (dr_a), DR_OFFSET (dr_b));
+
+ /* Alias is known at compilation time. */
+ if (comp_res == 0
+ && TREE_CODE (DR_STEP (dr_a)) == INTEGER_CST
+ && TREE_CODE (DR_STEP (dr_b)) == INTEGER_CST
+ && TREE_CODE (segment_length_a) == INTEGER_CST
+ && TREE_CODE (segment_length_b) == INTEGER_CST)
+ {
+ if (vect_no_alias_p (dr_a, dr_b, segment_length_a, segment_length_b))
+ continue;
+
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "not vectorized: compilation time alias.\n");
+
+ return false;
+ }
+
dr_with_seg_len_pair_t dr_with_seg_len_pair
(dr_with_seg_len (dr_a, segment_length_a),
dr_with_seg_len (dr_b, segment_length_b));
/* Canonicalize pairs by sorting the two DR members. */
- comp_res = compare_tree (DR_BASE_ADDRESS (dr_a), DR_BASE_ADDRESS (dr_b));
- if (comp_res > 0
- || (comp_res == 0
- && compare_tree (DR_OFFSET (dr_a), DR_OFFSET (dr_b)) > 0))
+ if (comp_res > 0)
std::swap (dr_with_seg_len_pair.first, dr_with_seg_len_pair.second);
comp_alias_ddrs.safe_push (dr_with_seg_len_pair);
may_alias_ddrs.length (), comp_alias_ddrs.length ());
if ((int) comp_alias_ddrs.length () >
PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
- return false;
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "number of versioning for alias "
+ "run-time tests exceeds %d "
+ "(--param vect-max-version-for-alias-checks)\n",
+ PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
+ return false;
+ }
+
+ /* All alias checks have been resolved at compilation time. */
+ if (!comp_alias_ddrs.length ())
+ LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).truncate (0);
return true;
}