cfgrtl.c (delete_insn_and_edges, [...]): New.
authorJan Hubicka <jh@suse.cz>
Wed, 6 Mar 2002 10:17:23 +0000 (11:17 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 6 Mar 2002 10:17:23 +0000 (10:17 +0000)
* cfgrtl.c (delete_insn_and_edges, delete_insn_chain_and_edges): New.
* rtl.h (delete_insn_and_edges, delete_insn_chain_and_edges): Declare

* basic-block.h (update_life_info, update_life_info_in_dirty_blocks,
delete_noop_moves): Return indeger.
* flow.c (ndead): New variable.
(propagate_block_delete_insn): Use delete_insn_and_edges; remove
BB argument; update callers.
(propagate_block_delete_libcall): Use delete_insn_chain_and_edges.
(life_analysis): Do not call purge_all_dead_edges.
(update_life_info): Return number of deleted insns; print statistics.
(update_life_info_in_dirty_blocks): likewise.
(delete_noop_moves): Use delete_insn_and_edges; print statistics;
return number of insns deleted.

* cse.c: Include timevar.h
(delete_trivially_dead_insns): Kill preserve_basic_blocks argument;
iterate until stabilizes; print statistics; return number of killed
insns.
* Makefile.in: (cse.o): Add timevar.h dependency
* rtl.h (delete_trivially_dead_insns): New.
* timever.def: Add TV_DELETE_TRIVIALLY_DEAD timer.
* toplev.c (rest_of_compilation): Update callers.

* cfgcleanup.c (try_optimize_cfg): Kill blocks.
(try_optimize_cfg): Do not update liveness.
(cleanup-cfg): Loop until try_optimize_cfg and dead code
removal stabilizes; use delete_trivially_dead_insns.

* cfgrtl.c (verify_flow_info): Sanity check outgoing edges.

From-SVN: r50355

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/basic-block.h
gcc/cfganal.c
gcc/cfgcleanup.c
gcc/cfgrtl.c
gcc/cse.c
gcc/emit-rtl.c
gcc/flow.c
gcc/profile.c
gcc/rtl.h
gcc/rtlanal.c
gcc/timevar.def
gcc/toplev.c

index 95a4bd89015611a52f9783d6a1ed3ebccaac4b70..3be7304970b95ae4d10d3fd72ecdcc2c0b1b7c1f 100644 (file)
@@ -1,3 +1,36 @@
+Wed Mar  6 10:59:39 CET 2002  Jan Hubicka  <jh@suse.cz>
+
+       * cfgrtl.c (delete_insn_and_edges, delete_insn_chain_and_edges): New.
+       * rtl.h (delete_insn_and_edges, delete_insn_chain_and_edges): Declare
+
+       * basic-block.h (update_life_info, update_life_info_in_dirty_blocks,
+       delete_noop_moves): Return indeger.
+       * flow.c (ndead): New variable.
+       (propagate_block_delete_insn): Use delete_insn_and_edges; remove
+       BB argument; update callers.
+       (propagate_block_delete_libcall): Use delete_insn_chain_and_edges.
+       (life_analysis): Do not call purge_all_dead_edges.
+       (update_life_info): Return number of deleted insns; print statistics.
+       (update_life_info_in_dirty_blocks): likewise.
+       (delete_noop_moves): Use delete_insn_and_edges; print statistics;
+       return number of insns deleted.
+
+       * cse.c: Include timevar.h
+       (delete_trivially_dead_insns): Kill preserve_basic_blocks argument;
+       iterate until stabilizes; print statistics; return number of killed
+       insns.
+       * Makefile.in: (cse.o): Add timevar.h dependency
+       * rtl.h (delete_trivially_dead_insns): New.
+       * timever.def: Add TV_DELETE_TRIVIALLY_DEAD timer.
+       * toplev.c (rest_of_compilation): Update callers.
+
+       * cfgcleanup.c (try_optimize_cfg): Kill blocks.
+       (try_optimize_cfg): Do not update liveness.
+       (cleanup-cfg): Loop until try_optimize_cfg and dead code
+       removal stabilizes; use delete_trivially_dead_insns.
+
+       * cfgrtl.c (verify_flow_info): Sanity check outgoing edges.
+
 2002-03-05  Zack Weinberg  <zack@codesourcery.com>
 
        * cppmain.c (setup_callbacks): Disable #pragma and #ident
index 5d1802f174495bec352027b95ec12513b69fba1b..2aabcdb5c3e07bb8548d5af845217ab3b7b27bdf 100644 (file)
@@ -1445,7 +1445,7 @@ cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) \
    output.h function.h cselib.h $(GGC_H) $(OBSTACK_H) $(TM_P_H)
 cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
    real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h function.h \
-   $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H)
+   $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H)
 gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) hard-reg-set.h \
    flags.h real.h insn-config.h ggc.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) \
    function.h output.h toplev.h $(TM_P_H) $(PARAMS_H)
index 39e24c82760c525d33c2f9c5ed671eb94c1abda3..e615a5dbd5f69ece53a02f055a0b58cdb2086136 100644 (file)
@@ -295,7 +295,10 @@ extern void free_basic_block_vars  PARAMS ((int));
 extern edge split_block                        PARAMS ((basic_block, rtx));
 extern basic_block split_edge          PARAMS ((edge));
 extern void insert_insn_on_edge                PARAMS ((rtx, edge));
