]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
backport: re PR tree-optimization/49161 (Fix VRP on switch stmts)
authorJakub Jelinek <jakub@redhat.com>
Tue, 19 Jul 2011 12:51:29 +0000 (14:51 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 19 Jul 2011 12:51:29 +0000 (14:51 +0200)
Backport from mainline
2011-05-26  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/49161
* tree-vrp.c (struct case_info): New type.
(compare_case_labels): Sort case_info structs instead of
trees, and not primarily by CASE_LABEL uids but by
label_for_block indexes.
(find_switch_asserts): Put case labels into struct case_info
array instead of TREE_VEC, adjust sorting, compare label_for_block
values instead of CASE_LABELs.

* gcc.c-torture/execute/pr49161.c: New test.

From-SVN: r176451

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr49161.c [new file with mode: 0644]
gcc/tree-vrp.c

index d59d4a58ae236c2f50afb4ab2d2d619c26f6f290..1da0eb374f21916a02e260e1e0e0a4619f8e9c9d 100644 (file)
@@ -1,6 +1,17 @@
 2011-07-19  Jakub Jelinek  <jakub@redhat.com>
 
        Backport from mainline
+       2011-05-26  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/49161
+       * tree-vrp.c (struct case_info): New type.
+       (compare_case_labels): Sort case_info structs instead of
+       trees, and not primarily by CASE_LABEL uids but by
+       label_for_block indexes.
+       (find_switch_asserts): Put case labels into struct case_info
+       array instead of TREE_VEC, adjust sorting, compare label_for_block
+       values instead of CASE_LABELs.
+
        2011-05-23  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/49120
index 0778cdd96a25adcc5c55700c1eb0eab77aa1412a..127eda200d3d2bffb615085f9a4d64b005367f07 100644 (file)
@@ -1,6 +1,11 @@
 2011-07-19  Jakub Jelinek  <jakub@redhat.com>
 
        Backport from mainline
+       2011-05-26  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/49161
+       * gcc.c-torture/execute/pr49161.c: New test.
+
        2011-05-23  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/49120
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr49161.c b/gcc/testsuite/gcc.c-torture/execute/pr49161.c
new file mode 100644 (file)
index 0000000..cc822da
--- /dev/null
@@ -0,0 +1,46 @@
+/* PR tree-optimization/49161 */
+
+extern void abort (void);
+
+int c;
+
+__attribute__((noinline, noclone)) void
+bar (int x)
+{
+  if (x != c++)
+    abort ();
+}
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+  switch (x)
+    {
+    case 3: goto l1;
+    case 4: goto l2;
+    case 6: goto l3;
+    default: return;
+    }
+l1:
+  goto l4;
+l2:
+  goto l4;
+l3:
+  bar (-1);
+l4:
+  bar (0);
+  if (x != 4)
+    bar (1);
+  if (x != 3)
+    bar (-1);
+  bar (2);
+}
+
+int
+main ()
+{
+  foo (3);
+  if (c != 3)
+    abort ();
+  return 0;
+}
index 6fcf2cce09f2677cf5fafcf785a8179b1978899d..62011fd0b96e0e9f549f860b6b3a68603472886d 100644 (file)
@@ -4515,28 +4515,35 @@ find_conditional_asserts (basic_block bb, gimple last)
   return need_assert;
 }
 
