aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2010-04-14 14:50:33 +0000
committerMichael Matz <matz@gcc.gnu.org>2010-04-14 14:50:33 +0000
commitfc249fe5d62c73210b3f752fb45119391d0774f0 (patch)
tree05e8f3fe688ca2ced73803178ff9b08bfa60f8b5 /gcc
parent289a9f867a78d0c928eed2d9793964b9c7272022 (diff)
downloadgcc-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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/pr42963.c28
-rw-r--r--gcc/tree-cfg.c205
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
{