diff options
author | Michael Matz <matz@suse.de> | 2010-04-14 14:50:33 +0000 |
---|---|---|
committer | Michael Matz <matz@gcc.gnu.org> | 2010-04-14 14:50:33 +0000 |
commit | fc249fe5d62c73210b3f752fb45119391d0774f0 (patch) | |
tree | 05e8f3fe688ca2ced73803178ff9b08bfa60f8b5 | |
parent | 289a9f867a78d0c928eed2d9793964b9c7272022 (diff) | |
download | gcc-fc249fe5d62c73210b3f752fb45119391d0774f0.zip gcc-fc249fe5d62c73210b3f752fb45119391d0774f0.tar.gz gcc-fc249fe5d62c73210b3f752fb45119391d0774f0.tar.bz2 |
re PR tree-optimization/42963 (Redundant switch labels not cleaned up anymore)
PR tree-optimization/42963
* tree-cfg.c (touched_switch_bbs): New static variable.
(group_case_labels_stmt): New function broken out from ...
(group_case_labels): ... here, use the above.
(start_recording_case_labels): Allocate touched_switch_bbs.
(end_recording_case_labels): Deallocate it, call
group_case_labels_stmt.
(gimple_redirect_edge_and_branch): Remember index of affected BB.
testsuite/
* testsuite/gcc.dg/pr42963.c: New testcase.
From-SVN: r158345
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr42963.c | 28 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 205 |
4 files changed, 161 insertions, 88 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 60548dc..06e1af4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2010-04-14 Michael Matz <matz@suse.de> + + PR tree-optimization/42963 + * tree-cfg.c (touched_switch_bbs): New static variable. + (group_case_labels_stmt): New function broken out from ... + (group_case_labels): ... here, use the above. + (start_recording_case_labels): Allocate touched_switch_bbs. + (end_recording_case_labels): Deallocate it, call + group_case_labels_stmt. + (gimple_redirect_edge_and_branch): Remember index of affected BB. + 2010-04-14 Uros Bizjak <ubizjak@gmail.com> * config/i386/i386.md (*popcountsi2_cmp_zext): Remove mode attribute diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d006531..13ef39f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-04-14 Michael Matz <matz@suse.de> + + PR tree-optimization/42963 + * testsuite/gcc.dg/pr42963.c: New testcase. + 2010-04-14 Eric Botcazou <ebotcazou@adacore.com> * gnat.dg/class_wide.adb: Rename into... diff --git a/gcc/testsuite/gcc.dg/pr42963.c b/gcc/testsuite/gcc.dg/pr42963.c new file mode 100644 index 0000000..8664b0d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr42963.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cfg" } */ +extern void foo (void); +extern int i; +void +bar (void) +{ + switch (i) + { + case 0: + foo (); + break; + case 1: + break; + } + + + switch (i) + { + case 0: + foo (); + break; + case 1: + break; + } +} +/* { dg-final { scan-tree-dump-times "case 1:" 0 "cfg" } } */ +/* { dg-final { cleanup-tree-dump "cfg" } } */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 01fefc30..0e89f99 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -71,6 +71,12 @@ static const int initial_cfg_capacity = 20; static struct pointer_map_t *edge_to_cases; +/* If we record edge_to_cases, this bitmap will hold indexes + of basic blocks that end in a GIMPLE_SWITCH which we touched + due to edge manipulations. */ + +static bitmap touched_switch_bbs; + /* CFG statistics. */ struct cfg_stats_d { @@ -122,6 +128,7 @@ static edge find_taken_edge_computed_goto (basic_block, tree); static edge find_taken_edge_cond_expr (basic_block, tree); static edge find_taken_edge_switch_expr (basic_block, tree); static tree find_case_label_for_value (gimple, tree); +static void group_case_labels_stmt (gimple); void init_empty_tree_cfg_for_function (struct function *fn) @@ -848,6 +855,7 @@ start_recording_case_labels (void) { gcc_assert (edge_to_cases == NULL); edge_to_cases = pointer_map_create (); + touched_switch_bbs = BITMAP_ALLOC (NULL); } /* Return nonzero if we are recording information for case labels. */ @@ -863,9 +871,22 @@ recording_case_labels_p (void) void end_recording_case_labels (void) { + bitmap_iterator bi; + unsigned i; pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL); pointer_map_destroy (edge_to_cases); edge_to_cases = NULL; + EXECUTE_IF_SET_IN_BITMAP (touched_switch_bbs, 0, i, bi) + { + basic_block bb = BASIC_BLOCK (i); + if (bb) + { + gimple stmt = last_stmt (bb); + if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + group_case_labels_stmt (stmt); + } + } + BITMAP_FREE (touched_switch_bbs); } /* If we are inside a {start,end}_recording_cases block, then return @@ -1278,108 +1299,115 @@ cleanup_dead_labels (void) free (label_for_bb); } -/* Look for blocks ending in a multiway branch (a SWITCH_EXPR in GIMPLE), - and scan the sorted vector of cases. Combine the ones jumping to the - same label. +/* Scan the sorted vector of cases in STMT (a GIMPLE_SWITCH) and combine + the ones jumping to the same label. Eg. three separate entries 1: 2: 3: become one entry 1..3: */ -void -group_case_labels (void) +static void +group_case_labels_stmt (gimple stmt) { - basic_block bb; + int old_size = gimple_switch_num_labels (stmt); + int i, j, new_size = old_size; + tree default_case = NULL_TREE; + tree default_label = NULL_TREE; + bool has_default; - FOR_EACH_BB (bb) + /* The default label is always the first case in a switch + statement after gimplification if it was not optimized + away */ + if (!CASE_LOW (gimple_switch_default_label (stmt)) + && !CASE_HIGH (gimple_switch_default_label (stmt))) { - gimple stmt = last_stmt (bb); - if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + default_case = gimple_switch_default_label (stmt); + default_label = CASE_LABEL (default_case); + has_default = true; + } + else + has_default = false; + + /* Look for possible opportunities to merge cases. */ + if (has_default) + i = 1; + else + i = 0; + while (i < old_size) + { + tree base_case, base_label, base_high; + base_case = gimple_switch_label (stmt, i); + + gcc_assert (base_case); + base_label = CASE_LABEL (base_case); + + /* Discard cases that have the same destination as the + default case. */ + if (base_label == default_label) { - int old_size = gimple_switch_num_labels (stmt); - int i, j, new_size = old_size; - tree default_case = NULL_TREE; - tree default_label = NULL_TREE; - bool has_default; - - /* The default label is always the first case in a switch - statement after gimplification if it was not optimized - away */ - if (!CASE_LOW (gimple_switch_default_label (stmt)) - && !CASE_HIGH (gimple_switch_default_label (stmt))) + gimple_switch_set_label (stmt, i, NULL_TREE); + i++; + new_size--; + continue; + } + + base_high = CASE_HIGH (base_case) + ? CASE_HIGH (base_case) + : CASE_LOW (base_case); + i++; + + /* Try to merge case labels. Break out when we reach the end + of the label vector or when we cannot merge the next case + label with the current one. */ + while (i < old_size) + { + tree merge_case = gimple_switch_label (stmt, i); + tree merge_label = CASE_LABEL (merge_case); + tree t = int_const_binop (PLUS_EXPR, base_high, + integer_one_node, 1); + + /* Merge the cases if they jump to the same place, + and their ranges are consecutive. */ + if (merge_label == base_label + && tree_int_cst_equal (CASE_LOW (merge_case), t)) { - default_case = gimple_switch_default_label (stmt); - default_label = CASE_LABEL (default_case); - has_default = true; + base_high = CASE_HIGH (merge_case) ? + CASE_HIGH (merge_case) : CASE_LOW (merge_case); + CASE_HIGH (base_case) = base_high; + gimple_switch_set_label (stmt, i, NULL_TREE); + new_size--; + i++; } else - has_default = false; - - /* Look for possible opportunities to merge cases. */ - if (has_default) - i = 1; - else - i = 0; - while (i < old_size) - { - tree base_case, base_label, base_high; - base_case = gimple_switch_label (stmt, i); - - gcc_assert (base_case); - base_label = CASE_LABEL (base_case); + break; + } + } - /* Discard cases that have the same destination as the - default case. */ - if (base_label == default_label) - { - gimple_switch_set_label (stmt, i, NULL_TREE); - i++; - new_size--; - continue; - } + /* Compress the case labels in the label vector, and adjust the + length of the vector. */ + for (i = 0, j = 0; i < new_size; i++) + { + while (! gimple_switch_label (stmt, j)) + j++; + gimple_switch_set_label (stmt, i, + gimple_switch_label (stmt, j++)); + } - base_high = CASE_HIGH (base_case) - ? CASE_HIGH (base_case) - : CASE_LOW (base_case); - i++; + gcc_assert (new_size <= old_size); + gimple_switch_set_num_labels (stmt, new_size); +} - /* Try to merge case labels. Break out when we reach the end - of the label vector or when we cannot merge the next case - label with the current one. */ - while (i < old_size) - { - tree merge_case = gimple_switch_label (stmt, i); - tree merge_label = CASE_LABEL (merge_case); - tree t = int_const_binop (PLUS_EXPR, base_high, - integer_one_node, 1); - - /* Merge the cases if they jump to the same place, - and their ranges are consecutive. */ - if (merge_label == base_label - && tree_int_cst_equal (CASE_LOW (merge_case), t)) - { - base_high = CASE_HIGH (merge_case) ? - CASE_HIGH (merge_case) : CASE_LOW (merge_case); - CASE_HIGH (base_case) = base_high; - gimple_switch_set_label (stmt, i, NULL_TREE); - new_size--; - i++; - } - else - break; - } - } +/* Look for blocks ending in a multiway branch (a GIMPLE_SWITCH), + and scan the sorted vector of cases. Combine the ones jumping to the + same label. */ - /* Compress the case labels in the label vector, and adjust the - length of the vector. */ - for (i = 0, j = 0; i < new_size; i++) - { - while (! gimple_switch_label (stmt, j)) - j++; - gimple_switch_set_label (stmt, i, - gimple_switch_label (stmt, j++)); - } +void +group_case_labels (void) +{ + basic_block bb; - gcc_assert (new_size <= old_size); - gimple_switch_set_num_labels (stmt, new_size); - } + FOR_EACH_BB (bb) + { + gimple stmt = last_stmt (bb); + if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + group_case_labels_stmt (stmt); } } @@ -4689,6 +4717,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) TREE_CHAIN (last) = TREE_CHAIN (cases2); TREE_CHAIN (cases2) = first; } + bitmap_set_bit (touched_switch_bbs, gimple_bb (stmt)->index); } else { |