From 34f3dfc228c3d7b94adbacb1cb98845f2ad93b7b Mon Sep 17 00:00:00 2001 From: bergner Date: Wed, 10 May 2017 16:44:45 +0000 Subject: [PATCH] gcc/ * tree-cfg.c (gimple_seq_unreachable_p): New function. (assert_unreachable_fallthru_edge_p): Use it. (group_case_labels_stmt): Likewise. * tree-cfg.h: Prototype it. * stmt.c: Include cfghooks.h and tree-cfg.h. (emit_case_dispatch_table) : New local variable. Use it to fill dispatch table gaps. Test for default_label before updating probabilities. (expand_case) : Remove unneeded initialization. Test for unreachable default case statement and remove its edge. Set default_label accordingly. * tree-ssa-ccp.c (optimize_unreachable): Update comment. gcc/testsuite/ * gcc.target/powerpc/pr51513.c: New test. * gcc.dg/predict-13.c: Replace __builtin_unreachable() with __builtin_abort(). * gcc.dg/predict-14.c: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@247844 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 15 +++++++++ gcc/stmt.c | 41 ++++++++++++++++-------- gcc/testsuite/ChangeLog | 7 +++++ gcc/testsuite/gcc.dg/predict-13.c | 4 +-- gcc/testsuite/gcc.dg/predict-14.c | 6 ++-- gcc/testsuite/gcc.target/powerpc/pr51513.c | 25 +++++++++++++++ gcc/tree-cfg.c | 50 ++++++++++++++++++------------ gcc/tree-cfg.h | 1 + gcc/tree-ssa-ccp.c | 3 +- 9 files changed, 114 insertions(+), 38 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr51513.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 788b33306f1..a3fe233c69c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2017-05-10 Peter Bergner + + * tree-cfg.c (gimple_seq_unreachable_p): New function. + (assert_unreachable_fallthru_edge_p): Use it. + (group_case_labels_stmt): Likewise. + * tree-cfg.h: Prototype it. + * stmt.c: Include cfghooks.h and tree-cfg.h. + (emit_case_dispatch_table) : New local variable. + Use it to fill dispatch table gaps. + Test for default_label before updating probabilities. + (expand_case) : Remove unneeded initialization. + Test for unreachable default case statement and remove its edge. + Set default_label accordingly. + * tree-ssa-ccp.c (optimize_unreachable): Update comment. + 2017-05-10 Carl Love * config/rs6000/rs6000-c: Add support for built-in functions diff --git a/gcc/stmt.c b/gcc/stmt.c index 3d4e383c91c..9b5157d345b 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #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. If not see #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_expr, tree index_type, = 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,21 @@ 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 (EDGE_COUNT (default_edge->dest->succs) == 0 + && gimple_seq_unreachable_p (bb_seq (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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ef45039217c..3e465e47d16 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-05-10 Peter Bergner + + * gcc.target/powerpc/pr51513.c: New test. + * gcc.dg/predict-13.c: Replace __builtin_unreachable() with + __builtin_abort(). + * gcc.dg/predict-14.c: Likewise. + 2017-05-10 Carl Love * gcc.target/powerpc/builtins-3.c: Add tests for the new built-ins to to the test suite file. diff --git a/gcc/testsuite/gcc.dg/predict-13.c b/gcc/testsuite/gcc.dg/predict-13.c index df82b7e708b..7fe714a0d72 100644 --- a/gcc/testsuite/gcc.dg/predict-13.c +++ b/gcc/testsuite/gcc.dg/predict-13.c @@ -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; } diff --git a/gcc/testsuite/gcc.dg/predict-14.c b/gcc/testsuite/gcc.dg/predict-14.c index e24166714ce..18ede8f39c0 100644 --- a/gcc/testsuite/gcc.dg/predict-14.c +++ b/gcc/testsuite/gcc.dg/predict-14.c @@ -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; diff --git a/gcc/testsuite/gcc.target/powerpc/pr51513.c b/gcc/testsuite/gcc.target/powerpc/pr51513.c new file mode 100644 index 00000000000..1c72a75502a --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr51513.c @@ -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 (); +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index a540416cbb5..77cb3d62368 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -452,6 +452,31 @@ computed_goto_p (gimple *t) && TREE_CODE (gimple_goto_dest (t)) != LABEL_DECL); } +/* Returns true if the sequence of statements STMTS only contains + a call to __builtin_unreachable (). */ + +bool +gimple_seq_unreachable_p (gimple_seq stmts) +{ + if (stmts == NULL) + return false; + + gimple_stmt_iterator gsi = gsi_last (stmts); + + if (!gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_UNREACHABLE)) + return false; + + for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + if (gimple_code (stmt) != GIMPLE_LABEL + && !is_gimple_debug (stmt) + && !gimple_clobber_p (stmt)) + return false; + } + return true; +} + /* 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: @@ -476,22 +501,7 @@ assert_unreachable_fallthru_edge_p (edge e) 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_seq_unreachable_p (bb_seq (other_bb)); } return false; } @@ -1668,9 +1678,11 @@ 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 + || (EDGE_COUNT (base_bb->succs) == 0 + && gimple_seq_unreachable_p (bb_seq (base_bb)))) { gimple_switch_set_label (stmt, i, NULL_TREE); i++; diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h index 5582a62b0f5..a3af5a40567 100644 --- a/gcc/tree-cfg.h +++ b/gcc/tree-cfg.h @@ -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_seq_unreachable_p (gimple_seq); extern bool assert_unreachable_fallthru_edge_p (edge); extern void delete_tree_cfg_annotations (function *); extern gphi *get_virtual_phi (basic_block); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 23f2adcb9c4..80dcae5af1f 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -2715,7 +2715,8 @@ optimize_unreachable (gimple_stmt_iterator i) } else { - /* Todo: handle other cases, f.i. switch statement. */ + /* Todo: handle other cases. Note that unreachable switch case + statements have already been removed. */ continue; } -- 2.11.4.GIT