[gcc(refs/users/guojiufu/heads/guojiufu-branch)] Support 1/-1 as step, and add test cases.
Jiu Fu Guo
guojiufu@gcc.gnu.org
Wed Jun 9 11:19:51 GMT 2021
https://gcc.gnu.org/g:305895dda86c574952345ffe7f26f2284d953c0a
commit 305895dda86c574952345ffe7f26f2284d953c0a
Author: Jiufu Guo <guojiufu@linux.ibm.com>
Date: Wed Jun 9 17:32:57 2021 +0800
Support 1/-1 as step, and add test cases.
Diff:
---
gcc/testsuite/gcc.dg/loop-split2.c | 107 +++++++++++++++++++++++++++++++++++--
gcc/testsuite/gcc.dg/loop-split3.c | 62 +++++++++++++++++++++
gcc/tree-ssa-loop-split.c | 30 ++++++-----
3 files changed, 182 insertions(+), 17 deletions(-)
diff --git a/gcc/testsuite/gcc.dg/loop-split2.c b/gcc/testsuite/gcc.dg/loop-split2.c
index 0d3fded3f61..1c7fd1bede1 100644
--- a/gcc/testsuite/gcc.dg/loop-split2.c
+++ b/gcc/testsuite/gcc.dg/loop-split2.c
@@ -3,6 +3,7 @@
extern void abort (void);
extern void exit (int);
+void push (int);
#define NI __attribute__ ((noinline))
@@ -17,38 +18,134 @@ unsigned NI
bar (int *a, int *b, unsigned char l, unsigned char n)
{
while (l++ != n)
- if (a[l] != b[l])
- break;
+ {
+ push (l);
+ if (a[l] != b[l])
+ break;
+ push (l+1);
+ }
+ return l;
+}
+
+void NI
+foo_1 (int *a, int *b, unsigned char l, unsigned char n)
+{
+ while (--l != n)
+ a[l] = b[l] + 1;
+}
+
+unsigned NI
+bar_1 (int *a, int *b, unsigned char l, unsigned char n)
+{
+ while (l-- != n)
+ {
+ push (l);
+ if (a[l] != b[l])
+ break;
+ push (l+1);
+ }
return l;
}
int a[258];
int b[258];
+int c[1024];
+static int top = 0;
+void push (int e)
+{
+ c[top++] = e;
+}
+
+void reset ()
+{
+ top = 0;
+ __builtin_memset (c, 0, sizeof (c));
+}
-int main()
+#define check(a, b) (b == -1 || a == b)
+
+int
+check_c (int *c, int a0, int a1, int a2, int a3, int a4, int a5)
+{
+ return check (c[0], a0) && check (c[1], a1) && check (c[2], a2)
+ && check (c[3], a3) && check (c[4], a4) && check (c[5], a5);
+}
+
+int main ()
{
__builtin_memcpy (b, a, sizeof (a));
+ reset ();
+ if (bar (a, b, 6, 8) != 9 || !check_c (c, 7, 8, 8, 9, 0, 0))
+ abort ();
- if (bar (a, b, 3, 8) != 9)
+ reset ();
+ if (bar (a, b, 5, 3) != 4 || !check_c (c, 6, 7, 7, 8, 8, 9)
+ || !check_c (c + 496, 254, 255, 255, 256, 0, 1))
abort ();
- if (bar (a, b, 8, 3) != 4)
+ reset ();
+ if (bar (a, b, 6, 6) != 7 || !check_c (c, 0, 0, 0, 0, 0, 0))
abort ();
+ reset ();
+ if (bar (a, b, 253, 255) != 0 || !check_c (c, 254, 255, 255, 256,-1,-1))
+ abort ();
+
+ reset ();
+ if (bar (a, b, 253, 0) != 1 || !check_c (c, 254, 255, 255, 256, 0, 1))
+ abort ();
+
+ reset ();
+ if (bar_1 (a, b, 6, 8) != 7 || !check_c (c, 5, 6, 4, 5, 3, 4))
+ abort ();
+
+ reset ();
+ if (bar_1 (a, b, 5, 3) != 2 || !check_c (c, 4, 5, 3, 4,-1,-1 ))
+ abort ();
+
+ reset ();
+ if (bar_1 (a, b, 6, 6) != 5)
+ abort ();
+
+ reset ();
+ if (bar_1 (a, b, 2, 255) != 254 || !check_c (c, 1, 2, 0, 1, 255, 256))
+ abort ();
+
+ reset ();
+ if (bar_1 (a, b, 2, 0) != 255 || !check_c (c, 1, 2, 0, 1, 0, 0))
+ abort ();
+
+
b[100] += 1;
+ reset ();
if (bar (a, b, 90, 110) != 100)
abort ();
+ reset ();
if (bar (a, b, 110, 105) != 100)
abort ();
+ reset ();
+ if (bar_1 (a, b, 90, 110) != 109)
+ abort ();
+
+ reset ();
+ if (bar_1 (a, b, 2, 90) != 100)
+ abort ();
+
foo (a, b, 99, 99);
a[99] = b[99] + 1;
for (int i = 0; i < 256; i++)
if (a[i] != b[i] + 1)
abort();
+ foo_1 (a, b, 99, 99);
+ a[99] = b[99] + 1;
+ for (int i = 0; i < 256; i++)
+ if (a[i] != b[i] + 1)
+ abort();
+
exit (0);
}
diff --git a/gcc/testsuite/gcc.dg/loop-split3.c b/gcc/testsuite/gcc.dg/loop-split3.c
new file mode 100644
index 00000000000..ec93ee8bd12
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-split3.c
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fsplit-loops -fdump-tree-lsplit-details" } */
+
+void
+foo (int *a, int *b, unsigned l, unsigned n)
+{
+ while (--l != n)
+ a[l] = b[l] + 1;
+}
+
+void
+foo1 (int *a, int *b, unsigned l, unsigned n)
+{
+ while (l-- != n)
+ a[l] = b[l] + 1;
+}
+
+unsigned
+foo2 (char *a, char *b, unsigned l, unsigned n)
+{
+ while (--l != n)
+ if (a[l] != b[l])
+ break;
+
+ return l;
+}
+
+unsigned
+foo3 (char *a, char *b, unsigned l, unsigned n)
+{
+ while (l-- != n)
+ if (a[l] != b[l])
+ break;
+
+ return l;
+}
+
+void
+bar ();
+void
+foo4 (unsigned n, unsigned i)
+{
+ do
+ {
+ if (i == n)
+ return;
+ bar ();
+ --i;
+ }
+ while (1);
+}
+
+unsigned
+find_skip_diff (char *p, char *q, unsigned n, unsigned i)
+{
+ while (p[i] == q[i] && --i != n)
+ p--, q--;
+
+ return i;
+}
+
+/* { dg-final { scan-tree-dump-times "Loop split" 6 "lsplit" } } */
diff --git a/gcc/tree-ssa-loop-split.c b/gcc/tree-ssa-loop-split.c
index ca35eee21b7..0365b6d069e 100644
--- a/gcc/tree-ssa-loop-split.c
+++ b/gcc/tree-ssa-loop-split.c
@@ -1602,7 +1602,7 @@ split_loop_on_cond (struct loop *loop)
Return the branch edge which exit loop, if wrap may happen on "idx". */
static edge
-get_ne_cond_branch (struct loop *loop)
+get_ne_cond_branch (struct loop *loop, tree *step)
{
int i;
edge e;
@@ -1638,9 +1638,8 @@ get_ne_cond_branch (struct loop *loop)
/* Avoid to split if bound is MAX/MIN val. */
tree bound_type = TREE_TYPE (bnd);
- if (TREE_CODE (bnd) == INTEGER_CST && INTEGRAL_TYPE_P (bound_type)
- && (tree_int_cst_equal (bnd, TYPE_MAX_VALUE (bound_type))
- || tree_int_cst_equal (bnd, TYPE_MIN_VALUE (bound_type))))
+ if (tree_int_cst_equal (bnd, TYPE_MAX_VALUE (bound_type))
+ || tree_int_cst_equal (bnd, TYPE_MIN_VALUE (bound_type)))
continue;
/* Check if there is possible wrap. */
@@ -1651,6 +1650,10 @@ get_ne_cond_branch (struct loop *loop)
return NULL;
if (niter.cmp != NE_EXPR)
continue;
+ if (!integer_onep (niter.control.step)
+ && !integer_minus_onep (niter.control.step))
+ continue;
+ *step = niter.control.step;
/* If exit edge is just before the empty latch, it is easy to link
the split loops: just jump from the exit edge of one loop to the
@@ -1701,7 +1704,7 @@ get_ne_cond_branch (struct loop *loop)
/* Split the LOOP with NE_EXPR into two loops with GT_EXPR and LT_EXPR. */
static bool
-split_ne_loop (struct loop *loop, edge cond_e)
+split_ne_loop (struct loop *loop, edge cond_e, tree step)
{
initialize_original_copy_tables ();
@@ -1740,11 +1743,13 @@ split_ne_loop (struct loop *loop, edge cond_e)
/* Change if (i != n) to LOOP1:if (i > n) and LOOP2:if (i < n) */
bool inv = expr_invariant_in_loop_p (loop, gimple_cond_lhs (gc));
- enum tree_code up_code = inv ? LT_EXPR : GT_EXPR;
- enum tree_code down_code = inv ? GT_EXPR : LT_EXPR;
+ if (tree_int_cst_sign_bit (step))
+ inv = !inv;
+ enum tree_code first_loop_code = inv ? LT_EXPR : GT_EXPR;
+ enum tree_code second_loop_code = inv ? GT_EXPR : LT_EXPR;
- gimple_cond_set_code (gc, up_code);
- gimple_cond_set_code (dup_gc, down_code);
+ gimple_cond_set_code (gc, first_loop_code);
+ gimple_cond_set_code (dup_gc, second_loop_code);
/* Link the exit cond edge to new loop. */
gcond *break_cond = as_a<gcond *> (gimple_copy (gc));
@@ -1752,7 +1757,7 @@ split_ne_loop (struct loop *loop, edge cond_e)
bool simple_loop
= pred_e && pred_e->src == cond_e->src && empty_block_p (loop->latch);
if (simple_loop)
- gimple_cond_set_code (break_cond, down_code);
+ gimple_cond_set_code (break_cond, second_loop_code);
else
gimple_cond_make_true (break_cond);
@@ -1810,7 +1815,8 @@ The loop with "i<N" is in favor both GIMPLE and RTL passes. */
static bool
split_loop_on_ne_cond (class loop *loop)
{
- edge branch_edge = get_ne_cond_branch (loop);
+ tree step;
+ edge branch_edge = get_ne_cond_branch (loop, &step);
if (!branch_edge)
return false;
@@ -1832,7 +1838,7 @@ split_loop_on_ne_cond (class loop *loop)
}
free (bbs);
- if (split_ne_loop (loop, branch_edge))
+ if (split_ne_loop (loop, branch_edge, step))
return true;
return false;
More information about the Gcc-cvs
mailing list