Fix PR42963: redundant switch label cleanup
Richard Guenther
richard.guenther@gmail.com
Wed Apr 14 13:55:00 GMT 2010
On Wed, Apr 14, 2010 at 3:03 PM, Michael Matz <matz@suse.de> wrote:
> Hello,
>
> so, it needed some prodding from Steven, but here it is. Due to various
> circumstances we don't cleanup redundant switch labels anymore until very
> late in the compiler (we currently clean them up at two points, one very
> early where we meanwhile didn't cleanup some jumps anymore, and one very
> late). This patch implements cleaning them up as soon as cfg-cleanup
> redirected any jump out of GIMPLE_SWITCH stmts. To avoid quadratic
> complexity in case we redirect many jump targets I simply remember all BBs
> that need investigation, and clean them up later.
>
> The patch is noisy because it breaks out the actual cleaning per stmt from
> group_case_labels() into it's own routine. Hence I include only the
> patch ignoring white-space changes for easier review.
>
> Regstrapping on x86_64-linux in progress, okay for trunk?
Ok.
Thanks,
Richard.
>
> Ciao,
> Michael.
> --
> 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.
>
> Index: tree-cfg.c
> ===================================================================
> *** tree-cfg.c (revision 158263)
> --- tree-cfg.c (working copy)
> *************** static const int initial_cfg_capacity =
> *** 71,76 ****
> --- 71,82 ----
>
> 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
> {
> *************** static edge find_taken_edge_computed_got
> *** 122,127 ****
> --- 128,134 ----
> 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)
> *************** start_recording_case_labels (void)
> *** 848,853 ****
> --- 855,861 ----
> {
> 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. */
> *************** recording_case_labels_p (void)
> *** 863,871 ****
> --- 871,892 ----
> 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
> *************** cleanup_dead_labels (void)
> *** 1278,1297 ****
> 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.
> Eg. three separate entries 1: 2: 3: become one entry 1..3: */
>
> ! void
> ! group_case_labels (void)
> ! {
> ! basic_block bb;
> !
> ! FOR_EACH_BB (bb)
> ! {
> ! gimple stmt = last_stmt (bb);
> ! if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
> {
> int old_size = gimple_switch_num_labels (stmt);
> int i, j, new_size = old_size;
> --- 1299,1310 ----
> free (label_for_bb);
> }
>
> ! /* 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: */
>
> ! static void
> ! group_case_labels_stmt (gimple stmt)
> {
> int old_size = gimple_switch_num_labels (stmt);
> int i, j, new_size = old_size;
> *************** group_case_labels (void)
> *** 1380,1385 ****
> --- 1393,1413 ----
> gcc_assert (new_size <= old_size);
> gimple_switch_set_num_labels (stmt, new_size);
> }
> +
> + /* 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. */
> +
> + void
> + group_case_labels (void)
> + {
> + basic_block bb;
> +
> + FOR_EACH_BB (bb)
> + {
> + gimple stmt = last_stmt (bb);
> + if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
> + group_case_labels_stmt (stmt);
> }
> }
>
> *************** gimple_redirect_edge_and_branch (edge e,
> *** 4689,4694 ****
> --- 4738,4744 ----
> TREE_CHAIN (last) = TREE_CHAIN (cases2);
> TREE_CHAIN (cases2) = first;
> }
> + bitmap_set_bit (touched_switch_bbs, gimple_bb (stmt)->index);
> }
> else
> {
> Index: testsuite/gcc.dg/pr42963.c
> ===================================================================
> --- testsuite/gcc.dg/pr42963.c (revision 0)
> +++ testsuite/gcc.dg/pr42963.c (revision 0)
> @@ -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" } } */
>
More information about the Gcc-patches
mailing list