diff options
author | Patrick Palka <ppalka@gcc.gnu.org> | 2016-08-05 23:29:53 +0000 |
---|---|---|
committer | Patrick Palka <ppalka@gcc.gnu.org> | 2016-08-05 23:29:53 +0000 |
commit | 5c3e5002db1096170c8dd33413842e91bfcb61d8 (patch) | |
tree | 79bec8abe360b6fb22f3048f60ff643598e1a6b3 /gcc/tree-vrp.c | |
parent | b10d44efe5bb64662a55fe74696b8c2ca2d17303 (diff) | |
download | gcc-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.c | 61 |
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; |