re PR ipa/44563 (GCC uses a lot of RAM when compiling a large numbers of functions)
authorRichard Biener <rguenther@suse.de>
Fri, 13 Mar 2015 08:47:14 +0000 (08:47 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 13 Mar 2015 08:47:14 +0000 (08:47 +0000)
2015-03-10  Richard Biener  <rguenther@suse.de>

PR middle-end/44563
* tree-cfgcleanup.c (split_bb_on_noreturn_calls): Remove.
(cleanup_tree_cfg_1): Do not call it.
(execute_cleanup_cfg_post_optimizing): Fixup the CFG here.
(fixup_noreturn_call): Mark the stmt as control altering.
* tree-cfg.c (execute_fixup_cfg): Do not dump the function
here.
(pass_data_fixup_cfg): Produce a dump file.
* tree-ssa-dom.c: Include tree-cfgcleanup.h.
(need_noreturn_fixup): New global.
(pass_dominator::execute): Fixup queued noreturn calls.
(optimize_stmt): Queue calls that became noreturn for fixup.
* tree-ssa-forwprop.c (pass_forwprop::execute): Likewise.
* tree-ssa-pre.c: Include tree-cfgcleanup.h.
(el_to_fixup): New global.
(eliminate_dom_walker::before_dom_childre): Queue calls that
became noreturn for fixup.
(eliminate): Fixup queued noreturn calls.
* tree-ssa-propagate.c: Include tree-cfgcleanup.h.
(substitute_and_fold_dom_walker): New member stmts_to_fixup.
(substitute_and_fold_dom_walker::before_dom_children): Queue
alls that became noreturn for fixup.
(substitute_and_fold): Fixup queued noreturn calls.

From-SVN: r221409

gcc/ChangeLog
gcc/tree-cfg.c
gcc/tree-cfgcleanup.c
gcc/tree-ssa-dom.c
gcc/tree-ssa-forwprop.c
gcc/tree-ssa-pre.c
gcc/tree-ssa-propagate.c

index 5692ea46ce0e2cc115e5f3dbf8cf5756a0b65902..18ada578fd6fd337756aeb3472c857b9625729f6 100644 (file)
@@ -1,3 +1,29 @@
+2015-03-13  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/44563
+       * tree-cfgcleanup.c (split_bb_on_noreturn_calls): Remove.
+       (cleanup_tree_cfg_1): Do not call it.
+       (execute_cleanup_cfg_post_optimizing): Fixup the CFG here.
+       (fixup_noreturn_call): Mark the stmt as control altering.
+       * tree-cfg.c (execute_fixup_cfg): Do not dump the function
+       here.
+       (pass_data_fixup_cfg): Produce a dump file.
+       * tree-ssa-dom.c: Include tree-cfgcleanup.h.
+       (need_noreturn_fixup): New global.
+       (pass_dominator::execute): Fixup queued noreturn calls.
+       (optimize_stmt): Queue calls that became noreturn for fixup.
+       * tree-ssa-forwprop.c (pass_forwprop::execute): Likewise.
+       * tree-ssa-pre.c: Include tree-cfgcleanup.h.
+       (el_to_fixup): New global.
+       (eliminate_dom_walker::before_dom_childre): Queue calls that
+       became noreturn for fixup.
+       (eliminate): Fixup queued noreturn calls.
+       * tree-ssa-propagate.c: Include tree-cfgcleanup.h.
+       (substitute_and_fold_dom_walker): New member stmts_to_fixup.
+       (substitute_and_fold_dom_walker::before_dom_children): Queue
+       alls that became noreturn for fixup.
+       (substitute_and_fold): Fixup queued noreturn calls.
+
 2015-03-12  Jan Hubicka  <hubicka@ucw.cz>
 
        * ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P
index e1bc14351baf749d359d7c9aef9548d8799f8f58..ac12a585c5174ec3ed061bb03664b6578b6a119a 100644 (file)
@@ -8721,10 +8721,6 @@ execute_fixup_cfg (void)
   if (count_scale != REG_BR_PROB_BASE)
     compute_function_frequency ();
 
-  /* Dump a textual representation of the flowgraph.  */
-  if (dump_file)
-    gimple_dump_cfg (dump_file, dump_flags);
-
   if (current_loops
       && (todo & TODO_cleanup_cfg))
     loops_state_set (LOOPS_NEED_FIXUP);
@@ -8737,7 +8733,7 @@ namespace {
 const pass_data pass_data_fixup_cfg =
 {
   GIMPLE_PASS, /* type */
-  "*free_cfg_annotations", /* name */
+  "fixup_cfg", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
   TV_NONE, /* tv_id */
   PROP_cfg, /* properties_required */
index 5c5c7bace75d62b7a6e66322593dfe3511a92c79..f5a21a30f85c0975c7bdcded3e12523fb4e38587 100644 (file)
@@ -625,35 +625,13 @@ fixup_noreturn_call (gimple stmt)
       update_stmt (stmt);
     }
 
+  /* Mark the call as altering control flow.  */
+  gimple_call_set_ctrl_altering (stmt, true);
+
   return remove_fallthru_edge (bb->succs);
 }
 
 
-/* Split basic blocks on calls in the middle of a basic block that are now
-   known not to return, and remove the unreachable code.  */
-
-static bool
-split_bb_on_noreturn_calls (basic_block bb)
-{
-  bool changed = false;
-  gimple_stmt_iterator gsi;
-
-  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-    {
-      gimple stmt = gsi_stmt (gsi);
-
-      if (!is_gimple_call (stmt))
-       continue;
-
-      if (gimple_call_noreturn_p (stmt))
-       changed |= fixup_noreturn_call (stmt);
-    }
-
-  if (changed)
-    bitmap_set_bit (cfgcleanup_altered_bbs, bb->index);
-  return changed;
-}
-
 /* Tries to cleanup cfg in basic block BB.  Returns true if anything
    changes.  */
 
@@ -703,10 +681,7 @@ cleanup_tree_cfg_1 (void)
     {
       bb = BASIC_BLOCK_FOR_FN (cfun, i);
       if (bb)
-       {
-         retval |= cleanup_tree_cfg_bb (bb);
-         retval |= split_bb_on_noreturn_calls (bb);
-       }
+       retval |= cleanup_tree_cfg_bb (bb);
     }
 
   /* Now process the altered blocks, as long as any are available.  */
@@ -722,10 +697,6 @@ cleanup_tree_cfg_1 (void)
        continue;
 
       retval |= cleanup_tree_cfg_bb (bb);
-
-      /* Rerun split_bb_on_noreturn_calls, in case we have altered any noreturn
-        calls.  */
-      retval |= split_bb_on_noreturn_calls (bb);
     }
 
   end_recording_case_labels ();
