diff options
Diffstat (limited to 'meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0349-PR-tree-optimization-49161.patch')
-rw-r--r-- | meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0349-PR-tree-optimization-49161.patch | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0349-PR-tree-optimization-49161.patch b/meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0349-PR-tree-optimization-49161.patch new file mode 100644 index 000000000..80f89fd41 --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc-4.6.0/gcc-4_6-branch-backports/0349-PR-tree-optimization-49161.patch @@ -0,0 +1,200 @@ +From a6f15e84e042ffb95afa499d2bd2d6b2758f85f9 Mon Sep 17 00:00:00 2001 +From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> +Date: Thu, 26 May 2011 10:20:34 +0000 +Subject: [PATCH] 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. + + +git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch@174272 138bc75d-0d04-0410-961f-82ee72b054a4 + +index 2c4fdd4..b5d9fd3 100644 +new file mode 100644 +index 0000000..cc822da +--- /dev/null ++++ b/gcc/testsuite/gcc.c-torture/execute/pr49161.c +@@ -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; ++} +diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c +index 7bff5fa..6914a08 100644 +--- a/gcc/tree-vrp.c ++++ b/gcc/tree-vrp.c +@@ -4672,28 +4672,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; +@@ -4714,8 +4721,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 +@@ -4730,36 +4737,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 +@@ -4768,7 +4777,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. */ +@@ -4786,6 +4795,7 @@ find_switch_asserts (basic_block bb, gimple last) + } + } + ++ XDELETEVEC (ci); + return need_assert; + } + +-- +1.7.0.4 + |