Commit fc249fe5 by Michael Matz Committed by Michael Matz

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
parent 289a9f86
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> 2010-04-14 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.md (*popcountsi2_cmp_zext): Remove mode attribute * config/i386/i386.md (*popcountsi2_cmp_zext): Remove mode attribute
......
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> 2010-04-14 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/class_wide.adb: Rename into... * gnat.dg/class_wide.adb: Rename into...
......
/* { 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" } } */
...@@ -71,6 +71,12 @@ static const int initial_cfg_capacity = 20; ...@@ -71,6 +71,12 @@ static const int initial_cfg_capacity = 20;
static struct pointer_map_t *edge_to_cases; 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. */ /* CFG statistics. */
struct cfg_stats_d struct cfg_stats_d
{ {
...@@ -122,6 +128,7 @@ static edge find_taken_edge_computed_goto (basic_block, tree); ...@@ -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_cond_expr (basic_block, tree);
static edge find_taken_edge_switch_expr (basic_block, tree); static edge find_taken_edge_switch_expr (basic_block, tree);
static tree find_case_label_for_value (gimple, tree); static tree find_case_label_for_value (gimple, tree);
static void group_case_labels_stmt (gimple);
void void
init_empty_tree_cfg_for_function (struct function *fn) init_empty_tree_cfg_for_function (struct function *fn)
...@@ -848,6 +855,7 @@ start_recording_case_labels (void) ...@@ -848,6 +855,7 @@ start_recording_case_labels (void)
{ {
gcc_assert (edge_to_cases == NULL); gcc_assert (edge_to_cases == NULL);
edge_to_cases = pointer_map_create (); edge_to_cases = pointer_map_create ();
touched_switch_bbs = BITMAP_ALLOC (NULL);
} }
/* Return nonzero if we are recording information for case labels. */ /* Return nonzero if we are recording information for case labels. */
...@@ -863,9 +871,22 @@ recording_case_labels_p (void) ...@@ -863,9 +871,22 @@ recording_case_labels_p (void)
void void
end_recording_case_labels (void) end_recording_case_labels (void)
{ {
bitmap_iterator bi;
unsigned i;
pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL); pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL);
pointer_map_destroy (edge_to_cases); pointer_map_destroy (edge_to_cases);
edge_to_cases = NULL; 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 /* If we are inside a {start,end}_recording_cases block, then return
...@@ -1278,108 +1299,115 @@ cleanup_dead_labels (void) ...@@ -1278,108 +1299,115 @@ cleanup_dead_labels (void)
free (label_for_bb); free (label_for_bb);
} }
/* Look for blocks ending in a multiway branch (a SWITCH_EXPR in GIMPLE), /* Scan the sorted vector of cases in STMT (a GIMPLE_SWITCH) and combine
and scan the sorted vector of cases. Combine the ones jumping to the the ones jumping to the same label.
same label.
Eg. three separate entries 1: 2: 3: become one entry 1..3: */ Eg. three separate entries 1: 2: 3: become one entry 1..3: */
void static void
group_case_labels (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); default_case = gimple_switch_default_label (stmt);
if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) 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); gimple_switch_set_label (stmt, i, NULL_TREE);
int i, j, new_size = old_size; i++;
tree default_case = NULL_TREE; new_size--;
tree default_label = NULL_TREE; continue;
bool has_default; }
/* The default label is always the first case in a switch base_high = CASE_HIGH (base_case)
statement after gimplification if it was not optimized ? CASE_HIGH (base_case)
away */ : CASE_LOW (base_case);
if (!CASE_LOW (gimple_switch_default_label (stmt)) i++;
&& !CASE_HIGH (gimple_switch_default_label (stmt)))
/* 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); base_high = CASE_HIGH (merge_case) ?
default_label = CASE_LABEL (default_case); CASE_HIGH (merge_case) : CASE_LOW (merge_case);
has_default = true; CASE_HIGH (base_case) = base_high;
gimple_switch_set_label (stmt, i, NULL_TREE);
new_size--;
i++;
} }
else else
has_default = false; break;
}
/* 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 /* Compress the case labels in the label vector, and adjust the
default case. */ length of the vector. */
if (base_label == default_label) for (i = 0, j = 0; i < new_size; i++)
{ {
gimple_switch_set_label (stmt, i, NULL_TREE); while (! gimple_switch_label (stmt, j))
i++; j++;
new_size--; gimple_switch_set_label (stmt, i,
continue; gimple_switch_label (stmt, j++));
} }
base_high = CASE_HIGH (base_case) gcc_assert (new_size <= old_size);
? CASE_HIGH (base_case) gimple_switch_set_num_labels (stmt, new_size);
: CASE_LOW (base_case); }
i++;
/* Try to merge case labels. Break out when we reach the end /* Look for blocks ending in a multiway branch (a GIMPLE_SWITCH),
of the label vector or when we cannot merge the next case and scan the sorted vector of cases. Combine the ones jumping to the
label with the current one. */ same label. */
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;
}
}
/* Compress the case labels in the label vector, and adjust the void
length of the vector. */ group_case_labels (void)
for (i = 0, j = 0; i < new_size; i++) {
{ basic_block bb;
while (! gimple_switch_label (stmt, j))
j++;
gimple_switch_set_label (stmt, i,
gimple_switch_label (stmt, j++));
}
gcc_assert (new_size <= old_size); FOR_EACH_BB (bb)
gimple_switch_set_num_labels (stmt, new_size); {
} 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) ...@@ -4689,6 +4717,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
TREE_CHAIN (last) = TREE_CHAIN (cases2); TREE_CHAIN (last) = TREE_CHAIN (cases2);
TREE_CHAIN (cases2) = first; TREE_CHAIN (cases2) = first;
} }
bitmap_set_bit (touched_switch_bbs, gimple_bb (stmt)->index);
} }
else else
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment