aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/other/pr82032.C36
-rw-r--r--gcc/testsuite/gcc.dg/switch-10.c5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr68198.c6
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp34.c5
-rw-r--r--gcc/tree-cfg.c24
-rw-r--r--gcc/tree-cfg.h2
-rw-r--r--gcc/tree-cfgcleanup.c49
-rw-r--r--gcc/tree-switch-conversion.c27
10 files changed, 144 insertions, 29 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e7e8c23..7a824f8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+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-04 Uros Bizjak <ubizjak@gmail.com>
PR target/82098
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 91aa16f..7479065 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+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.
+
2017-09-04 Uros Bizjak <ubizjak@gmail.com>
* gcc.target/i386/mpx/mpx-os-support.h: New file.
diff --git a/gcc/testsuite/g++.dg/other/pr82032.C b/gcc/testsuite/g++.dg/other/pr82032.C
new file mode 100644
index 0000000..607bf85
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/pr82032.C
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -Wno-return-type" } */
+
+template <typename a> class b
+{
+public:
+ typename a::aa operator[] (typename a::c) { }
+};
+class d
+{
+public:
+ typedef long c;
+ typedef int aa;
+};
+struct e
+{
+ int af[4];
+ int ag;
+};
+b<d> f;
+bool
+g (e &i)
+{
+ for (int h; h; ++h)
+ switch (f[h])
+ {
+ case 'x':
+ case 'a':
+ i.af[h] = 3;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
diff --git a/gcc/testsuite/gcc.dg/switch-10.c b/gcc/testsuite/gcc.dg/switch-10.c
index 0ffc9eb..9e59267 100644
--- a/gcc/testsuite/gcc.dg/switch-10.c
+++ b/gcc/testsuite/gcc.dg/switch-10.c
@@ -1,6 +1,4 @@
/* { dg-options "-O2 -fdump-tree-cfg" } */
-/* { dg-final { scan-tree-dump "case 0:" "cfg" } } */
-/* { dg-final { scan-tree-dump-not "case 1 ... 255:" "cfg" } } */
#include <stdint.h>
void foo (void);
@@ -20,3 +18,6 @@ test (uint8_t ch)
break;
}
}
+
+/* Switch statement is converted to GIMPLE condition. */
+/* { dg-final { scan-tree-dump-not "switch" "cfg" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr68198.c b/gcc/testsuite/gcc.dg/tree-ssa/pr68198.c
index 16097d7..59d562e 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr68198.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr68198.c
@@ -37,7 +37,5 @@ c_finish_omp_clauses (tree clauses)
}
}
-/* There are 3 FSM jump threading opportunities, two of which will
- get filtered out. */
-/* { dg-final { scan-tree-dump-times "Registering FSM" 1 "thread1"} } */
-/* { dg-final { scan-tree-dump-times "FSM Thread through multiway branch without threading a multiway branch" 2 "thread1"} } */
+/* There are 3 FSM jump threading opportunities. */
+/* { dg-final { scan-tree-dump-times "Registering FSM" 3 "thread1"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp34.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp34.c
index 142e56c..d2a36a7 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp34.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp34.c
@@ -15,5 +15,6 @@ foo (int a)
}
}
-/* Both ifs should be optimized. */
-/* { dg-final { scan-tree-dump-times "if \\\(" 0 "vrp1" } } */
+/* Both ifs should be optimized (and switch statement will be the only if
+ in the function). */
+/* { dg-final { scan-tree-dump-times "if \\\(" 1 "vrp1" } } */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index b759306..b601012 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -8927,7 +8927,31 @@ extract_true_false_controlled_edges (basic_block dom, basic_block phiblock,
return true;
}
+/* Generate a range test LHS CODE RHS that determines whether INDEX is in the
+ range [low, high]. Place associated stmts before *GSI. */
+void
+generate_range_test (basic_block bb, tree index, tree low, tree high,
+ tree *lhs, tree *rhs)
+{
+ tree type = TREE_TYPE (index);
+ tree utype = unsigned_type_for (type);
+
+ low = fold_convert (type, low);
+ high = fold_convert (type, high);
+
+ tree tmp = make_ssa_name (type);
+ gassign *sub1
+ = gimple_build_assign (tmp, MINUS_EXPR, index, low);
+
+ *lhs = make_ssa_name (utype);
+ gassign *a = gimple_build_assign (*lhs, NOP_EXPR, tmp);
+
+ *rhs = fold_build2 (MINUS_EXPR, utype, high, low);
+ gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ gsi_insert_before (&gsi, sub1, GSI_SAME_STMT);
+ gsi_insert_before (&gsi, a, GSI_SAME_STMT);
+}
/* Emit return warnings. */
diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h
index 66be436..7a08cb0 100644
--- a/gcc/tree-cfg.h
+++ b/gcc/tree-cfg.h
@@ -109,6 +109,8 @@ extern basic_block insert_cond_bb (basic_block, gimple *, gimple *,
extern bool gimple_find_sub_bbs (gimple_seq, gimple_stmt_iterator *);
extern bool extract_true_false_controlled_edges (basic_block, basic_block,
edge *, edge *);
+extern void generate_range_test (basic_block bb, tree index, tree low,
+ tree high, tree *lhs, tree *rhs);
/* Return true if the LHS of a call should be removed. */
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))
{
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index d0d0897..6d7c2c4 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -2057,9 +2057,8 @@ try_switch_expansion (gswitch *stmt)
expressions being INTEGER_CST. */
gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
- /* Optimization of switch statements with only one label has already
- occurred, so we should never see them at this point. */
- gcc_assert (ncases > 1);
+ if (ncases == 1)
+ return false;
/* Find the default case target label. */
tree default_label = CASE_LABEL (gimple_switch_default_label (stmt));
@@ -2701,27 +2700,13 @@ emit_case_nodes (basic_block bb, tree index, case_node_ptr node,
}
else if (!low_bound && !high_bound)
{
- tree type = TREE_TYPE (index);
- tree utype = unsigned_type_for (type);
-
- tree lhs = make_ssa_name (type);
- gassign *sub1
- = gimple_build_assign (lhs, MINUS_EXPR, index, node->low);
-
- tree converted = make_ssa_name (utype);
- gassign *a = gimple_build_assign (converted, NOP_EXPR, lhs);
-
- tree rhs = fold_build2 (MINUS_EXPR, utype,
- fold_convert (type, node->high),
- fold_convert (type, node->low));
- gimple_stmt_iterator gsi = gsi_last_bb (bb);
- gsi_insert_before (&gsi, sub1, GSI_SAME_STMT);
- gsi_insert_before (&gsi, a, GSI_SAME_STMT);
-
+ tree lhs, rhs;
+ generate_range_test (bb, index, node->low, node->high,
+ &lhs, &rhs);
probability
= conditional_probability (default_prob,
subtree_prob + default_prob);
- bb = emit_cmp_and_jump_insns (bb, converted, rhs, GT_EXPR,
+ bb = emit_cmp_and_jump_insns (bb, lhs, rhs, GT_EXPR,
default_bb, probability,
phi_mapping);
}