@@ -1111,9 +1082,12 @@ make_pass_merge_phi (gcc::context *ctxt)
 static unsigned int
 execute_cleanup_cfg_post_optimizing (void)
 {
-  unsigned int todo = 0;
+  unsigned int todo = execute_fixup_cfg ();
   if (cleanup_tree_cfg ())
-    todo |= TODO_update_ssa;
+    {
+      todo &= ~TODO_cleanup_cfg;
+      todo |= TODO_update_ssa;
+    }
   maybe_remove_unreachable_handlers ();
   cleanup_dead_labels ();
   group_case_labels ();
index d230ce1c7b38637ce539a86f9c3f46206a04b501..ea49eb7c3c79a6cf9a4083c78758d71b77c29c6a 100644 (file)
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-dom.h"
 #include "inchash.h"
 #include "gimplify.h"
+#include "tree-cfgcleanup.h"
 
 /* This file implements optimizations on the dominator tree.  */
 
@@ -246,6 +247,7 @@ static bool cfg_altered;
 /* Bitmap of blocks that have had EH statements cleaned.  We should
    remove their dead edges eventually.  */
 static bitmap need_eh_cleanup;
+static vec<gimple> need_noreturn_fixup;
 
 /* Statistics for dominator optimizations.  */
 struct opt_stats_d
@@ -885,6 +887,7 @@ pass_dominator::execute (function *fun)
   avail_exprs_stack.create (20);
   const_and_copies_stack.create (20);
   need_eh_cleanup = BITMAP_ALLOC (NULL);
+  need_noreturn_fixup.create (0);
 
   calculate_dominance_info (CDI_DOMINATORS);
   cfg_altered = false;
@@ -967,6 +970,23 @@ pass_dominator::execute (function *fun)
       bitmap_clear (need_eh_cleanup);
     }
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk or before
+     jump threading finished.  Do this in reverse order so we don't
+     inadvertedly remove a stmt we want to fixup by visiting a dominating
+     now noreturn call first.  */
+  while (!need_noreturn_fixup.is_empty ())
+    {
+      gimple stmt = need_noreturn_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      fixup_noreturn_call (stmt);
+    }
+
   statistics_counter_event (fun, "Redundant expressions eliminated",
                            opt_stats.num_re);
   statistics_counter_event (fun, "Constants propagated",
@@ -986,7 +1006,7 @@ pass_dominator::execute (function *fun)
 
   /* Free asserted bitmaps and stacks.  */
   BITMAP_FREE (need_eh_cleanup);
-
+  need_noreturn_fixup.release ();
   avail_exprs_stack.release ();
   const_and_copies_stack.release ();
 
@@ -2364,8 +2384,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
   gimple stmt, old_stmt;
   bool may_optimize_p;
   bool modified_p = false;
+  bool was_noreturn;
 
   old_stmt = stmt = gsi_stmt (si);
+  was_noreturn = is_gimple_call (stmt) && gimple_call_noreturn_p (stmt);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -2545,6 +2567,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si)
          if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "  Flagged to clear EH edges.\n");
        }
