diff options
author | Jakub Jelinek <jakub@redhat.com> | 2011-05-26 12:05:05 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2011-05-26 12:05:05 +0200 |
commit | 1aa9438fdb536c081195b462c7d7be9f82004a73 (patch) | |
tree | 8bca149e3f780e52c9095bee5dec1c249b4481f0 /gcc/tree-vrp.c | |
parent | 0dd5327a4608ea3db17ed4af83d6b31d792c2768 (diff) | |
download | gcc-1aa9438fdb536c081195b462c7d7be9f82004a73.zip gcc-1aa9438fdb536c081195b462c7d7be9f82004a73.tar.gz gcc-1aa9438fdb536c081195b462c7d7be9f82004a73.tar.bz2 |
re PR tree-optimization/49161 (Fix VRP on switch stmts)
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
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 58 |
1 files changed, 34 insertions, 24 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 2d3a6fc..8fcf629 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -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; } |