+
 extern void commit_edge_insertions     PARAMS ((void));
+extern void commit_edge_insertions_watch_calls PARAMS ((void));
+
 extern void remove_fake_edges          PARAMS ((void));
 extern void add_noreturn_fake_exit_edges       PARAMS ((void));
 extern void connect_infinite_loops_to_exit     PARAMS ((void));
@@ -588,9 +591,9 @@ enum update_life_extent
 #define LOOP_ALL              31       /* All of the above  */
 
 extern void life_analysis      PARAMS ((rtx, FILE *, int));
-extern void update_life_info   PARAMS ((sbitmap, enum update_life_extent,
+extern int update_life_info    PARAMS ((sbitmap, enum update_life_extent,
                                         int));
-extern void update_life_info_in_dirty_blocks PARAMS ((enum update_life_extent,
+extern int update_life_info_in_dirty_blocks PARAMS ((enum update_life_extent,
                                                      int));
 extern int count_or_remove_death_notes PARAMS ((sbitmap, int));
 extern int propagate_block     PARAMS ((basic_block, regset, regset, regset,
@@ -636,7 +639,7 @@ extern void allocate_bb_life_data   PARAMS ((void));
 extern void expunge_block              PARAMS ((basic_block));
 extern basic_block alloc_block         PARAMS ((void));
 extern void find_unreachable_blocks    PARAMS ((void));
-extern void delete_noop_moves          PARAMS ((rtx));
+extern int delete_noop_moves           PARAMS ((rtx));
 extern basic_block redirect_edge_and_branch_force PARAMS ((edge, basic_block));
 extern basic_block force_nonfallthru   PARAMS ((edge));
 extern bool redirect_edge_and_branch   PARAMS ((edge, basic_block));
index 6009d59cbe85884295ed0e1b40554ee90297d07a..46c4758d3e7b78c807606a95485e1b11d28a7375 100644 (file)
@@ -55,7 +55,6 @@ static void flow_dfs_compute_reverse_finish
   PARAMS ((depth_first_search_ds));
 static void remove_fake_successors     PARAMS ((basic_block));
 static bool need_fake_edge_p           PARAMS ((rtx));
-static bool keep_with_call_p           PARAMS ((rtx));
 \f
 /* Return true if the block has no effect and only forwards control flow to
    its single destination.  */
@@ -212,32 +211,6 @@ need_fake_edge_p (insn)
          || GET_CODE (PATTERN (insn)) == ASM_INPUT);
 }
 
-/* Return true if INSN should be kept in the same block as a preceding call.
-   This is done for a single-set whose destination is a fixed register or
-   whose source is the function return value.  This is a helper function for
-   flow_call_edges_add.  */
-
-static bool
-keep_with_call_p (insn)
-     rtx insn;
-{
-  rtx set;
-
-  if (INSN_P (insn) && (set = single_set (insn)) != NULL)
-    {
-      if (GET_CODE (SET_DEST (set)) == REG
-         && fixed_regs[REGNO (SET_DEST (set))]
-         && general_operand (SET_SRC (set), VOIDmode))
-       return true;
-      if (GET_CODE (SET_SRC (set)) == REG
-         && FUNCTION_VALUE_REGNO_P (REGNO (SET_SRC (set)))
-         && GET_CODE (SET_DEST (set)) == REG
-         && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
-       return true;
-    }
-  return false;
-}
-
 /* Add fake edges to the function exit for any non constant and non noreturn
    calls, volatile inline assembly in the bitmap of blocks specified by
    BLOCKS or to the whole CFG if BLOCKS is zero.  Return the number of blocks
index 017a4aa539031471ca52b3f4449e5f94ae5bcc9f..a4dccbea80581422625daae6e373e16d72d00074 100644 (file)
@@ -1510,7 +1510,6 @@ try_optimize_cfg (mode)
   bool changed_overall = false;
   bool changed;
   int iterations = 0;
-  sbitmap blocks;
 
   if (mode & CLEANUP_CROSSJUMP)
     add_noreturn_fake_exit_edges ();
@@ -1673,11 +1672,6 @@ try_optimize_cfg (mode)
   if (mode & CLEANUP_CROSSJUMP)
     remove_fake_edges ();
 
-  if ((mode & CLEANUP_UPDATE_LIFE) && changed_overall)
-    update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL,
-                                     PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
-                                     | PROP_KILL_DEAD_CODE | PROP_LOG_LINKS);
-
   for (i = 0; i < n_basic_blocks; i++)
     BASIC_BLOCK (i)->aux = NULL;
 
@@ -1720,9 +1714,39 @@ cleanup_cfg (mode)
   bool changed = false;
 
   timevar_push (TV_CLEANUP_CFG);
-  changed = delete_unreachable_blocks ();
-  if (try_optimize_cfg (mode))
-    delete_unreachable_blocks (), changed = true;
+  if (delete_unreachable_blocks ())
+    {
+      changed = true;
+      /* We've possibly created trivially dead code.  Cleanup it right
+        now to introduce more oppurtunities for try_optimize_cfg.  */
+      if (!(mode & (CLEANUP_UPDATE_LIFE | CLEANUP_PRE_SIBCALL))
+         && !reload_completed)
+       delete_trivially_dead_insns (get_insns(), max_reg_num ());
+    }
+  while (try_optimize_cfg (mode))
+    {
+      delete_unreachable_blocks (), changed = true;
+      if (mode & CLEANUP_UPDATE_LIFE)
+       {
+         /* Cleaning up CFG introduces more oppurtunities for dead code
+            removal that in turn may introduce more oppurtunities for
+            cleaning up the CFG.  */
+         if (!update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL,
+                                                PROP_DEATH_NOTES
+                                                | PROP_SCAN_DEAD_CODE
+                                                | PROP_KILL_DEAD_CODE
+                                                | PROP_LOG_LINKS))
+           break;
+       }
+      else if (!(mode & CLEANUP_PRE_SIBCALL) && !reload_completed)
+       {
+         if (!delete_trivially_dead_insns (get_insns(), max_reg_num ()))
+           break;
+       }
+      else
+       break;
+      delete_dead_jumptables ();
+    }
 
   /* Kill the data we won't maintain.  */
   free_EXPR_LIST_list (&label_value_list);
index 151502087ac003d12918941337b6c37c606e9f07..81722ac1b33276dfd106918a15c035ae862c46e0 100644 (file)
@@ -74,7 +74,7 @@ rtx tail_recursion_label_list;
 
 static int can_delete_note_p           PARAMS ((rtx));
 static int can_delete_label_p          PARAMS ((rtx));
-static void commit_one_edge_insertion  PARAMS ((edge));
+static void commit_one_edge_insertion  PARAMS ((edge, int));
 static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
 static rtx last_loop_beg_note          PARAMS ((rtx));
 static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
@@ -178,6 +178,26 @@ delete_insn (insn)
   return next;
 }
 
+/* Like delete_insn but also purge dead edges from BB.  */
+rtx
+delete_insn_and_edges (insn)
+     rtx insn;
+{
+  rtx x;
+  bool purge = false;
+
+  if (basic_block_for_insn
+      && INSN_P (insn)
+      && (unsigned int)INSN_UID (insn) < basic_block_for_insn->num_elements
+      && BLOCK_FOR_INSN (insn)
+      && BLOCK_FOR_INSN (insn)->end == insn)
+    purge = true;
+  x = delete_insn (insn);
+  if (purge)
+    purge_dead_edges (BLOCK_FOR_INSN (insn));
+  return x;
+}
+
 /* Unlink a chain of insns between START and FINISH, leaving notes
    that must be paired.  */
 
@@ -203,6 +223,24 @@ delete_insn_chain (start, finish)
       start = next;
     }
 }
