On Tue, 16 May 2017, Peter Bergner wrote: > The test case in PR80775 exposes a problem in handling two separate > case labels that lead to the same block that contains a call to > __builtin_unreachable(). The current code handles the first label > and deletes the associated edge/block, but trips up when we see the > second case label that now points to a removed block. This patch moves > the deletion of the unreachable case statement to after the merging > of consecutive case labels, which easily fixes the issue. It also has > a side benefit of reducing the number of calls to gimple_seq_unreachable_p() > when we have consecutive case labels that point to unreachable blocks. > > This bootstrapped and regtested with no regressions on both powerpc64le-linux > and x86_64-linux. Is this ok for trunk?
Ok. Thanks, Richard. > Peter > > gcc/ > PR middle-end/80775 > * tree-cfg.c: Move deletion of unreachable case statements to after > the merging of consecutive case labels. > > gcc/testsuite/ > PR middle-end/80775 > * gcc.dg/pr80775.c: New test. > > Index: gcc/tree-cfg.c > =================================================================== > --- gcc/tree-cfg.c (revision 248119) > +++ gcc/tree-cfg.c (working copy) > @@ -1661,7 +1661,7 @@ void > group_case_labels_stmt (gswitch *stmt) > { > int old_size = gimple_switch_num_labels (stmt); > - int i, j, new_size = old_size; > + int i, j, base_index, new_size = old_size; > basic_block default_bb = NULL; > > default_bb = label_to_block (CASE_LABEL (gimple_switch_default_label > (stmt))); > @@ -1678,16 +1678,9 @@ group_case_labels_stmt (gswitch *stmt) > gcc_assert (base_case); > base_bb = label_to_block (CASE_LABEL (base_case)); > > - /* Discard cases that have the same destination as the default case > - or if their destination block is unreachable. */ > - if (base_bb == default_bb > - || (EDGE_COUNT (base_bb->succs) == 0 > - && gimple_seq_unreachable_p (bb_seq (base_bb)))) > + /* Discard cases that have the same destination as the default case. > */ > + if (base_bb == default_bb) > { > - edge e; > - if (base_bb != default_bb > - && (e = find_edge (gimple_bb (stmt), base_bb)) != NULL) > - remove_edge_and_dominated_blocks (e); > gimple_switch_set_label (stmt, i, NULL_TREE); > i++; > new_size--; > @@ -1697,7 +1690,7 @@ group_case_labels_stmt (gswitch *stmt) > base_high = CASE_HIGH (base_case) > ? CASE_HIGH (base_case) > : CASE_LOW (base_case); > - i++; > + base_index = 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 > @@ -1723,6 +1716,18 @@ group_case_labels_stmt (gswitch *stmt) > else > break; > } > + > + /* Discard cases that have an unreachable destination block. */ > + if (EDGE_COUNT (base_bb->succs) == 0 > + && gimple_seq_unreachable_p (bb_seq (base_bb))) > + { > + edge base_edge = find_edge (gimple_bb (stmt), base_bb); > + if (base_edge != NULL) > + remove_edge_and_dominated_blocks (base_edge); > + gimple_switch_set_label (stmt, base_index, NULL_TREE); > + new_size--; > + i++; > + } > } > > /* Compress the case labels in the label vector, and adjust the > Index: gcc/testsuite/gcc.dg/pr80775.c > =================================================================== > --- gcc/testsuite/gcc.dg/pr80775.c (nonexistent) > +++ gcc/testsuite/gcc.dg/pr80775.c (working copy) > @@ -0,0 +1,21 @@ > +/* PR middle-end/80775 ICE: -O3 produces ice in group_case_labels_stmt. */ > +/* { dg-do compile } */ > +/* { dg-options "-O3" } */ > + > +typedef struct { short a; } b; > +b c[10]; > +int d, e, f, g, h; > +int > +i (void) > +{ > + f = 0; > + for (; f < e; f++) { > + switch (g) { > + case 1: > + d = 1; > + case 2: > + c[2 + f].a = 1; > + } > + h += c[f].a; > + } > +} > > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)