+
+      if (!was_noreturn
+         && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+       need_noreturn_fixup.safe_push (stmt);
     }
 }
 
index d8db20acd3cbf010fcdeaa5e72f8c015cf41da70..93f92f33a59a92b3ef71f944f9749bdbba4d12ef 100644 (file)
@@ -2141,6 +2141,7 @@ pass_forwprop::execute (function *fun)
   lattice.quick_grow_cleared (num_ssa_names);
   int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun));
   int postorder_num = inverted_post_order_compute (postorder);
+  auto_vec<gimple, 4> to_fixup;
   to_purge = BITMAP_ALLOC (NULL);
   for (int i = 0; i < postorder_num; ++i)
     {
@@ -2340,6 +2341,8 @@ pass_forwprop::execute (function *fun)
          gimple stmt = gsi_stmt (gsi);
          gimple orig_stmt = stmt;
          bool changed = false;
+         bool was_noreturn = (is_gimple_call (stmt)
+                              && gimple_call_noreturn_p (stmt));
 
          /* Mark stmt as potentially needing revisiting.  */
          gimple_set_plf (stmt, GF_PLF_1, false);
@@ -2350,6 +2353,9 @@ pass_forwprop::execute (function *fun)
              stmt = gsi_stmt (gsi);
              if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
                bitmap_set_bit (to_purge, bb->index);
+             if (!was_noreturn
+                 && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+               to_fixup.safe_push (stmt);
              /* Cleanup the CFG if we simplified a condition to
                 true or false.  */
              if (gcond *cond = dyn_cast <gcond *> (stmt))
@@ -2470,6 +2476,22 @@ pass_forwprop::execute (function *fun)
   free (postorder);
   lattice.release ();
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!to_fixup.is_empty ())
+    {
+      gimple stmt = to_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      cfg_changed |= fixup_noreturn_call (stmt);
+    }
+
   cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
   BITMAP_FREE (to_purge);
 
index 83b48df8b4e390833912ae53e0b1354d18d7bcfe..c985e798696bd5271db6a2e49ee6f5b2b88337fb 100644 (file)
@@ -98,6 +98,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "tree-ssa-propagate.h"
 #include "ipa-utils.h"
+#include "tree-cfgcleanup.h"
 
 /* TODO:
 
@@ -3922,6 +3923,7 @@ compute_avail (void)
 
 /* Local state for the eliminate domwalk.  */
 static vec<gimple> el_to_remove;
+static vec<gimple> el_to_fixup;
 static unsigned int el_todo;
 static vec<tree> el_avail;
 static vec<tree> el_avail_stack;
@@ -4429,7 +4431,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
              /* When changing a call into a noreturn call, cfg cleanup
                 is needed to fix up the noreturn call.  */
              if (!was_noreturn && gimple_call_noreturn_p (stmt))
-               el_todo |= TODO_cleanup_cfg;
+               el_to_fixup.safe_push  (stmt);
            }
          else
            {
@@ -4529,6 +4531,7 @@ eliminate (bool do_pre)
   need_ab_cleanup = BITMAP_ALLOC (NULL);
 
   el_to_remove.create (0);
+  el_to_fixup.create (0);
   el_todo = 0;
   el_avail.create (num_ssa_names);
   el_avail_stack.create (0);
@@ -4580,6 +4583,25 @@ eliminate (bool do_pre)
     }
   el_to_remove.release ();
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!el_to_fixup.is_empty ())
+    {
+      stmt = el_to_fixup.pop ();
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+       }
+
+      if (fixup_noreturn_call (stmt))
+       el_todo |= TODO_cleanup_cfg;
+    }
+  el_to_fixup.release ();
+
   return el_todo;
 }
 
