]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Learn CFG cleanup to transform single case switches to gcond.
authorMartin Liska <mliska@suse.cz>
Tue, 5 Sep 2017 08:12:27 +0000 (10:12 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Tue, 5 Sep 2017 08:12:27 +0000 (08:12 +0000)
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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/pr82032.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/switch-10.c
gcc/testsuite/gcc.dg/tree-ssa/pr68198.c
gcc/testsuite/gcc.dg/tree-ssa/vrp34.c
gcc/tree-cfg.c
gcc/tree-cfg.h
gcc/tree-cfgcleanup.c
gcc/tree-switch-conversion.c

index e7e8c2319c2d2a20973e1f457fc0650d3b09c668..7a824f82a2ecb6b9080e611c3b13e5a926b4fe2e 100644 (file)
@@ -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
index 91aa16f5d3653762cace4e10689b86f5f5d9f916..74790654be854a22690a351d66098fc9ca2f4dff 100644 (file)
@@ -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 (file)
index 0000000..607bf85
--- /dev/null
@@ -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;
+}
index 0ffc9eb5757162186feb1ac5c9f735e3f96fe4bc..9e5926745b88c39a3a2309fe7b10949a3ed5da96 100644 (file)
@@ -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" } }  */
index 16097d7e2bc5e8fc11c764c9601b15e1a11c60b2..59d562e156c2da3b70374d5eae347c7bd09db9a1 100644 (file)
@@ -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"} } */
index 142e56c1641eb0e1b4e42849efe0995e551f8752..d2a36a706f23c5bf344b6354a2b61f4320f42ff6 100644 (file)
@@ -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" } } */
index b7593068ea9ee3bfa6fb2b78ac7004aa37ada133..b601012cfeddb546ee7a3d1ac02e2eb19b755f56 100644 (file)
@@ -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.  */
 
index 66be43657bc952975b08e8912120c57bf32eca50..7a08cb074f733835d9def0c21a19a9d1945cbf5d 100644 (file)
@@ -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.  */
 
index c6e5c8da03c3391e1da693281d6ebf8ff2f2b3b2..a7053d748c66b22f905f29dac4b28adfd3cb7cfc 100644 (file)
@@ -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))
        {
index d0d0897280437a2aa46092fc75dd272fa38fcd22..6d7c2c4902fa75c6fcdcf6765953373d747b9d1b 100644 (file)
@@ -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);
            }