re PR tree-optimization/71433 (-Warray-bounds false positive with -O2)
authorRichard Biener <rguenther@suse.de>
Fri, 27 Jan 2017 12:30:43 +0000 (12:30 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 27 Jan 2017 12:30:43 +0000 (12:30 +0000)
2017-01-27  Richard Biener  <rguenther@suse.de>

PR tree-optimization/71433
* tree-vrp.c (register_new_assert_for): Revert earlier changes.
(compare_assert_loc): New function.
(process_assert_insertions): Sort and optimize assert locations
to remove duplicates and push down identical assertions on
edges to their destination block.

* gcc.dg/Warray-bounds-21.c: New testcase.

From-SVN: r244974

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Warray-bounds-21.c [new file with mode: 0644]
gcc/tree-vrp.c

index 41df9bbcc1bec608301028da52f27f3cb160d9b3..a9f2421636885af53697afc4f0b89005ae9520aa 100644 (file)
@@ -1,3 +1,12 @@
+2017-01-27  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/71433
+       * tree-vrp.c (register_new_assert_for): Revert earlier changes.
+       (compare_assert_loc): New function.
+       (process_assert_insertions): Sort and optimize assert locations
+       to remove duplicates and push down identical assertions on
+       edges to their destination block.
+
 2017-01-27  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/79244
index 525a7c7f2145dacb63ab3d02a5daadadb534b74f..2c044f58d9e2bdae1898994bc73f493c18bec34b 100644 (file)
@@ -1,3 +1,8 @@
+2017-01-27  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/71433
+       * gcc.dg/Warray-bounds-21.c: New testcase.
+
 2017-01-27  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/79244
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-21.c b/gcc/testsuite/gcc.dg/Warray-bounds-21.c
new file mode 100644 (file)
index 0000000..759944f
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Warray-bounds" } */
+
+int t[1];
+int a (void);
+int fct (int r, long e, int neg)
+{
+  int d = 0;
+  if (r == 4)
+    r = neg ? 3 : 2;
+  if (__builtin_expect(e < -52, 0))
+    d = r == 0 && a () ? 1 : 2;
+  else
+    {
+      int i, n = 53;
+      if (e < 0)
+       n += e;
+      for (i = 1 ; i < n / 64 + 1 ; i++)
+       d = t[i]; /* { dg-bogus "array bounds" } */
+    }
+  return d;
+}
index e023244577c838e777db8de0736b5da2199730e8..5c43e35d89cce921cd14eaef8a75b5f8596867c6 100644 (file)
@@ -5032,18 +5032,6 @@ register_new_assert_for (tree name, tree expr,
              loc->si = si;
              return;
            }
-         /* If we have the same assertion on all incoming edges of a BB
-            instead insert it at the beginning of it.  */
-         if (e && loc->e
-             && e != loc->e
-             && dest_bb == loc->e->dest
-             && EDGE_COUNT (dest_bb->preds) == 2)
-           {
-             loc->bb = dest_bb;
-             loc->e = NULL;
-             loc->si = gsi_none ();
-             return;
-           }
        }
 
       /* Update the last node of the list and move to the next one.  */
@@ -6473,6 +6461,41 @@ process_assert_insertions_for (tree name, assert_locus *loc)
   gcc_unreachable ();
 }
 
+/* Qsort helper for sorting assert locations.  */
+
+static int
+compare_assert_loc (const void *pa, const void *pb)
+{
+  assert_locus * const a = *(assert_locus * const *)pa;
+  assert_locus * const b = *(assert_locus * const *)pb;
+  if (! a->e && b->e)
+    return 1;
+  else if (a->e && ! b->e)
+    return -1;
+
+  /* Sort after destination index.  */
+  if (! a->e && ! b->e)
+    ;
+  else if (a->e->dest->index > b->e->dest->index)
+    return 1;
+  else if (a->e->dest->index < b->e->dest->index)
+    return -1;
+
+  /* Sort after comp_code.  */
+  if (a->comp_code > b->comp_code)
+    return 1;
+  else if (a->comp_code < b->comp_code)
+    return -1;
+
+  /* Break the tie using hashing and source/bb index.  */
+  hashval_t ha = iterative_hash_expr (a->expr, iterative_hash_expr (a->val, 0));
+  hashval_t hb = iterative_hash_expr (b->expr, iterative_hash_expr (b->val, 0));
+  if (ha == hb)
+    return (a->e && b->e
+           ? a->e->src->index - b->e->src->index
+           : a->bb->index - b->bb->index);
+  return ha - hb;
+}
 
 /* Process all the insertions registered for every name N_i registered
    in NEED_ASSERT_FOR.  The list of assertions to be inserted are
@@ -6494,13 +6517,66 @@ process_assert_insertions (void)
       assert_locus *loc = asserts_for[i];
       gcc_assert (loc);
 
-      while (loc)
+      auto_vec<assert_locus *, 16> asserts;
+      for (; loc; loc = loc->next)
+       asserts.safe_push (loc);
+      asserts.qsort (compare_assert_loc);
+
+      /* Push down common asserts to successors and remove redundant ones.  */
+      unsigned ecnt = 0;
+      assert_locus *common = NULL;
+      unsigned commonj = 0;
+      for (unsigned j = 0; j < asserts.length (); ++j)
+       {
+         loc = asserts[j];
+         if (! loc->e)
+           common = NULL;
+         else if (! common
+                  || loc->e->dest != common->e->dest
+                  || loc->comp_code != common->comp_code
+                  || ! operand_equal_p (loc->val, common->val, 0)
+                  || ! operand_equal_p (loc->expr, common->expr, 0))
+           {
+             commonj = j;
+             common = loc;
+             ecnt = 1;
+           }
+         else if (loc->e == asserts[j-1]->e)
+           {
+             /* Remove duplicate asserts.  */
+             free (asserts[j-1]);
+             asserts[j-1] = NULL;
+           }
+         else
+           {
+             ecnt++;
+             if (EDGE_COUNT (common->e->dest->preds) == ecnt)
+               {
+                 /* We have the same assertion on all incoming edges of a BB.
+                    Insert it at the beginning of that block.  */
+                 loc->bb = loc->e->dest;
+                 loc->e = NULL;
+                 loc->si = gsi_none ();
+                 common = NULL;
+                 /* Clear asserts commoned.  */
+                 for (; commonj != j; ++commonj)
+                   if (asserts[commonj])
+                     {
+                       free (asserts[commonj]);
+                       asserts[commonj] = NULL;
+                     }
+               }
+           }
+       }
+
+      for (unsigned j = 0; j < asserts.length (); ++j)
        {
-         assert_locus *next = loc->next;
+         loc = asserts[j];
+         if (! loc)
+           continue;
          update_edges_p |= process_assert_insertions_for (ssa_name (i), loc);
-         free (loc);
-         loc = next;
          num_asserts++;
+         free (loc);
        }
     }