-/* Compare two case labels sorting first by the destination label uid
+struct case_info
+{
+  tree expr;
+  basic_block bb;
+};
+
+/* Compare two case labels sorting first by the destination bb index
    and then by the case value.  */
 
 static int
 compare_case_labels (const void *p1, const void *p2)
 {
-  const_tree const case1 = *(const_tree const*)p1;
-  const_tree const case2 = *(const_tree const*)p2;
-  unsigned int uid1 = DECL_UID (CASE_LABEL (case1));
-  unsigned int uid2 = DECL_UID (CASE_LABEL (case2));
+  const struct case_info *ci1 = (const struct case_info *) p1;
+  const struct case_info *ci2 = (const struct case_info *) p2;
+  int idx1 = ci1->bb->index;
+  int idx2 = ci2->bb->index;
 
-  if (uid1 < uid2)
+  if (idx1 < idx2)
     return -1;
-  else if (uid1 == uid2)
+  else if (idx1 == idx2)
     {
       /* Make sure the default label is first in a group.  */
-      if (!CASE_LOW (case1))
+      if (!CASE_LOW (ci1->expr))
        return -1;
-      else if (!CASE_LOW (case2))
+      else if (!CASE_LOW (ci2->expr))
        return 1;
       else
-        return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
+       return tree_int_cst_compare (CASE_LOW (ci1->expr),
+                                    CASE_LOW (ci2->expr));
     }
   else
     return 1;
@@ -4557,8 +4564,8 @@ find_switch_asserts (basic_block bb, gimple last)
   gimple_stmt_iterator bsi;
   tree op;
   edge e;
-  tree vec2;
-  size_t n = gimple_switch_num_labels(last);
+  struct case_info *ci;
+  size_t n = gimple_switch_num_labels (last);
 #if GCC_VERSION >= 4000
   unsigned int idx;
 #else
@@ -4573,36 +4580,38 @@ find_switch_asserts (basic_block bb, gimple last)
     return false;
 
   /* Build a vector of case labels sorted by destination label.  */
-  vec2 = make_tree_vec (n);
+  ci = XNEWVEC (struct case_info, n);
   for (idx = 0; idx < n; ++idx)
-    TREE_VEC_ELT (vec2, idx) = gimple_switch_label (last, idx);
-  qsort (&TREE_VEC_ELT (vec2, 0), n, sizeof (tree), compare_case_labels);
+    {
+      ci[idx].expr = gimple_switch_label (last, idx);
+      ci[idx].bb = label_to_block (CASE_LABEL (ci[idx].expr));
+    }
+  qsort (ci, n, sizeof (struct case_info), compare_case_labels);
 
   for (idx = 0; idx < n; ++idx)
     {
       tree min, max;
-      tree cl = TREE_VEC_ELT (vec2, idx);
+      tree cl = ci[idx].expr;
+      basic_block cbb = ci[idx].bb;
 
       min = CASE_LOW (cl);
       max = CASE_HIGH (cl);
 
       /* If there are multiple case labels with the same destination
         we need to combine them to a single value range for the edge.  */
-      if (idx + 1 < n
-         && CASE_LABEL (cl) == CASE_LABEL (TREE_VEC_ELT (vec2, idx + 1)))
+      if (idx + 1 < n && cbb == ci[idx + 1].bb)
        {
          /* Skip labels until the last of the group.  */
          do {
            ++idx;
-         } while (idx < n
-                  && CASE_LABEL (cl) == CASE_LABEL (TREE_VEC_ELT (vec2, idx)));
+         } while (idx < n && cbb == ci[idx].bb);
          --idx;
 
          /* Pick up the maximum of the case label range.  */
-         if (CASE_HIGH (TREE_VEC_ELT (vec2, idx)))
-           max = CASE_HIGH (TREE_VEC_ELT (vec2, idx));
+         if (CASE_HIGH (ci[idx].expr))
+           max = CASE_HIGH (ci[idx].expr);
          else
-           max = CASE_LOW (TREE_VEC_ELT (vec2, idx));
+           max = CASE_LOW (ci[idx].expr);
        }
 
       /* Nothing to do if the range includes the default label until we
@@ -4611,7 +4620,7 @@ find_switch_asserts (basic_block bb, gimple last)
        continue;
 
       /* Find the edge to register the assert expr on.  */
-      e = find_edge (bb, label_to_block (CASE_LABEL (cl)));
+      e = find_edge (bb, cbb);
 
       /* Register the necessary assertions for the operand in the
         SWITCH_EXPR.  */
@@ -4629,6 +4638,7 @@ find_switch_asserts (basic_block bb, gimple last)
        }
     }
 
+  XDELETEVEC (ci);
   return need_assert;
 }