On Wed, Apr 26, 2017 at 10:39:12PM -0500, Peter Bergner wrote: > +/* Returns true if the basic block BB has no successors and only contains > + a call to __builtin_unreachable (). */
so return EDGE_COUNT (bb->succs) == 0 && (gsi = gsi_last_nondebug_bb (bb)) && !gsi_end_p (gsi) && gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_UNREACHABLE); or at least if (EDGE_COUNT (bb->succs) != 0) return false; /* there is also a first_non_label_stmt() in tree-cfg.c ?! */ gsi = gsi_start_nondebug_after_labels_bb (bb); if (gsi_end_p (gsi)) return false; while (gimple_clobber_p (gsi_stmt (gsi))) { gsi_next (&gsi); if (gsi_end_p (gsi)) return false; } return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE); which i should better phrase as gsi = gsi_start_nondebug_after_labels_bb (bb); while (!gsi_end_p (gsi) { gimple *stmt = gsi_stmt (gsi); if (gimple_clobber_p (stmt)) gsi_next (&gsi); else return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE); } return false; No comment on the patch itself. cheers, > + > +bool > +gimple_unreachable_bb_p (basic_block bb) > +{ > + gimple_stmt_iterator gsi; > + gimple_seq stmts = bb_seq (bb); > + gimple *stmt; > + > + if (EDGE_COUNT (bb->succs) != 0) > + return false; > + > + gsi = gsi_start (stmts); > + while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL) > + gsi_next (&gsi); > + > + if (gsi_end_p (gsi)) > + return false; > + > + stmt = gsi_stmt (gsi); > + while (is_gimple_debug (stmt) || gimple_clobber_p (stmt)) > + { > + gsi_next (&gsi); > + if (gsi_end_p (gsi)) > + return false; > + stmt = gsi_stmt (gsi); > + } > + return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE); > +} > + > /* Returns true for edge E where e->src ends with a GIMPLE_COND and > the other edge points to a bb with just __builtin_unreachable (). > I.e. return true for C->M edge in: > @@ -475,23 +506,7 @@ assert_unreachable_fallthru_edge_p (edge > basic_block other_bb = EDGE_SUCC (pred_bb, 0)->dest; > if (other_bb == e->dest) > other_bb = EDGE_SUCC (pred_bb, 1)->dest; > - if (EDGE_COUNT (other_bb->succs) == 0) > - { > - gimple_stmt_iterator gsi = gsi_after_labels (other_bb); > - gimple *stmt; > - > - if (gsi_end_p (gsi)) > - return false; > - stmt = gsi_stmt (gsi); > - while (is_gimple_debug (stmt) || gimple_clobber_p (stmt)) > - { > - gsi_next (&gsi); > - if (gsi_end_p (gsi)) > - return false; > - stmt = gsi_stmt (gsi); > - } > - return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE); > - } > + return gimple_unreachable_bb_p (other_bb); > } > return false; > } > @@ -1668,9 +1683,10 @@ 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. */ > - if (base_bb == default_bb) > + /* Discard cases that have the same destination as the default case > + or if their destination block is unreachable. */ > + if (base_bb == default_bb > + || gimple_unreachable_bb_p (base_bb)) > { > gimple_switch_set_label (stmt, i, NULL_TREE); > i++; > Index: gcc/tree-cfg.h > =================================================================== > --- gcc/tree-cfg.h (revision 247291) > +++ gcc/tree-cfg.h (working copy) > @@ -56,6 +56,7 @@ extern bool is_ctrl_stmt (gimple *); > extern bool is_ctrl_altering_stmt (gimple *); > extern bool simple_goto_p (gimple *); > extern bool stmt_ends_bb_p (gimple *); > +extern bool gimple_unreachable_bb_p (basic_block); > extern bool assert_unreachable_fallthru_edge_p (edge); > extern void delete_tree_cfg_annotations (function *); > extern gphi *get_virtual_phi (basic_block); > Index: gcc/stmt.c > =================================================================== > --- gcc/stmt.c (revision 247291) > +++ gcc/stmt.c (working copy) > @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. > #include "rtl.h" > #include "tree.h" > #include "gimple.h" > +#include "cfghooks.h" > #include "predict.h" > #include "alloc-pool.h" > #include "memmodel.h" > @@ -49,6 +50,7 @@ along with GCC; see the file COPYING3. > #include "expr.h" > #include "langhooks.h" > #include "cfganal.h" > +#include "tree-cfg.h" > #include "params.h" > #include "dumpfile.h" > #include "builtins.h" > @@ -1007,20 +1009,21 @@ emit_case_dispatch_table (tree index_exp > = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label)); > } > > - /* Fill in the gaps with the default. We may have gaps at > - the beginning if we tried to avoid the minval subtraction, > - so substitute some label even if the default label was > - deemed unreachable. */ > - if (!default_label) > - default_label = fallback_label; > + /* The dispatch table may contain gaps, including at the beginning of > + the table if we tried to avoid the minval subtraction. We fill the > + dispatch table slots associated with the gaps with the default case > label. > + However, in the event the default case is unreachable, we then use > + any label from one of the case statements. */ > + rtx gap_label = (default_label) ? default_label : fallback_label; > + > for (i = 0; i < ncases; i++) > if (labelvec[i] == 0) > { > - has_gaps = true; > - labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label); > + has_gaps = true; > + labelvec[i] = gen_rtx_LABEL_REF (Pmode, gap_label); > } > > - if (has_gaps) > + if (has_gaps && default_label) > { > /* There is at least one entry in the jump table that jumps > to default label. The default label can either be reached > @@ -1115,7 +1118,7 @@ void > expand_case (gswitch *stmt) > { > tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE; > - rtx_code_label *default_label = NULL; > + rtx_code_label *default_label; > unsigned int count, uniq; > int i; > int ncases = gimple_switch_num_labels (stmt); > @@ -1232,9 +1235,20 @@ expand_case (gswitch *stmt) > case_list, default_label, > default_prob); > else > - emit_case_dispatch_table (index_expr, index_type, > - case_list, default_label, > - minval, maxval, range, bb); > + { > + /* If the default case is unreachable, then set default_label to NULL > + so that we omit the range check when generating the dispatch table. > + We also remove the edge to the unreachable default case. The block > + itself will be automatically removed later. */ > + if (gimple_unreachable_bb_p (default_edge->dest)) > + { > + default_label = NULL; > + remove_edge (default_edge); > + } > + emit_case_dispatch_table (index_expr, index_type, > + case_list, default_label, > + minval, maxval, range, bb); > + } > > reorder_insns (NEXT_INSN (before_case), get_last_insn (), before_case); > > Index: gcc/tree-ssa-ccp.c > =================================================================== > --- gcc/tree-ssa-ccp.c (revision 247291) > +++ gcc/tree-ssa-ccp.c (working copy) > @@ -2715,7 +2715,8 @@ optimize_unreachable (gimple_stmt_iterat > } > else > { > - /* Todo: handle other cases, f.i. switch statement. */ > + /* Todo: handle other cases. Note that unreachable switch case > + statements have already been removed. */ > continue; > } > > Index: gcc/testsuite/gcc.target/powerpc/pr51513.c > =================================================================== > --- gcc/testsuite/gcc.target/powerpc/pr51513.c (nonexistent) > +++ gcc/testsuite/gcc.target/powerpc/pr51513.c (working copy) > @@ -0,0 +1,25 @@ > +/* { dg-do compile { target { powerpc*-*-linux* } } } */ > +/* { dg-options "-O2 -fjump-tables --param case-values-threshold=1" } */ > +/* Verify we created a jump table. */ > +/* { dg-final { scan-assembler-times "mtctr " 1 } } */ > +/* { dg-final { scan-assembler-times "bctr" 1 } } */ > +/* Verify we eliminated the range check. */ > +/* { dg-final { scan-assembler-not "cmpldi" } } */ > +/* { dg-final { scan-assembler-not "cmplwi" } } */ > + > +long > +bug (long cond, long v0, long v1, long v2) > +{ > + switch (cond) > + { > + case 0: > + return v0; > + case 1: > + return v1; > + case 2: > + return v2; > + default: > + __builtin_unreachable (); > + } > + __builtin_abort (); > +} > Index: gcc/testsuite/gcc.dg/predict-13.c > =================================================================== > --- gcc/testsuite/gcc.dg/predict-13.c (revision 247291) > +++ gcc/testsuite/gcc.dg/predict-13.c (working copy) > @@ -10,9 +10,9 @@ int main(int argc, char **argv) > case 2: > return 2; > case 3: > - __builtin_unreachable(); > + __builtin_abort(); > case 4: > - __builtin_unreachable(); > + __builtin_abort(); > default: > return 5; > } > Index: gcc/testsuite/gcc.dg/predict-14.c > =================================================================== > --- gcc/testsuite/gcc.dg/predict-14.c (revision 247291) > +++ gcc/testsuite/gcc.dg/predict-14.c (working copy) > @@ -6,11 +6,11 @@ int main(int argc, char **argv) > switch (argc) > { > case 1: > - __builtin_unreachable(); > + __builtin_abort(); > case 4: > - __builtin_unreachable(); > + __builtin_abort(); > default: > - __builtin_unreachable(); > + __builtin_abort(); > } > > return 10; > >