Hi,
This patch fixes PR80815 in which negative DR_STEP is mis-handled. It does
below:
1) Reorder three cases in which we merge alias checks, in order like:
old_case_A -> new_case_B
old_case_B -> new_case_C (and removed as described in 3))
old_case_C -> new_case_A
This is because new_case_1 is accurate check that doesn't introduce false
alias,
while the other two does.
2) Explicitly comment that Case A and B combined together can merge all
dr_a1&dr_b and
dr_a2&dr_b pairs if SEGMENT_LEN_A is constant. We still keep Case A/B
separately
for clarity, also because Case A doesn't introduces false alias, while B
does.
3) Remove the old_case_C:
/* Generally the new segment length is the maximum of the
left segment size and the right segment size plus the distance.
??? We can also build tree MAX_EXPR here but it's not clear this
is profitable. */
else if (tree_fits_uhwi_p (dr_a1->seg_len)
&& tree_fits_uhwi_p (dr_a2->seg_len))
This check is actually covered by A and B.
4) Handle negative DR_STEPs explicitly.
5) Add two tests illustrating wrong alias checking issue.
Bootstrap and test on x86_64 and AArch64, is it OK?
BTW, I tried to keep the change as minimal as possible, but ended up with quite
amount refactoring because the old cases are somehow duplicated/complicated,
and not fit to negative DR_STEPs handling.
Thanks,
bin
2017-05-22 Bin Cheng <bin.ch...@arm.com>
PR tree-optimization/80815
* tree-data-ref.c (prune_runtime_alias_test_list): Simplify condition
for merging runtime alias checks. Handle negative DR_STEPs.
gcc/testsuite/ChangeLog
2017-05-22 Bin Cheng <bin.ch...@arm.com>
PR tree-optimization/80815
* gcc.dg/vect/pr80815-1.c: New test.
* gcc.dg/vect/pr80815-2.c: New test.
From af1dda073f8bd1a371cd1207fcaf467be0dc1106 Mon Sep 17 00:00:00 2001
From: Bin Cheng <binch...@e108451-lin.cambridge.arm.com>
Date: Fri, 19 May 2017 18:46:14 +0100
Subject: [PATCH 3/6] negative-step-alias-check-20170516.txt
---
gcc/testsuite/gcc.dg/vect/pr80815-1.c | 38 ++++++++++
gcc/testsuite/gcc.dg/vect/pr80815-2.c | 46 ++++++++++++
gcc/tree-data-ref.c | 131 +++++++++++++++++++++++-----------
3 files changed, 175 insertions(+), 40 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/vect/pr80815-1.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr80815-2.c
diff --git a/gcc/testsuite/gcc.dg/vect/pr80815-1.c
b/gcc/testsuite/gcc.dg/vect/pr80815-1.c
new file mode 100644
index 0000000..98c06c0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr80815-1.c
@@ -0,0 +1,38 @@
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+int arr[2048];
+
+__attribute__ ((noinline)) int
+foo (int *a, int *b)
+{
+ int i;
+ int *a1 = a;
+ int *a0 = a1 - 512;
+ for (i = 0; i < 500; i++)
+ {
+ *b = *a0 + *a1;
+ b++;
+ a0--;
+ a1--;
+ }
+ return 0;
+}
+
+int main (void)
+{
+ int *a = &arr[1027];
+ int *b = &arr[1024];
+
+ int i;
+ for (i = 0; i < 2048; i++)
+ arr[i] = i;
+
+ foo (a, b);
+
+ if (arr[1026] != 2053 || arr[1027] != 2054)
+ abort ();
+
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vect/pr80815-2.c
b/gcc/testsuite/gcc.dg/vect/pr80815-2.c
new file mode 100644
index 0000000..83557da
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr80815-2.c
@@ -0,0 +1,46 @@
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+int arr[2048];
+int res[100] = { 13198, 13224, 12735, 12760, 12270, 12294,
+ 11803, 11826, 11334, 11356, 10863, 10884,
+ 10390, 10410, 9915, 9934, 9438, 9456,
+ 8959, 8976, 8478, 8494, 7995, 8010,
+ 7510, 7524, 7023, 7036, 6534, 6546,
+ 6043, 6054, 5550, 5560, 5055, 5064,
+ 4558, 4566, 4059, 4066, 3558, 3564,
+ 3055, 3060, 2550, 2554, 2043, 0};
+
+__attribute__ ((noinline)) int
+foo (int *a, int *b)
+{
+ int i;
+ int *a1 = a;
+ int *a0 = a1 - 512;
+ for (i = 0; i < 50; i++)
+ {
+ *b = *a0 + *a1;
+ b--;
+ a0--;
+ a1--;
+ }
+ return 0;
+}
+
+int main (void)
+{
+ int *a = &arr[1024];
+ int *b = &arr[1022];
+
+ int i;
+ for (i = 0; i < 2048; i++)
+ arr[i] = i;
+
+ foo (a, b);
+
+ for (i = 973; i < 1020; i++)
+ if (arr[i] != res[i - 973])
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index a5f8c1c..f0799d9 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -1259,6 +1259,15 @@ prune_runtime_alias_test_list
(vec<dr_with_seg_len_pair_t> *alias_pairs,
!= tree_int_cst_compare (DR_STEP (dr_a2->dr), size_zero_node))
continue;
+ bool neg_step
+ = (tree_int_cst_compare (DR_STEP (dr_a1->dr), size_zero_node) < 0);
+
+ /* DR_A1 and DR_A2 must have the same step if it's negative. */
+ if (neg_step
+ && tree_int_cst_compare (DR_STEP (dr_a1->dr),
+ DR_STEP (dr_a2->dr)) != 0)
+ continue;
+
/* Make sure dr_a1 starts left of dr_a2. */
if (tree_int_cst_lt (DR_INIT (dr_a2->dr), DR_INIT (dr_a1->dr)))
std::swap (*dr_a1, *dr_a2);
@@ -1266,60 +1275,101 @@ prune_runtime_alias_test_list
(vec<dr_with_seg_len_pair_t> *alias_pairs,
bool do_remove = false;
unsigned HOST_WIDE_INT diff
= (tree_to_shwi (DR_INIT (dr_a2->dr))
- - tree_to_shwi (DR_INIT (dr_a1->dr)));
+ - tree_to_shwi (DR_INIT (dr_a1->dr)));
+ tree new_seg_len;
+ unsigned HOST_WIDE_INT min_seg_len_b;
- /* If the left segment does not extend beyond the start of the
- right segment the new segment length is that of the right
- plus the segment distance. */
- if (tree_fits_uhwi_p (dr_a1->seg_len)
- && compare_tree_int (dr_a1->seg_len, diff) <= 0)
+ if (tree_fits_uhwi_p (dr_b1->seg_len))
{
- dr_a1->seg_len = size_binop (PLUS_EXPR, dr_a2->seg_len,
- size_int (diff));
- do_remove = true;
+ min_seg_len_b = tree_to_uhwi (dr_b1->seg_len);
+ if (tree_int_cst_sign_bit (dr_b1->seg_len))
+ min_seg_len_b = 0 - min_seg_len_b;
}
- /* Generally the new segment length is the maximum of the
- left segment size and the right segment size plus the distance.
- ??? We can also build tree MAX_EXPR here but it's not clear this
- is profitable. */
- else if (tree_fits_uhwi_p (dr_a1->seg_len)
- && tree_fits_uhwi_p (dr_a2->seg_len))
- {
- unsigned HOST_WIDE_INT seg_len_a1 = tree_to_uhwi (dr_a1->seg_len);
- unsigned HOST_WIDE_INT seg_len_a2 = tree_to_uhwi (dr_a2->seg_len);
- dr_a1->seg_len = size_int (MAX (seg_len_a1, diff + seg_len_a2));
- do_remove = true;
- }
- /* Now we check if the following condition is satisfied:
+ else
+ min_seg_len_b = factor;
- DIFF - SEGMENT_LENGTH_A < SEGMENT_LENGTH_B
+ /* Now we try to merge alias check dr_a1 & dr_b and dr_a2 & dr_b.
- where DIFF = DR_A2_INIT - DR_A1_INIT. 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:
+ Case A:
+ check if the following condition is satisfied:
- 1: DIFF <= MIN_SEG_LEN_B
- 2: DIFF - SEGMENT_LENGTH_A < MIN_SEG_LEN_B */
- else
+ DIFF - SEGMENT_LENGTH_A < SEGMENT_LENGTH_B
+
+ where DIFF = DR_A2_INIT - DR_A1_INIT. 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
+ Because DIFF - SEGMENT_LENGTH_A is done in sizetype, we need
+ to take care of wrapping behavior in it.
+
+ Case B:
+ If the left segment does not extend beyond the start of the
+ right segment the new segment length is that of the right
+ plus the segment distance.
+
+ Note 1: Case A.2 and B combined together effectively merges every
+ dr_a1 & dr_b and dr_a2 & dr_b when SEGMENT_LENGTH_A is const. We
+ test them separately for clarity, also because Case A never
+ introduces false alias, while Case B does.
+
+ Note 2: Above description is based on positive DR_STEP, we need to
+ take care of negative DR_STEP for wrapping behavior. See PR80815
+ for more information. */
+ if (neg_step)
{
- unsigned HOST_WIDE_INT min_seg_len_b
- = (tree_fits_uhwi_p (dr_b1->seg_len)
- ? tree_to_uhwi (dr_b1->seg_len)
- : factor);
+ /* Case A. */
+ if (diff <= min_seg_len_b
+ || (tree_fits_uhwi_p (dr_a1->seg_len)
+ && (diff + tree_to_uhwi (dr_a1->seg_len) < min_seg_len_b
+ || diff < 0 - tree_to_uhwi (dr_a1->seg_len)))
+ /* Case B. */
+ || (tree_fits_uhwi_p (dr_a1->seg_len)
+ && diff > 0 - tree_to_uhwi (dr_a1->seg_len)))
+ {
+ if (tree_fits_uhwi_p (dr_a1->seg_len)
+ && tree_fits_uhwi_p (dr_a2->seg_len))
+ new_seg_len
+ = size_int (MIN (tree_to_uhwi (dr_a1->seg_len),
+ tree_to_uhwi (dr_a2->seg_len) - diff));
+ else
+ new_seg_len = size_binop (MINUS_EXPR,
+ dr_a2->seg_len, size_int (diff));
+ dr_a2->seg_len = new_seg_len;
+ do_remove = true;
+ }
+ }
+ else
+ {
+ /* Case A. */
if (diff <= min_seg_len_b
|| (tree_fits_uhwi_p (dr_a1->seg_len)
- && diff - tree_to_uhwi (dr_a1->seg_len) < min_seg_len_b))
+ && (diff - tree_to_uhwi (dr_a1->seg_len) < min_seg_len_b
+ || diff < tree_to_uhwi (dr_a1->seg_len)))
+ /* Case B. */
+ || (tree_fits_uhwi_p (dr_a1->seg_len)
+ && diff > tree_to_uhwi (dr_a1->seg_len)))
{
- dr_a1->seg_len = size_binop (PLUS_EXPR,
- dr_a2->seg_len, size_int (diff));
+ if (tree_fits_uhwi_p (dr_a1->seg_len)
+ && tree_fits_uhwi_p (dr_a2->seg_len))
+ new_seg_len
+ = size_int (MAX (tree_to_uhwi (dr_a1->seg_len),
+ diff + tree_to_uhwi (dr_a2->seg_len)));
+ else
+ new_seg_len
+ = size_binop (PLUS_EXPR, dr_a2->seg_len, size_int (diff));
+
+ dr_a1->seg_len = new_seg_len;
do_remove = true;
}
}
+
if (do_remove)
{
if (dump_enabled_p ())
@@ -1334,7 +1384,8 @@ prune_runtime_alias_test_list
(vec<dr_with_seg_len_pair_t> *alias_pairs,
dump_generic_expr (MSG_NOTE, TDF_SLIM, DR_REF (dr_b2->dr));
dump_printf (MSG_NOTE, "\n");
}
- alias_pairs->ordered_remove (i--);
+ alias_pairs->ordered_remove (neg_step ? i - 1 : i);
+ i--;
}
}
}
--
1.9.1