tree-cfg.c (group_case_labels_stmt): Return whether we changed anything.
authorRichard Biener <rguenther@suse.de>
Thu, 29 Jun 2017 11:25:29 +0000 (11:25 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 29 Jun 2017 11:25:29 +0000 (11:25 +0000)
2017-06-29  Richard Biener  <rguenther@suse.de>

* tree-cfg.c (group_case_labels_stmt): Return whether we changed
anything.
(group_case_labels): Likewise.
(find_taken_edge): Push sanity checking on val to workers...
(find_taken_edge_cond_expr): ... here
(find_taken_edge_switch_expr): ... and here, handle cases
with just a default label.
* tree-cfg.h (group_case_labels_stmt): Adjust prototype.
(group_case_labels): Likewise.
* tree-cfgcleanup.c (execute_cleanup_cfg_post_optimizing): When
group_case_labels does anything cleanup the CFG again.

From-SVN: r249780

gcc/ChangeLog
gcc/tree-cfg.c
gcc/tree-cfg.h
gcc/tree-cfgcleanup.c

index bed5b90f86820d8da8fe6be98599c7004d7b8f79..578068bd3436cd5fb91f18296a4651be9a3e8f12 100644 (file)
@@ -1,3 +1,17 @@
+2017-06-29  Richard Biener  <rguenther@suse.de>
+
+       * tree-cfg.c (group_case_labels_stmt): Return whether we changed
+       anything.
+       (group_case_labels): Likewise.
+       (find_taken_edge): Push sanity checking on val to workers...
+       (find_taken_edge_cond_expr): ... here
+       (find_taken_edge_switch_expr): ... and here, handle cases
+       with just a default label.
+       * tree-cfg.h (group_case_labels_stmt): Adjust prototype.
+       (group_case_labels): Likewise.
+       * tree-cfgcleanup.c (execute_cleanup_cfg_post_optimizing): When
+       group_case_labels does anything cleanup the CFG again.
+
 2017-06-29  Bin Cheng  <bin.cheng@arm.com>
 
        PR tree-optimization/81196
index 589508df0443df378899a8307375f89af2f1cf87..e82f95b48ddbb8c2067b1a9bbee15f27537bd3ec 100644 (file)
@@ -1675,7 +1675,7 @@ cleanup_dead_labels (void)
    the ones jumping to the same label.
    Eg. three separate entries 1: 2: 3: become one entry 1..3:  */
 
-void
+bool
 group_case_labels_stmt (gswitch *stmt)
 {
   int old_size = gimple_switch_num_labels (stmt);
@@ -1759,23 +1759,27 @@ group_case_labels_stmt (gswitch *stmt)
 
   gcc_assert (new_size <= old_size);
   gimple_switch_set_num_labels (stmt, new_size);
+  return new_size < old_size;
 }
 
 /* Look for blocks ending in a multiway branch (a GIMPLE_SWITCH),
    and scan the sorted vector of cases.  Combine the ones jumping to the
    same label.  */
 
-void
+bool
 group_case_labels (void)
 {
   basic_block bb;
+  bool changed = false;
 
   FOR_EACH_BB_FN (bb, cfun)
     {
       gimple *stmt = last_stmt (bb);
       if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
-       group_case_labels_stmt (as_a <gswitch *> (stmt));
+       changed |= group_case_labels_stmt (as_a <gswitch *> (stmt));
     }
+
+  return changed;
 }
 
 /* Checks whether we can merge block B into block A.  */
@@ -2243,15 +2247,8 @@ find_taken_edge (basic_block bb, tree val)
 
   stmt = last_stmt (bb);
 
-  gcc_assert (stmt);
   gcc_assert (is_ctrl_stmt (stmt));
 
-  if (val == NULL)
-    return NULL;
-
-  if (!is_gimple_min_invariant (val))
-    return NULL;
-
   if (gimple_code (stmt) == GIMPLE_COND)
     return find_taken_edge_cond_expr (bb, val);
 
@@ -2266,7 +2263,8 @@ find_taken_edge (basic_block bb, tree val)
          It may be the case that we only need to allow the LABEL_REF to
          appear inside an ADDR_EXPR, but we also allow the LABEL_REF to
          appear inside a LABEL_EXPR just to be safe.  */
-      if ((TREE_CODE (val) == ADDR_EXPR || TREE_CODE (val) == LABEL_EXPR)
+      if (val
+         && (TREE_CODE (val) == ADDR_EXPR || TREE_CODE (val) == LABEL_EXPR)
          && TREE_CODE (TREE_OPERAND (val, 0)) == LABEL_DECL)
        return find_taken_edge_computed_goto (bb, TREE_OPERAND (val, 0));
       return NULL;
@@ -2304,9 +2302,12 @@ find_taken_edge_cond_expr (basic_block bb, tree val)
 {
   edge true_edge, false_edge;
 
+  if (val == NULL
+      || TREE_CODE (val) != INTEGER_CST)
+    return NULL;
+
   extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
 
-  gcc_assert (TREE_CODE (val) == INTEGER_CST);
   return (integer_zerop (val) ? false_edge : true_edge);
 }
 
@@ -2322,7 +2323,12 @@ find_taken_edge_switch_expr (gswitch *switch_stmt, basic_block bb,
   edge e;
   tree taken_case;
 
-  taken_case = find_case_label_for_value (switch_stmt, val);
+  if (gimple_switch_num_labels (switch_stmt) == 1)
+    taken_case = gimple_switch_default_label (switch_stmt);
+  else if (! val || TREE_CODE (val) != INTEGER_CST)
+    return NULL;
+  else
+    taken_case = find_case_label_for_value (switch_stmt, val);
   dest_bb = label_to_block (CASE_LABEL (taken_case));
 
   e = find_edge (bb, dest_bb);
index a0ef479ef20f06930a1511eb9d938aef3714d94d..4e1b5b076d5b2cdedceab90df9e571d1c7a1cb54 100644 (file)
@@ -36,8 +36,8 @@ extern void end_recording_case_labels (void);
 extern basic_block label_to_block_fn (struct function *, tree);
 #define label_to_block(t) (label_to_block_fn (cfun, t))
 extern void cleanup_dead_labels (void);
-extern void group_case_labels_stmt (gswitch *);
-extern void group_case_labels (void);
+extern bool group_case_labels_stmt (gswitch *);
+extern bool group_case_labels (void);
 extern void replace_uses_by (tree, tree);
 extern basic_block single_noncomplex_succ (basic_block bb);
 extern void notice_special_calls (gcall *);
index 8bb5e237395259dfa7d49ccb3b1ab1932f1cd781..c904d0cf57f42a729771d05a754f09a80ca419e2 100644 (file)
@@ -1205,7 +1205,8 @@ execute_cleanup_cfg_post_optimizing (void)
     }
   maybe_remove_unreachable_handlers ();
   cleanup_dead_labels ();
-  group_case_labels ();
+  if (group_case_labels ())
+    todo |= TODO_cleanup_cfg;
   if ((flag_compare_debug_opt || flag_compare_debug)
       && flag_dump_final_insns)
     {