+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
#include "rtl.h"
#include "tree.h"
#include "gimple.h"
+#include "cfghooks.h"
#include "predict.h"
#include "alloc-pool.h"
#include "memmodel.h"
#include "expr.h"
#include "langhooks.h"
#include "cfganal.h"
+#include "tree-cfg.h"
#include "params.h"
#include "dumpfile.h"
#include "builtins.h"
= 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
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);
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);
+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.
case 2:
return 2;
case 3:
- __builtin_unreachable();
+ __builtin_abort();
case 4:
- __builtin_unreachable();
+ __builtin_abort();
default:
return 5;
}
switch (argc)
{
case 1:
- __builtin_unreachable();
+ __builtin_abort();
case 4:
- __builtin_unreachable();
+ __builtin_abort();
default:
- __builtin_unreachable();
+ __builtin_abort();
}
return 10;
--- /dev/null
+/* { 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 ();
+}
&& 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:
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;
}
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++;
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);
}
else
{
- /* Todo: handle other cases, f.i. switch statement. */
+ /* Todo: handle other cases. Note that unreachable switch case
+ statements have already been removed. */
continue;
}