aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfgcleanup.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2017-09-05 10:12:27 +0200
committerMartin Liska <marxin@gcc.gnu.org>2017-09-05 08:12:27 +0000
commit02e637d86f9ecb6d0e368438291bb6f6f8feb3ab (patch)
tree93af2d7dae66c7bb229217f75ae4b0d99853f7c7 /gcc/tree-cfgcleanup.c
parentb471c5c6cf2bfe51699b7fcbcffc34024ff7bfce (diff)
downloadgcc-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.c49
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))
{