+2016-08-05 Patrick Palka <ppalka@gcc.gnu.org>
+
+ PR tree-optimization/18046
+ * tree-ssa-threadedge.c: Include cfganal.h.
+ (simplify_control_statement_condition): If simplifying a
+ GIMPLE_SWITCH, replace the index operand of the GIMPLE_SWITCH
+ with the dominating ASSERT_EXPR before handing it off to VRP.
+ Mention that a CASE_LABEL_EXPR may be returned.
+ (thread_around_empty_blocks): Adjust to handle
+ simplify_control_statement_condition() returning a
+ CASE_LABEL_EXPR.
+ (thread_through_normal_block): Likewise.
+ * tree-vrp.c (simplify_stmt_for_jump_threading): Simplify
+ a switch statement by trying to determine which case label
+ will be taken.
+
2016-08-05 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/69847
+2016-08-05 Patrick Palka <ppalka@gcc.gnu.org>
+
+ PR tree-optimization/18046
+ * gcc.dg/tree-ssa/vrp105.c: New test.
+ * gcc.dg/tree-ssa/vrp106.c: New test.
+
2016-08-05 Martin Sebor <msebor@redhat.com>
* g++.dg/cpp0x/constexpr-cast.C: Avoid assuming (void*)1 is spelled
--- /dev/null
+/* PR tree-optimization/18046 */
+/* { dg-options "-O2 -fdump-tree-vrp2-details" } */
+/* { dg-final { scan-tree-dump-times "Threaded jump" 1 "vrp2" } } */
+/* In the 2nd VRP pass (after PRE) we expect to thread the default label of the
+ 1st switch straight to that of the 2nd switch. */
+
+extern void foo (void);
+extern void bar (void);
+
+extern int i;
+void
+test (void)
+{
+ switch (i)
+ {
+ case 0:
+ foo ();
+ break;
+ case 1:
+ bar ();
+ break;
+ default:
+ break;
+ }
+
+ switch (i)
+ {
+ case 0:
+ foo ();
+ break;
+ case 1:
+ bar ();
+ break;
+ default:
+ break;
+ }
+}
--- /dev/null
+/* PR tree-optimization/18046 */
+/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+/* { dg-final { scan-tree-dump-times "Threaded jump" 1 "vrp1" } } */
+/* During VRP we expect to thread the true arm of the conditional through the switch
+ and to the BB that corresponds to the 7 ... 9 case label. */
+extern void foo (void);
+extern void bar (void);
+extern void baz (void);
+
+void
+test (int i)
+{
+ if (i >= 7 && i <= 8)
+ foo ();
+
+ switch (i)
+ {
+ case 1:
+ bar ();
+ break;
+ case 7:
+ case 8:
+ case 9:
+ baz ();
+ break;
+ }
+}
#include "tree-ssa-threadedge.h"
#include "tree-ssa-dom.h"
#include "gimple-fold.h"
+#include "cfganal.h"
/* To avoid code explosion due to jump threading, we limit the
number of statements we are going to copy. This variable
a condition using pass specific information.
Return the simplified condition or NULL if simplification could
- not be performed.
+ not be performed. When simplifying a GIMPLE_SWITCH, we may return
+ the CASE_LABEL_EXPR that will be taken.
The available expression table is referenced via AVAIL_EXPRS_STACK. */
/* If we haven't simplified to an invariant yet, then use the
pass specific callback to try and simplify it further. */
if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
- cached_lhs = (*simplify) (stmt, stmt, avail_exprs_stack);
+ {
+ if (handle_dominating_asserts && code == GIMPLE_SWITCH)
+ {
+ /* Replace the index operand of the GIMPLE_SWITCH with the
+ dominating ASSERT_EXPR before handing it off to VRP. If
+ simplification is possible, the simplified value will be a
+ CASE_LABEL_EXPR of the label that is proven to be taken. */
+ gswitch *dummy_switch = as_a<gswitch *> (gimple_copy (stmt));
+ gimple_switch_set_index (dummy_switch, cached_lhs);
+ cached_lhs = (*simplify) (dummy_switch, stmt, avail_exprs_stack);
+ ggc_free (dummy_switch);
+ }
+ else
+ cached_lhs = (*simplify) (stmt, stmt, avail_exprs_stack);
+ }
/* We couldn't find an invariant. But, callers of this
function may be able to do something useful with the
/* If the condition can be statically computed and we have not already
visited the destination edge, then add the taken edge to our thread
path. */
- if (cond && is_gimple_min_invariant (cond))
+ if (cond != NULL_TREE
+ && (is_gimple_min_invariant (cond)
+ || TREE_CODE (cond) == CASE_LABEL_EXPR))
{
- taken_edge = find_taken_edge (bb, cond);
+ if (TREE_CODE (cond) == CASE_LABEL_EXPR)
+ taken_edge = find_edge (bb, label_to_block (CASE_LABEL (cond)));
+ else
+ taken_edge = find_taken_edge (bb, cond);
if ((taken_edge->flags & EDGE_DFS_BACK) != 0)
return false;
if (!cond)
return 0;
- if (is_gimple_min_invariant (cond))
+ if (is_gimple_min_invariant (cond)
+ || TREE_CODE (cond) == CASE_LABEL_EXPR)
{
- edge taken_edge = find_taken_edge (e->dest, cond);
+ edge taken_edge;
+ if (TREE_CODE (cond) == CASE_LABEL_EXPR)
+ taken_edge = find_edge (e->dest,
+ label_to_block (CASE_LABEL (cond)));
+ else
+ taken_edge = find_taken_edge (e->dest, cond);
+
basic_block dest = (taken_edge ? taken_edge->dest : NULL);
/* DEST could be NULL for a computed jump to an absolute
gimple_cond_rhs (cond_stmt),
within_stmt);
+ /* We simplify a switch statement by trying to determine which case label
+ will be taken. If we are successful then we return the corresponding
+ CASE_LABEL_EXPR. */
+ if (gswitch *switch_stmt = dyn_cast <gswitch *> (stmt))
+ {
+ tree op = gimple_switch_index (switch_stmt);
+ if (TREE_CODE (op) != SSA_NAME)
+ return NULL_TREE;
+
+ value_range *vr = get_value_range (op);
+ if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
+ || symbolic_range_p (vr))
+ return NULL_TREE;
+
+ if (vr->type == VR_RANGE)
+ {
+ size_t i, j;
+ /* Get the range of labels that contain a part of the operand's
+ value range. */
+ find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+
+ /* Is there only one such label? */
+ if (i == j)
+ {
+ tree label = gimple_switch_label (switch_stmt, i);
+
+ /* The i'th label will be taken only if the value range of the
+ operand is entirely within the bounds of this label. */
+ if (CASE_HIGH (label) != NULL_TREE
+ ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
+ && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
+ : (tree_int_cst_equal (CASE_LOW (label), vr->min)
+ && tree_int_cst_equal (vr->min, vr->max)))
+ return label;
+ }
+
+ /* If there are no such labels then the default label will be
+ taken. */
+ if (i > j)
+ return gimple_switch_label (switch_stmt, 0);
+ }
+
+ if (vr->type == VR_ANTI_RANGE)
+ {
+ unsigned n = gimple_switch_num_labels (switch_stmt);
+ tree min_label = gimple_switch_label (switch_stmt, 1);
+ tree max_label = gimple_switch_label (switch_stmt, n - 1);
+
+ /* The default label will be taken only if the anti-range of the
+ operand is entirely outside the bounds of all the (non-default)
+ case labels. */
+ if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+ && (CASE_HIGH (max_label) != NULL_TREE
+ ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
+ : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+ return gimple_switch_label (switch_stmt, 0);
+ }
+
+ return NULL_TREE;
+ }
+
if (gassign *assign_stmt = dyn_cast <gassign *> (stmt))
{
value_range new_vr = VR_INITIALIZER;