+
+/* Like delete_insn but also purge dead edges from BB.  */
+void
+delete_insn_chain_and_edges (first, last)
+     rtx first, last;
+{
+  bool purge = false;
+
+  if (basic_block_for_insn
+      && INSN_P (last)
+      && (unsigned int)INSN_UID (last) < basic_block_for_insn->num_elements
+      && BLOCK_FOR_INSN (last)
+      && BLOCK_FOR_INSN (last)->end == last)
+    purge = true;
+  delete_insn_chain (first, last);
+  if (purge)
+    purge_dead_edges (BLOCK_FOR_INSN (last));
+}
 \f
 /* Create a new basic block consisting of the instructions between HEAD and END
    inclusive.  This function is designed to allow fast BB construction - reuses
@@ -1271,8 +1309,9 @@ insert_insn_on_edge (pattern, e)
 /* Update the CFG for the instructions queued on edge E.  */
 
 static void
-commit_one_edge_insertion (e)
+commit_one_edge_insertion (e, watch_calls)
      edge e;
+     int watch_calls;
 {
   rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
   basic_block bb;
@@ -1281,63 +1320,84 @@ commit_one_edge_insertion (e)
   insns = e->insns;
   e->insns = NULL_RTX;
 
-  /* Figure out where to put these things.  If the destination has
-     one predecessor, insert there.  Except for the exit block.  */
-  if (e->dest->pred->pred_next == NULL
-      && e->dest != EXIT_BLOCK_PTR)
+  /* Special case -- avoid inserting code between call and storing
+     its return value.  */
+  if (watch_calls && (e->flags & EDGE_FALLTHRU) && !e->dest->pred->pred_next
+      && e->src != ENTRY_BLOCK_PTR
+      && GET_CODE (e->src->end) == CALL_INSN)
     {
-      bb = e->dest;
+      rtx next = next_nonnote_insn (e->src->end);
 
-      /* Get the location correct wrt a code label, and "nice" wrt
-        a basic block note, and before everything else.  */
-      tmp = bb->head;
-      if (GET_CODE (tmp) == CODE_LABEL)
-       tmp = NEXT_INSN (tmp);
-      if (NOTE_INSN_BASIC_BLOCK_P (tmp))
-       tmp = NEXT_INSN (tmp);
-      if (tmp == bb->head)
-       before = tmp;
-      else
-       after = PREV_INSN (tmp);
+      after = e->dest->head;
+      /* The first insn after the call may be a stack pop, skip it.  */
+      while (next
+            && keep_with_call_p (next))
+        {
+          after = next;
+         next = next_nonnote_insn (next);
+       }
+      bb = e->dest;
     }
-
-  /* If the source has one successor and the edge is not abnormal,
-     insert there.  Except for the entry block.  */
-  else if ((e->flags & EDGE_ABNORMAL) == 0
-          && e->src->succ->succ_next == NULL
-          && e->src != ENTRY_BLOCK_PTR)
+  if (!before && !after)
     {
-      bb = e->src;
-
-      /* It is possible to have a non-simple jump here.  Consider a target
-        where some forms of unconditional jumps clobber a register.  This
-        happens on the fr30 for example.
-
-        We know this block has a single successor, so we can just emit
-        the queued insns before the jump.  */
-      if (GET_CODE (bb->end) == JUMP_INSN)
-       for (before = bb->end;
-            GET_CODE (PREV_INSN (before)) == NOTE
-            && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG;
-            before = PREV_INSN (before))
-         ;
-      else
+      /* Figure out where to put these things.  If the destination has
+         one predecessor, insert there.  Except for the exit block.  */
+      if (e->dest->pred->pred_next == NULL && e->dest != EXIT_BLOCK_PTR)
        {
-         /* We'd better be fallthru, or we've lost track of what's what.  */
-         if ((e->flags & EDGE_FALLTHRU) == 0)
-           abort ();
+         bb = e->dest;
+
+         /* Get the location correct wrt a code label, and "nice" wrt
+            a basic block note, and before everything else.  */
+         tmp = bb->head;
+         if (GET_CODE (tmp) == CODE_LABEL)
+           tmp = NEXT_INSN (tmp);
+         if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+           tmp = NEXT_INSN (tmp);
+         if (tmp == bb->head)
+           before = tmp;
+         else if (tmp)
+           after = PREV_INSN (tmp);
+         else
+           after = get_last_insn ();
+       }
+
+      /* If the source has one successor and the edge is not abnormal,
+         insert there.  Except for the entry block.  */
+      else if ((e->flags & EDGE_ABNORMAL) == 0
+              && e->src->succ->succ_next == NULL
+              && e->src != ENTRY_BLOCK_PTR)
+       {
+         bb = e->src;
+
+         /* It is possible to have a non-simple jump here.  Consider a target
+            where some forms of unconditional jumps clobber a register.  This
+            happens on the fr30 for example.
+
+            We know this block has a single successor, so we can just emit
+            the queued insns before the jump.  */
+         if (GET_CODE (bb->end) == JUMP_INSN)
+           for (before = bb->end;
+                GET_CODE (PREV_INSN (before)) == NOTE
+                && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
+                NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
+             ;
+         else
+           {
+             /* We'd better be fallthru, or we've lost track of what's what.  */
+             if ((e->flags & EDGE_FALLTHRU) == 0)
+               abort ();
 
+             after = bb->end;
+           }
+       }
+      /* Otherwise we must split the edge.  */
+      else
+       {
+         bb = split_edge (e);
          after = bb->end;
        }
     }
 
-  /* Otherwise we must split the edge.  */
-  else
-    {
-      bb = split_edge (e);
-      after = bb->end;
-    }
-
   /* Now that we've found the spot, do the insertion.  */
 
   if (before)
@@ -1352,13 +1412,12 @@ commit_one_edge_insertion (e)
     {
       /* ??? Remove all outgoing edges from BB and add one for EXIT.
          This is not currently a problem because this only happens
-        for the (single) epilogue, which already has a fallthru edge
-        to EXIT.  */
+         for the (single) epilogue, which already has a fallthru edge
+         to EXIT.  */
 
       e = bb->succ;
       if (e->dest != EXIT_BLOCK_PTR
-         || e->succ_next != NULL
-         || (e->flags & EDGE_FALLTHRU) == 0)
+         || e->succ_next != NULL || (e->flags & EDGE_FALLTHRU) == 0)
        abort ();
 
       e->flags &= ~EDGE_FALLTHRU;
@@ -1395,7 +1454,39 @@ commit_edge_insertions ()
        {
          next = e->succ_next;
          if (e->insns)
-           commit_one_edge_insertion (e);
+           commit_one_edge_insertion (e, false);
+       }
+
+      if (++i >= n_basic_blocks)
+       break;
+      bb = BASIC_BLOCK (i);
+    }
+}
+\f
+/* Update the CFG for all queued instructions, taking special care of inserting
+   code on edges between call and storing its return value.  */
+
+void
+commit_edge_insertions_watch_calls ()
+{
+  int i;
+  basic_block bb;
+
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
+
+  i = -1;
+  bb = ENTRY_BLOCK_PTR;
+  while (1)
+    {
+      edge e, next;
+
+      for (e = bb->succ; e; e = next)
+       {
+         next = e->succ_next;
+         if (e->insns)
+           commit_one_edge_insertion (e, true);
        }
 
       if (++i >= n_basic_blocks)
@@ -1649,7 +1740,7 @@ verify_flow_info ()
   for (i = n_basic_blocks - 1; i >= 0; i--)
     {
       basic_block bb = BASIC_BLOCK (i);
-      int has_fallthru = 0;
+      int n_fallthru = 0, n_eh = 0, n_call = 0, n_abnormal = 0, n_branch = 0;
       edge e;
       rtx note;
 
@@ -1705,7 +1796,18 @@ verify_flow_info ()
          last_visited [e->dest->index + 2] = bb;
 
          if (e->flags & EDGE_FALLTHRU)
-           has_fallthru = 1;
+           n_fallthru++;
+
+         if ((e->flags & ~EDGE_DFS_BACK) == 0)
+           n_branch++;
+
+         if (e->flags & EDGE_ABNORMAL_CALL)
+           n_call++;
+
+         if (e->flags & EDGE_EH)
+           n_eh++;
+         else if (e->flags & EDGE_ABNORMAL)
+           n_abnormal++;
 
          if ((e->flags & EDGE_FALLTHRU)
              && e->src != ENTRY_BLOCK_PTR
@@ -1753,7 +1855,51 @@ verify_flow_info ()
          edge_checksum[e->dest->index + 2] += (size_t) e;
        }
 
-      if (!has_fallthru)
+      if (n_eh && !find_reg_note (bb->end, REG_EH_REGION, NULL_RTX))
+       {
+         error ("Missing REG_EH_REGION note in the end of bb %i", bb->index);
+         err = 1;
+       }
+      if (n_branch
+         && (GET_CODE (bb->end) != JUMP_INSN
+             || (n_branch > 1 && (any_uncondjump_p (bb->end)
+                                  || any_condjump_p (bb->end)))))
+       {
+         error ("Too many outgoing branch edges from bb %i", bb->index);
+         err = 1;
+       }
+      if (n_fallthru && any_uncondjump_p (bb->end))
+       {
+         error ("Fallthru edge after unconditional jump %i", bb->index);
+         err = 1;
+       }
+      if (n_branch != 1 && any_uncondjump_p (bb->end))
+       {
+         error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
+         err = 1;
+       }
+      if (n_branch != 1 && any_condjump_p (bb->end)
+         && JUMP_LABEL (bb->end) != BASIC_BLOCK (bb->index + 1)->head)
+       {
+         error ("Wrong amount of branch edges after conditional jump %i", bb->index);
+         err = 1;
+       }
+      if (n_call && GET_CODE (bb->end) != CALL_INSN)
+       {
+         error ("Call edges for non-call insn in bb %i", bb->index);
+         err = 1;
+       }
+      if (n_abnormal
+         && (GET_CODE (bb->end) != CALL_INSN && n_call != n_abnormal)
+         && (GET_CODE (bb->end) != JUMP_INSN
+             || any_condjump_p (bb->end)
+             || any_uncondjump_p (bb->end)))
+       {
+         error ("Abnormal edges for no purpose in bb %i", bb->index);
+         err = 1;
+       }
+       
+      if (!n_fallthru)
        {
          rtx insn;
 
index 557e8086d7f762fd6b2ce8975c76656aa1b2a040..7a05dad03077c4bb391caa6012862826abb1ebd4 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "output.h"
 #include "ggc.h"
+#include "timevar.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -7605,81 +7606,42 @@ dead_libcall_p (insn)
    move dead invariants out of loops or make givs for dead quantities.  The
    remaining passes of the compilation are also sped up.  */
 
-void
-delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
+int
+delete_trivially_dead_insns (insns, nreg)
      rtx insns;
      int nreg;
-     int preserve_basic_blocks;
 {
   int *counts;
   rtx insn, prev;
-  int i;
   int in_libcall = 0, dead_libcall = 0;
-  basic_block bb;
+  int ndead = 0, nlastdead, niterations = 0;
 
+  timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
   counts = (int *) xcalloc (nreg, sizeof (int));
   for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
     count_reg_usage (insn, counts, NULL_RTX, 1);
 
-  /* Go from the last insn to the first and delete insns that only set unused
-     registers or copy a register to itself.  As we delete an insn, remove
-     usage counts for registers it uses.
-
-     The first jump optimization pass may leave a real insn as the last
-     insn in the function.   We must not skip that insn or we may end
-     up deleting code that is not really dead.  */
-  insn = get_last_insn ();
-  if (! INSN_P (insn))
-    insn = prev_real_insn (insn);
-
-  if (!preserve_basic_blocks)
-    for (; insn; insn = prev)
-      {
-       int live_insn = 0;
-
-       prev = prev_real_insn (insn);
-
-       /* Don't delete any insns that are part of a libcall block unless
-          we can delete the whole libcall block.
-
-          Flow or loop might get confused if we did that.  Remember
-          that we are scanning backwards.  */
-       if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
-         {
-           in_libcall = 1;
-           live_insn = 1;
-           dead_libcall = dead_libcall_p (insn);
-         }
-       else if (in_libcall)
-         live_insn = ! dead_libcall;
-       else
-         live_insn = insn_live_p (insn, counts);
-
-       /* If this is a dead insn, delete it and show registers in it aren't
-          being used.  */
-
-       if (! live_insn)
-         {
-           count_reg_usage (insn, counts, NULL_RTX, -1);
-           delete_related_insns (insn);
-         }
+  do
+    {
+      nlastdead = ndead;
+      niterations++;
+      /* Go from the last insn to the first and delete insns that only set unused
+        registers or copy a register to itself.  As we delete an insn, remove
+        usage counts for registers it uses.
+
+        The first jump optimization pass may leave a real insn as the last
+        insn in the function.   We must not skip that insn or we may end
+        up deleting code that is not really dead.  */
+      insn = get_last_insn ();
+      if (! INSN_P (insn))
+       insn = prev_real_insn (insn);
 
-       if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-         {
-           in_libcall = 0;
-           dead_libcall = 0;
-         }
-      }
-  else
-    for (i = 0; i < n_basic_blocks; i++)
-      for (bb = BASIC_BLOCK (i), insn = bb->end; insn != bb->head; insn = prev)
+      for (; insn; insn = prev)
        {
          int live_insn = 0;
 
-         prev = PREV_INSN (insn);
-         if (!INSN_P (insn))
-           continue;
+         prev = prev_real_insn (insn);
 
          /* Don't delete any insns that are part of a libcall block unless
             we can delete the whole libcall block.
@@ -7703,7 +7665,8 @@ delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
          if (! live_insn)
            {
              count_reg_usage (insn, counts, NULL_RTX, -1);
-             delete_insn (insn);
+             delete_insn_and_edges (insn);
+             ndead++;
            }
 
          if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
@@ -7712,7 +7675,13 @@ delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
              dead_libcall = 0;
            }
        }
+    } while (ndead != nlastdead);
 
+  if (rtl_dump_file && ndead)
+    fprintf (rtl_dump_file, "Deleted %i trivially dead insns; %i iterations\n",
+            ndead, niterations);
   /* Clean up.  */
   free (counts);
+  timevar_pop (TV_DELETE_TRIVIALLY_DEAD);
+  return ndead;
 }
index ae3ab5f070eaa067afc8f13e8cb3717735283029..47574278e9dbb365b0fab863079973f0b413df07 100644 (file)
@@ -2468,6 +2468,17 @@ get_insns ()
   return first_insn;
 }
 
+/* Specify a new insn as the first in the chain.  */
+
+void
+set_first_insn (insn)
+     rtx insn;
+{
+  if (PREV_INSN (insn) != 0)
+    abort ();
+  first_insn = insn;
+}
+
 /* Return the last insn emitted in current sequence or current function.  */
 
 rtx
index e2d957f2f6c46c210d2da4e4c8100b5cce6a5978..ee127a5ad0dafe2311a7233d65cd3464b5d7b24c 100644 (file)
@@ -276,6 +276,9 @@ struct propagate_block_info
   int flags;
 };
 
+/* Number of dead insns removed.  */
+static int ndead;
+
 /* Maximum length of pbi->mem_set_list before we start dropping
    new elements on the floor.  */
 #define MAX_MEM_SET_LIST_LEN   100
@@ -290,7 +293,7 @@ static void mark_reg                        PARAMS ((rtx, void *));
 static void mark_regs_live_at_end      PARAMS ((regset));
 static int set_phi_alternative_reg      PARAMS ((rtx, int, int, void *));
 static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
-static void propagate_block_delete_insn PARAMS ((basic_block, rtx));
+static void propagate_block_delete_insn PARAMS ((rtx));
 static rtx propagate_block_delete_libcall PARAMS ((rtx, rtx));
 static int insn_dead_p                 PARAMS ((struct propagate_block_info *,
                                                 rtx, int, rtx));
@@ -448,7 +451,6 @@ life_analysis (f, file, flags)
   /* Always remove no-op moves.  Do this before other processing so
      that we don't have to keep re-scanning them.  */
   delete_noop_moves (f);
-  purge_all_dead_edges (false);
 
   /* Some targets can emit simpler epilogues if they know that sp was
      not ever modified during the function.  After reload, of course,
@@ -623,7 +625,7 @@ verify_local_live_at_start (new_live_at_start, bb)
    Including PROP_REG_INFO does not properly refresh regs_ever_live
    unless the caller resets it to zero.  */
 
-void
+int
 update_life_info (blocks, extent, prop_flags)
      sbitmap blocks;
      enum update_life_extent extent;
@@ -634,6 +636,7 @@ update_life_info (blocks, extent, prop_flags)
   int i;
 
   tmp = INITIALIZE_REG_SET (tmp_head);
+  ndead = 0;
 
   timevar_push ((extent == UPDATE_LIFE_LOCAL || blocks)
                ? TV_LIFE_UPDATE : TV_LIFE);
@@ -743,11 +746,14 @@ update_life_info (blocks, extent, prop_flags)
     }
   timevar_pop ((extent == UPDATE_LIFE_LOCAL || blocks)
               ? TV_LIFE_UPDATE : TV_LIFE);
+  if (ndead && rtl_dump_file)
+    fprintf (rtl_dump_file, "deleted %i dead insns\n", ndead);
+  return ndead;
 }
 
 /* Update life information in all blocks where BB_DIRTY is set.  */
 
-void
+int
 update_life_info_in_dirty_blocks (extent, prop_flags)
      enum update_life_extent extent;
      int prop_flags;
@@ -755,6 +761,7 @@ update_life_info_in_dirty_blocks (extent, prop_flags)
   sbitmap update_life_blocks = sbitmap_alloc (n_basic_blocks);
   int block_num;
   int n = 0;
+  int ndead;
 
   sbitmap_zero (update_life_blocks);
   for (block_num = 0; block_num < n_basic_blocks; block_num++)
@@ -765,9 +772,10 @@ update_life_info_in_dirty_blocks (extent, prop_flags)
       }
 
   if (n)
-    update_life_info (update_life_blocks, extent, prop_flags);
+    ndead = update_life_info (update_life_blocks, extent, prop_flags);
 
   sbitmap_free (update_life_blocks);
+  return ndead;
 }
 
 /* Free the variables allocated by find_basic_blocks.
@@ -796,13 +804,14 @@ free_basic_block_vars (keep_head_end_p)
 
 /* Delete any insns that copy a register to itself.  */
 
