aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/stmt.c41
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.dg/predict-13.c4
-rw-r--r--gcc/testsuite/gcc.dg/predict-14.c6
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr51513.c25
-rw-r--r--gcc/tree-cfg.c50
-rw-r--r--gcc/tree-cfg.h1
-rw-r--r--gcc/tree-ssa-ccp.c3
9 files changed, 114 insertions, 38 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 788b333..a3fe233 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2017-05-10 Peter Bergner <bergner@vnet.ibm.com>
+
+ * 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) <gap_label>: New local variable.
+ Use it to fill dispatch table gaps.
+ Test for default_label before updating probabilities.
+ (expand_case) <default_label>: 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 <cel@us.ibm.com>
* config/rs6000/rs6000-c: Add support for built-in functions
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 3d4e383..9b5157d 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 ef45039..3e465e4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2017-05-10 Peter Bergner <bergner@vnet.ibm.com>
+
+ * 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 <cel@us.ibm.com>
* 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 df82b7e..7fe714a 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 e241667..18ede8f 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 0000000..1c72a75
--- /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 a540416..77cb3d6 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 5582a62..a3af5a4 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 23f2adcb..80dcae5 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;
}