index 8b82f9e20866b9c338336c7ae99c18cdff8c1b3b..c3f9d3e1cdaa32afd7c7dc6918dbbee748e506ba 100644 (file)
@@ -67,6 +67,7 @@
 #include "value-prof.h"
 #include "domwalk.h"
 #include "cfgloop.h"
+#include "tree-cfgcleanup.h"
 
 /* This file implements a generic value propagation engine based on
    the same propagation used by the SSA-CCP algorithm [1].
@@ -1071,11 +1072,13 @@ public:
       fold_fn (fold_fn_), do_dce (do_dce_), something_changed (false)
     {
       stmts_to_remove.create (0);
+      stmts_to_fixup.create (0);
       need_eh_cleanup = BITMAP_ALLOC (NULL);
     }
     ~substitute_and_fold_dom_walker ()
     {
       stmts_to_remove.release ();
+      stmts_to_fixup.release ();
       BITMAP_FREE (need_eh_cleanup);
     }
 
@@ -1087,6 +1090,7 @@ public:
     bool do_dce;
     bool something_changed;
     vec<gimple> stmts_to_remove;
+    vec<gimple> stmts_to_fixup;
     bitmap need_eh_cleanup;
 };
 
@@ -1125,7 +1129,6 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
     {
       bool did_replace;
       gimple stmt = gsi_stmt (i);
-      gimple old_stmt;
       enum gimple_code code = gimple_code (stmt);
 
       /* Ignore ASSERT_EXPRs.  They are used by VRP to generate
@@ -1163,7 +1166,9 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
          print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
        }
 
-      old_stmt = stmt;
+      gimple old_stmt = stmt;
+      bool was_noreturn = (is_gimple_call (stmt)
+                          && gimple_call_noreturn_p (stmt));
 
       /* Some statements may be simplified using propagator
         specific information.  Do this before propagating
@@ -1194,6 +1199,13 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
          if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
            bitmap_set_bit (need_eh_cleanup, bb->index);
 
+         /* If we turned a not noreturn call into a noreturn one
+            schedule it for fixup.  */
+         if (!was_noreturn
+             && is_gimple_call (stmt)
+             && gimple_call_noreturn_p (stmt))
+           stmts_to_fixup.safe_push (stmt);
+
          if (is_gimple_assign (stmt)
              && (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
                  == GIMPLE_SINGLE_RHS))
@@ -1286,6 +1298,22 @@ substitute_and_fold (ssa_prop_get_value_fn get_value_fn,
   if (!bitmap_empty_p (walker.need_eh_cleanup))
     gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
 
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the dominator walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!walker.stmts_to_fixup.is_empty ())
+    {
+      gimple stmt = walker.stmts_to_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      fixup_noreturn_call (stmt);
+    }
+
   statistics_counter_event (cfun, "Constants propagated",
                            prop_stats.num_const_prop);
   statistics_counter_event (cfun, "Copies propagated",