-void
+int
 delete_noop_moves (f)
      rtx f ATTRIBUTE_UNUSED;
 {
   int i;
   rtx insn, next;
   basic_block bb;
+  int nnoops = 0;
 
   for (i = 0; i < n_basic_blocks; i++)
     {
@@ -829,14 +838,14 @@ delete_noop_moves (f)
                  XEXP (retval_note, 0) = new_libcall_insn;
                }
 
-             /* Do not call delete_insn here since that may change
-                the basic block boundaries which upsets some callers.  */
-             PUT_CODE (insn, NOTE);
-             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (insn) = 0;
+             delete_insn_and_edges (insn);
+             nnoops++;
            }
        }
     }
+  if (nnoops && rtl_dump_file)
+    fprintf (rtl_dump_file, "deleted %i noop moves", nnoops);
+  return nnoops;
 }
 
 /* Delete any jump tables never referenced.  We can't delete them at the
@@ -1483,12 +1492,11 @@ allocate_reg_life_data ()
 /* Delete dead instructions for propagate_block.  */
 
 static void
-propagate_block_delete_insn (bb, insn)
-     basic_block bb;
+propagate_block_delete_insn (insn)
      rtx insn;
 {
   rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
-  bool purge = false;
+  basic_block bb = BLOCK_FOR_INSN (insn);
 
   /* If the insn referred to a label, and that label was attached to
      an ADDR_VEC, it's safe to delete the ADDR_VEC.  In fact, it's
@@ -1526,15 +1534,13 @@ propagate_block_delete_insn (bb, insn)
          for (i = 0; i < len; i++)
            LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
 
-         delete_insn (next);
+         delete_insn_and_edges (next);
+         ndead++;
        }
     }
 
-  if (bb->end == insn)
-    purge = true;
-  delete_insn (insn);
-  if (purge)
-    purge_dead_edges (bb);
+  delete_insn_and_edges (insn);
+  ndead++;
 }
 
 /* Delete dead libcalls for propagate_block.  Return the insn
@@ -1547,7 +1553,8 @@ propagate_block_delete_libcall ( insn, note)
   rtx first = XEXP (note, 0);
   rtx before = PREV_INSN (first);
 
-  delete_insn_chain (first, insn);
+  delete_insn_chain_and_edges (first, insn);
+  ndead++;
   return before;
 }
 
@@ -1608,7 +1615,7 @@ propagate_one_insn (pbi, insn)
       if (libcall_is_dead)
        prev = propagate_block_delete_libcall ( insn, note);
       else
-       propagate_block_delete_insn (pbi->bb, insn);
+       propagate_block_delete_insn (insn);
 
       return prev;
     }
@@ -3940,7 +3947,7 @@ try_pre_increment_1 (pbi, insn)
     {
       /* We have found a suitable auto-increment and already changed
         insn Y to do it.  So flush this increment instruction.  */
-      propagate_block_delete_insn (pbi->bb, insn);
+      propagate_block_delete_insn (insn);
 
       /* Count a reference to this reg for the increment insn we are
         deleting.  When a reg is incremented, spilling it is worse,
index 0c4acdfc1846aae6101cb4673ad249b13e658763..09fab359a8959b1aba557d0ef3c5d453c5f53f90 100644 (file)
@@ -169,7 +169,7 @@ instrument_edges (el)
   if (rtl_dump_file)
     fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
 
-  commit_edge_insertions ();
+  commit_edge_insertions_watch_calls ();
 }
 
 /* Output STRING to bb_file, surrounded by DELIMITER.  */
index a11bf9b6db0d0e24de41873807093036fb44a7de..e8f819c9dd77e8eb9f776e2876a88e5cc5669f90 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1518,6 +1518,7 @@ extern void remove_node_from_expr_list    PARAMS ((rtx, rtx *));
 extern int insns_safe_to_move_p         PARAMS ((rtx, rtx, rtx *));
 extern int loc_mentioned_in_p          PARAMS ((rtx *, rtx));
 extern rtx find_first_parameter_load   PARAMS ((rtx, rtx));
+extern bool keep_with_call_p           PARAMS ((rtx));
 
 /* flow.c */
 
@@ -1792,7 +1793,7 @@ struct cse_basic_block_data;
 
 extern int rtx_cost                    PARAMS ((rtx, enum rtx_code));
 extern int address_cost                        PARAMS ((rtx, enum machine_mode));
-extern void delete_trivially_dead_insns        PARAMS ((rtx, int, int));
+extern int delete_trivially_dead_insns PARAMS ((rtx, int));
 #ifdef BUFSIZ
 extern int cse_main                    PARAMS ((rtx, int, int, FILE *));
 #endif
@@ -1873,6 +1874,8 @@ extern void renumber_insns                      PARAMS ((FILE *));
 extern void remove_unnecessary_notes             PARAMS ((void));
 extern rtx delete_insn                 PARAMS ((rtx));
 extern void delete_insn_chain          PARAMS ((rtx, rtx));
+extern rtx delete_insn_and_edges       PARAMS ((rtx));
+extern void delete_insn_chain_and_edges        PARAMS ((rtx, rtx));
 
 /* In combine.c */
 extern int combine_instructions                PARAMS ((rtx, unsigned int));
index 5f338e86e2f91d03149987ba91c135ca9c0a784b..997bb525a2be0d2cf0d28a6f7cb6139b014c0901 100644 (file)
@@ -3119,3 +3119,38 @@ find_first_parameter_load (call_insn, boundary)
     }
   return before;
 }
