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-ssa-threadedge.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-ssa-threadedge.c')
-rw-r--r-- | gcc/tree-ssa-threadedge.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index de671b9..170e456 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #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 @@ -390,7 +391,8 @@ static tree simplify_control_stmt_condition_1 (edge, gimple *, 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. */ @@ -513,7 +515,21 @@ simplify_control_stmt_condition (edge e, /* 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 @@ -938,9 +954,14 @@ thread_around_empty_blocks (edge taken_edge, /* 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; @@ -1069,9 +1090,16 @@ thread_through_normal_block (edge e, 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 |