diff options
author | Martin Liska <mliska@suse.cz> | 2017-09-05 10:12:27 +0200 |
---|---|---|
committer | Martin Liska <marxin@gcc.gnu.org> | 2017-09-05 08:12:27 +0000 |
commit | 02e637d86f9ecb6d0e368438291bb6f6f8feb3ab (patch) | |
tree | 93af2d7dae66c7bb229217f75ae4b0d99853f7c7 /gcc/tree-cfgcleanup.c | |
parent | b471c5c6cf2bfe51699b7fcbcffc34024ff7bfce (diff) | |
download | gcc-02e637d86f9ecb6d0e368438291bb6f6f8feb3ab.zip gcc-02e637d86f9ecb6d0e368438291bb6f6f8feb3ab.tar.gz gcc-02e637d86f9ecb6d0e368438291bb6f6f8feb3ab.tar.bz2 |
Learn CFG cleanup to transform single case switches to gcond.
2017-09-05 Martin Liska <mliska@suse.cz>
PR tree-optimization/82032
* tree-cfg.c (generate_range_test): New function.
* tree-cfg.h (generate_range_test): Declared here.
* tree-cfgcleanup.c (convert_single_case_switch): New function.
(cleanup_control_expr_graph): Use it.
* tree-switch-conversion.c (try_switch_expansion): Remove
assert.
(emit_case_nodes): Use generate_range_test.
2017-09-05 Martin Liska <mliska@suse.cz>
PR tree-optimization/82032
* g++.dg/other/pr82032.C: New test.
* gcc.dg/tree-ssa/pr68198.c: Update scanned pattern.
* gcc.dg/tree-ssa/vrp34.c: Likewise.
* gcc.dg/switch-10.c: Likewise.
From-SVN: r251690
Diffstat (limited to 'gcc/tree-cfgcleanup.c')
-rw-r--r-- | gcc/tree-cfgcleanup.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index c6e5c8d..a7053d7 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -74,6 +74,49 @@ remove_fallthru_edge (vec<edge, va_gc> *ev) return false; } +/* Convert a SWTCH with single non-default case to gcond and replace it + at GSI. */ + +static bool +convert_single_case_switch (gswitch *swtch, gimple_stmt_iterator &gsi) +{ + if (gimple_switch_num_labels (swtch) != 2) + return false; + + tree index = gimple_switch_index (swtch); + tree default_label = CASE_LABEL (gimple_switch_default_label (swtch)); + tree label = gimple_switch_label (swtch, 1); + tree low = CASE_LOW (label); + tree high = CASE_HIGH (label); + + basic_block default_bb = label_to_block_fn (cfun, default_label); + basic_block case_bb = label_to_block_fn (cfun, CASE_LABEL (label)); + + basic_block bb = gimple_bb (swtch); + gcond *cond; + + /* Replace switch statement with condition statement. */ + if (high) + { + tree lhs, rhs; + generate_range_test (bb, index, low, high, &lhs, &rhs); + cond = gimple_build_cond (LE_EXPR, lhs, rhs, NULL_TREE, NULL_TREE); + } + else + cond = gimple_build_cond (EQ_EXPR, index, + fold_convert (TREE_TYPE (index), low), + NULL_TREE, NULL_TREE); + + gsi_replace (&gsi, cond, true); + + /* Update edges. */ + edge case_edge = find_edge (bb, case_bb); + edge default_edge = find_edge (bb, default_bb); + + case_edge->flags |= EDGE_TRUE_VALUE; + default_edge->flags |= EDGE_FALSE_VALUE; + return true; +} /* Disconnect an unreachable block in the control expression starting at block BB. */ @@ -93,6 +136,12 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi, bool warned; tree val = NULL_TREE; + /* Try to convert a switch with just a single non-default case to + GIMPLE condition. */ + if (gimple_code (stmt) == GIMPLE_SWITCH + && convert_single_case_switch (as_a<gswitch *> (stmt), gsi)) + stmt = gsi_stmt (gsi); + fold_defer_overflow_warnings (); switch (gimple_code (stmt)) { |