[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