+
+/* Return true if we should avoid inserting code between INSN and preceeding
+   call instruction.  */
+
+bool
+keep_with_call_p (insn)
+     rtx insn;
+{
+  rtx set;
+
+  if (INSN_P (insn) && (set = single_set (insn)) != NULL)
+    {
+      if (GET_CODE (SET_DEST (set)) == REG
+         && fixed_regs[REGNO (SET_DEST (set))]
+         && general_operand (SET_SRC (set), VOIDmode))
+       return true;
+      if (GET_CODE (SET_SRC (set)) == REG
+         && FUNCTION_VALUE_REGNO_P (REGNO (SET_SRC (set)))
+         && GET_CODE (SET_DEST (set)) == REG
+         && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
+       return true;
+      /* There may be stack pop just after the call and
+         before actual store of return register.  Search
+        for the actual store when deciding if we can break
+        or not.  */
+      if (SET_DEST (set) == stack_pointer_rtx)
+       {
+         rtx i2 = next_nonnote_insn (insn);
+         if (i2 && keep_with_call_p (insn))
+           return true;
+       }
+    }
+  return false;
+}
+
index 353a942bf71dfe9ed2f4843dd1b461614dd575f8..74f8907ae7b58b363e681840ed4b169cec15ce53 100644 (file)
@@ -43,6 +43,7 @@ DEFTIMEVAR (TV_DUMP                  , "dump files")
 DEFTIMEVAR (TV_CFG                   , "cfg construction")
 /* Time spent by cleaning up CFG.  */
 DEFTIMEVAR (TV_CLEANUP_CFG           , "cfg cleanup")
+DEFTIMEVAR (TV_DELETE_TRIVIALLY_DEAD , "trivially dead code")
 /* Time spent by life analysis.  */
 DEFTIMEVAR (TV_LIFE                 , "life analysis")
 DEFTIMEVAR (TV_LIFE_UPDATE          , "life info update")
index 93cb2c9038981d456400050d17753b34ff635689..f97db60235008ad5ec14f3154a6c3004cfa7da55 100644 (file)
@@ -2778,7 +2778,7 @@ rest_of_compilation (decl)
 
       /* Run this after jump optmizations remove all the unreachable code
         so that unreachable code will not keep values live.  */
-      delete_trivially_dead_insns (insns, max_reg_num (), 1);
+      delete_trivially_dead_insns (insns, max_reg_num ());
 
       /* Try to identify useless null pointer tests and delete them.  */
       if (flag_delete_null_pointer_checks || flag_thread_jumps)
@@ -2851,7 +2851,7 @@ rest_of_compilation (decl)
          tem = tem2 = 0;
          timevar_push (TV_JUMP);
          rebuild_jump_labels (insns);
-         delete_trivially_dead_insns (insns, max_reg_num (), 1);
+         delete_trivially_dead_insns (insns, max_reg_num ());
          cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
          timevar_pop (TV_JUMP);
 
@@ -2899,7 +2899,7 @@ rest_of_compilation (decl)
             trivially dead.  We delete those instructions now in the
             hope that doing so will make the heuristics in loop work
             better and possibly speed up compilation.  */
-         delete_trivially_dead_insns (insns, max_reg_num (), 0);
+         delete_trivially_dead_insns (insns, max_reg_num ());
 
          /* The regscan pass is currently necessary as the alias
                  analysis code depends on this information.  */
@@ -2911,7 +2911,7 @@ rest_of_compilation (decl)
                     | (flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0));
 
       /* Loop can create trivially dead instructions.  */
-      delete_trivially_dead_insns (insns, max_reg_num (), 0);
+      delete_trivially_dead_insns (insns, max_reg_num ());
       close_dump_file (DFI_loop, print_rtl, insns);
       timevar_pop (TV_LOOP);