Loop splitting is fine when the control variable is of integer type,
but when it is a pointer type the upper bound of the new loop is
calculated incorrectly.
The calculation should be guard_init + (end-beg), but instead we do
guard_init - (end-beg).

Fixed thusly.  Bootstrapped, regtested.

OK?

Andrew.


2017-03-08  Andrew Haley  <a...@redhat.com>

        PR tree-optimization/79894
        * tree-ssa-loop-split.c (compute_new_first_bound): When
        calculating the new upper bound, (END-BEG) should be added, not
        subtracted.

Index: gcc/tree-ssa-loop-split.c
===================================================================
--- gcc/tree-ssa-loop-split.c   (revision 245948)
+++ gcc/tree-ssa-loop-split.c   (working copy)
@@ -436,7 +436,6 @@
   if (POINTER_TYPE_P (TREE_TYPE (guard_init)))
     {
       enddiff = gimple_convert (stmts, sizetype, enddiff);
-      enddiff = gimple_build (stmts, NEGATE_EXPR, sizetype, enddiff);
       newbound = gimple_build (stmts, POINTER_PLUS_EXPR,
                               TREE_TYPE (guard_init),
                               guard_init, enddiff);


2017-03-08  Andrew Haley  <a...@redhat.com>

        PR tree-optimization/79894
        * gcc.dg/tree-ssa/pr79943.c: New test.

Index: gcc/testsuite/gcc.dg/tree-ssa/pr79943.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/pr79943.c     (revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/pr79943.c     (revision 0)
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fsplit-loops -fdump-tree-lsplit-details" } */
+/* { dg-require-effective-target int32plus } */
+
+#ifdef __cplusplus
+extern "C" void abort (void);
+#else
+extern void abort (void);
+#endif
+
+typedef struct {
+  int n;
+} region_t;
+
+void set (region_t *region) __attribute__((noinline));
+void doit (region_t *beg, region_t *end, region_t *limit)
+  __attribute__((noinline));
+
+region_t regions[10];
+
+void
+set (region_t *region) {
+  region->n = 1;
+}
+
+void
+doit (region_t *beg, region_t *end, region_t *limit) {
+  for (region_t *cur = beg; cur < end; cur++) {
+    if (cur < limit) {
+      set(cur);
+    }
+  }
+}
+
+int
+main (void) {
+  doit(&regions[0], &regions[2], &regions[10]);
+  if (regions[1].n != 1)
+    abort();
+}

Reply via email to