aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vrp.c
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@gcc.gnu.org>2016-08-05 23:29:53 +0000
committerPatrick Palka <ppalka@gcc.gnu.org>2016-08-05 23:29:53 +0000
commit5c3e5002db1096170c8dd33413842e91bfcb61d8 (patch)
tree79bec8abe360b6fb22f3048f60ff643598e1a6b3 /gcc/tree-vrp.c
parentb10d44efe5bb64662a55fe74696b8c2ca2d17303 (diff)
downloadgcc-5c3e5002db1096170c8dd33413842e91bfcb61d8.zip
gcc-5c3e5002db1096170c8dd33413842e91bfcb61d8.tar.gz
gcc-5c3e5002db1096170c8dd33413842e91bfcb61d8.tar.bz2
Improve forward jump threading of switch statements (PR18046)
gcc/ChangeLog: 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. gcc/testsuite/ChangeLog: PR tree-optimization/18046 * gcc.dg/tree-ssa/vrp105.c: New test. * gcc.dg/tree-ssa/vrp106.c: New test. From-SVN: r239181
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r--gcc/tree-vrp.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 5573023..44dfc84 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -10183,6 +10183,67 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
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;