re PR tree-optimization/49161 (Fix VRP on switch stmts)
authorJakub Jelinek <jakub@redhat.com>
Thu, 26 May 2011 10:05:05 +0000 (12:05 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 26 May 2011 10:05:05 +0000 (12:05 +0200)
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: r174270

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

index c60706c275df946584886abf110035aa037a917e..14503137b5aedb874c9d1ff0e2a2565e661661de 100644 (file)
@@ -1,3 +1,14 @@
+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-26  Ramana Radhakrishnan  <ramana.radhakrishnan@linaro.org>
 
        * config/arm/neon.md ("orn<mode>3_neon"): Canonicalize not.
index bf6a2eeed0305d57ed0e1fdc5e871a37c034f461..27f468d308c40703225640ca69472fd9724a6e8c 100644 (file)
@@ -1,3 +1,8 @@
+2011-05-26  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/49161
+       * gcc.c-torture/execute/pr49161.c: New test.
+
 2011-05-26  Ramana Radhakrishnan  <ramana.radhakrishnan@linaro.org>
 
        * gcc.target/arm/neon-vorn-vbic.c: New test.
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 2d3a6fcad703f2a22039d63145c9d32a690fe5fb..8fcf629addecac26ba0e8ba1508321b3ee7c1a48 100644 (file)
@@ -4673,28 +4673,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;
@@ -4715,8 +4722,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
@@ -4731,36 +4738,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
@@ -4769,7 +4778,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.  */
@@ -4787,6 +4796,7 @@ find_switch_asserts (basic_block bb, gimple last)
        }
     }
 
+  XDELETEVEC (ci);
   return need_assert;
 }