]> gcc.gnu.org Git - gcc.git/commitdiff
Begin cleaning up jump.c
authorDavid S. Miller <davem@pierdol.cobaltmicro.com>
Thu, 5 Nov 1998 06:20:37 +0000 (06:20 +0000)
committerDavid S. Miller <davem@gcc.gnu.org>
Thu, 5 Nov 1998 06:20:37 +0000 (22:20 -0800)
Begin cleaning up jump.c
* jump.c (init_label_info, delete_barrier_successors,
mark_all_labels, delete_unreferenced_labels,
delete_noop_moves, calculate_can_reach_end): New functions broken
out of jump_optimize.
(jump_optimize): Use them.

From-SVN: r23539

gcc/ChangeLog
gcc/jump.c

index 431f4b6837f655eb889ae1ee64a08ed0b32247d7..20138d45541eae251fa6c19b57c46f7eb8c54625 100644 (file)
@@ -1,3 +1,11 @@
+Thu Nov  5 07:59:05 1998  David S. Miller  <davem@pierdol.cobaltmicro.com>
+
+       * jump.c (init_label_info, delete_barrier_successors,
+       mark_all_labels, delete_unreferenced_labels,
+       delete_noop_moves, calculate_can_reach_end): New functions broken
+       out of jump_optimize.
+       (jump_optimize): Use them.
+
 Thu Nov  5 07:57:45 EST 1998  Andrew MacLeod  <amacleod@cygnus.com>
 
        * except.c (expand_fixup_region_end): Make sure outer context labels
index 18696ec8806f208e1f4529569a914bc1b097bf5a..cfc7f4f9da0bc951318212dc9d06cab2445c5968 100644 (file)
@@ -108,6 +108,12 @@ int can_reach_end;
 
 static int cross_jump_death_matters = 0;
 
+static int init_label_info             PROTO((rtx));
+static void delete_barrier_successors  PROTO((rtx));
+static void mark_all_labels            PROTO((rtx, int));
+static rtx delete_unreferenced_labels  PROTO((rtx));
+static void delete_noop_moves          PROTO((rtx));
+static int calculate_can_reach_end     PROTO((rtx, int, int));
 static int duplicate_loop_exit_test    PROTO((rtx));
 static void find_cross_jump            PROTO((rtx, rtx, int, rtx *, rtx *));
 static void do_cross_jump              PROTO((rtx, rtx, rtx));
@@ -157,30 +163,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
   rtx last_insn;
 
   cross_jump_death_matters = (cross_jump == 2);
-
-  /* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
-     notes whose labels don't occur in the insn any more.  */
-
-  for (insn = f; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == CODE_LABEL)
-       LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
-      else if (GET_CODE (insn) == JUMP_INSN)
-       JUMP_LABEL (insn) = 0;
-      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
-       for (note = REG_NOTES (insn); note; note = next)
-         {
-           next = XEXP (note, 1);
-           if (REG_NOTE_KIND (note) == REG_LABEL
-               && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
-             remove_note (insn, note);
-         }
-
-      if (INSN_UID (insn) > max_uid)
-       max_uid = INSN_UID (insn);
-    }
-
-  max_uid++;
+  max_uid = init_label_info (f) + 1;
 
   /* If we are performing cross jump optimizations, then initialize
      tables mapping UIDs to EH regions to avoid incorrect movement
@@ -188,26 +171,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
   if (flag_exceptions && cross_jump)
     init_insn_eh_region (f, max_uid);
 
-  /* Delete insns following barriers, up to next label.  */
-
-  for (insn = f; insn;)
-    {
-      if (GET_CODE (insn) == BARRIER)
-       {
-         insn = NEXT_INSN (insn);
-         while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
-           {
-             if (GET_CODE (insn) == NOTE
-                 && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
-               insn = NEXT_INSN (insn);
-             else
-               insn = delete_insn (insn);
-           }
-         /* INSN is now the code_label.  */
-       }
-      else
-       insn = NEXT_INSN (insn);
-    }
+  delete_barrier_successors (f);
 
   /* Leave some extra room for labels and duplicate exit test insns
      we make.  */
@@ -215,32 +179,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
   jump_chain = (rtx *) alloca (max_jump_chain * sizeof (rtx));
   bzero ((char *) jump_chain, max_jump_chain * sizeof (rtx));
 
-  /* Mark the label each jump jumps to.
-     Combine consecutive labels, and count uses of labels.
-
-     For each label, make a chain (using `jump_chain')
-     of all the *unconditional* jumps that jump to it;
-     also make a chain of all returns.  */
-
-  for (insn = f; insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-      {
-       mark_jump_label (PATTERN (insn), insn, cross_jump);
-       if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
-         {
-           if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
-             {
-               jump_chain[INSN_UID (insn)]
-                 = jump_chain[INSN_UID (JUMP_LABEL (insn))];
-               jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
-             }
-           if (GET_CODE (PATTERN (insn)) == RETURN)
-             {
-               jump_chain[INSN_UID (insn)] = jump_chain[0];
-               jump_chain[0] = insn;
-             }
-         }
-      }
+  mark_all_labels (f, cross_jump);
 
   /* Keep track of labels used from static data;
      they cannot ever be deleted.  */
@@ -258,51 +197,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
   exception_optimize ();
 
-  /* Delete all labels already not referenced.
-     Also find the last insn.  */
-
-  last_insn = 0;
-  for (insn = f; insn; )
-    {
-      if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0)
-       insn = delete_insn (insn);
-      else
-       {
-         last_insn = insn;
-         insn = NEXT_INSN (insn);
-       }
-    }
+  last_insn = delete_unreferenced_labels (f);
 
   if (!optimize)
     {
-      /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
-        If so record that this function can drop off the end.  */
-
-      insn = last_insn;
-      {
-       int n_labels = 1;
-       while (insn
-              /* One label can follow the end-note: the return label.  */
-              && ((GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
-                  /* Ordinary insns can follow it if returning a structure.  */
-                  || GET_CODE (insn) == INSN
-                  /* If machine uses explicit RETURN insns, no epilogue,
-                     then one of them follows the note.  */
-                  || (GET_CODE (insn) == JUMP_INSN
-                      && GET_CODE (PATTERN (insn)) == RETURN)
-                  /* A barrier can follow the return insn.  */
-                  || GET_CODE (insn) == BARRIER
-                  /* Other kinds of notes can follow also.  */
-                  || (GET_CODE (insn) == NOTE
-                      && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)))
-         insn = PREV_INSN (insn);
-      }
-
-      /* Report if control can fall through at the end of the function.  */
-      if (insn && GET_CODE (insn) == NOTE
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
-         && ! INSN_DELETED_P (insn))
-       can_reach_end = 1;
+      can_reach_end = calculate_can_reach_end (last_insn, 1, 0);
 
       /* Zero the "deleted" flag of all the "deleted" insns.  */
       for (insn = f; insn; insn = NEXT_INSN (insn))
@@ -333,245 +232,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 #endif
 
   if (noop_moves)
-    for (insn = f; insn; )
-      {
-       next = NEXT_INSN (insn);
-
-       if (GET_CODE (insn) == INSN)
-         {
-           register rtx body = PATTERN (insn);
-
-/* Combine stack_adjusts with following push_insns.  */
-#ifdef PUSH_ROUNDING
-           if (GET_CODE (body) == SET
-               && SET_DEST (body) == stack_pointer_rtx
-               && GET_CODE (SET_SRC (body)) == PLUS
-               && XEXP (SET_SRC (body), 0) == stack_pointer_rtx
-               && GET_CODE (XEXP (SET_SRC (body), 1)) == CONST_INT
-               && INTVAL (XEXP (SET_SRC (body), 1)) > 0)
-             {
-               rtx p;
-               rtx stack_adjust_insn = insn;
-               int stack_adjust_amount = INTVAL (XEXP (SET_SRC (body), 1));
-               int total_pushed = 0;
-               int pushes = 0;
-
-               /* Find all successive push insns.  */
-               p = insn;
-               /* Don't convert more than three pushes;
-                  that starts adding too many displaced addresses
-                  and the whole thing starts becoming a losing
-                  proposition.  */
-               while (pushes < 3)
-                 {
-                   rtx pbody, dest;
-                   p = next_nonnote_insn (p);
-                   if (p == 0 || GET_CODE (p) != INSN)
-                     break;
-                   pbody = PATTERN (p);
-                   if (GET_CODE (pbody) != SET)
-                     break;
-                   dest = SET_DEST (pbody);
-                   /* Allow a no-op move between the adjust and the push.  */
-                   if (GET_CODE (dest) == REG
-                       && GET_CODE (SET_SRC (pbody)) == REG
-                       && REGNO (dest) == REGNO (SET_SRC (pbody)))
-                     continue;
-                   if (! (GET_CODE (dest) == MEM
-                          && GET_CODE (XEXP (dest, 0)) == POST_INC
-                          && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
-                     break;
-                   pushes++;
-                   if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)))
-                       > stack_adjust_amount)
-                     break;
-                   total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
-                 }
-
-               /* Discard the amount pushed from the stack adjust;
-                  maybe eliminate it entirely.  */
-               if (total_pushed >= stack_adjust_amount)
-                 {
-                   delete_computation (stack_adjust_insn);
-                   total_pushed = stack_adjust_amount;
-                 }
-               else
-                 XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1)
-                   = GEN_INT (stack_adjust_amount - total_pushed);
-
-               /* Change the appropriate push insns to ordinary stores.  */
-               p = insn;
-               while (total_pushed > 0)
-                 {
-                   rtx pbody, dest;
-                   p = next_nonnote_insn (p);
-                   if (GET_CODE (p) != INSN)
-                     break;
-                   pbody = PATTERN (p);
-                   if (GET_CODE (pbody) != SET)
-                     break;
-                   dest = SET_DEST (pbody);
-                   /* Allow a no-op move between the adjust and the push.  */
-                   if (GET_CODE (dest) == REG
-                       && GET_CODE (SET_SRC (pbody)) == REG
-                       && REGNO (dest) == REGNO (SET_SRC (pbody)))
-                     continue;
-                   if (! (GET_CODE (dest) == MEM
-                          && GET_CODE (XEXP (dest, 0)) == POST_INC
-                          && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
-                     break;
-                   total_pushed -= GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
-                   /* If this push doesn't fully fit in the space
-                      of the stack adjust that we deleted,
-                      make another stack adjust here for what we
-                      didn't use up.  There should be peepholes
-                      to recognize the resulting sequence of insns.  */
-                   if (total_pushed < 0)
-                     {
-                       emit_insn_before (gen_add2_insn (stack_pointer_rtx,
-                                                        GEN_INT (- total_pushed)),
-                                         p);
-                       break;
-                     }
-                   XEXP (dest, 0)
-                     = plus_constant (stack_pointer_rtx, total_pushed);
-                 }
-             }
-#endif
-
-           /* Detect and delete no-op move instructions
-              resulting from not allocating a parameter in a register.  */
-
-           if (GET_CODE (body) == SET
-               && (SET_DEST (body) == SET_SRC (body)
-                   || (GET_CODE (SET_DEST (body)) == MEM
-                       && GET_CODE (SET_SRC (body)) == MEM
-                       && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
-               && ! (GET_CODE (SET_DEST (body)) == MEM
-                     && MEM_VOLATILE_P (SET_DEST (body)))
-               && ! (GET_CODE (SET_SRC (body)) == MEM
-                     && MEM_VOLATILE_P (SET_SRC (body))))
-             delete_computation (insn);
-
-           /* Detect and ignore no-op move instructions
-              resulting from smart or fortuitous register allocation.  */
-
-           else if (GET_CODE (body) == SET)
-             {
-               int sreg = true_regnum (SET_SRC (body));
-               int dreg = true_regnum (SET_DEST (body));
-
-               if (sreg == dreg && sreg >= 0)
-                 delete_insn (insn);
-               else if (sreg >= 0 && dreg >= 0)
-                 {
-                   rtx trial;
-                   rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
-                                             sreg, NULL_PTR, dreg,
-                                             GET_MODE (SET_SRC (body)));
-
-                   if (tem != 0
-                       && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
-                     {
-                       /* DREG may have been the target of a REG_DEAD note in
-                          the insn which makes INSN redundant.  If so, reorg
-                          would still think it is dead.  So search for such a
-                          note and delete it if we find it.  */
-                       if (! find_regno_note (insn, REG_UNUSED, dreg))
-                         for (trial = prev_nonnote_insn (insn);
-                              trial && GET_CODE (trial) != CODE_LABEL;
-                              trial = prev_nonnote_insn (trial))
-                           if (find_regno_note (trial, REG_DEAD, dreg))
-                             {
-                               remove_death (dreg, trial);
-                               break;
-                             }
-
-                       /* Deleting insn could lose a death-note for SREG.  */
-                       if ((trial = find_regno_note (insn, REG_DEAD, sreg)))
-                         {
-                           /* Change this into a USE so that we won't emit
-                              code for it, but still can keep the note.  */
-                           PATTERN (insn)
-                             = gen_rtx_USE (VOIDmode, XEXP (trial, 0));
-                           INSN_CODE (insn) = -1;
-                           /* Remove all reg notes but the REG_DEAD one.  */
-                           REG_NOTES (insn) = trial;
-                           XEXP (trial, 1) = NULL_RTX;
-                         }
-                       else
-                         delete_insn (insn);
-                     }
-                 }
-               else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
-                        && find_equiv_reg (SET_SRC (body), insn, 0, dreg,
-                                           NULL_PTR, 0,
-                                           GET_MODE (SET_DEST (body))))
-                 {
-                   /* This handles the case where we have two consecutive
-                      assignments of the same constant to pseudos that didn't
-                      get a hard reg.  Each SET from the constant will be
-                      converted into a SET of the spill register and an
-                      output reload will be made following it.  This produces
-                      two loads of the same constant into the same spill
-                      register.  */
-
-                   rtx in_insn = insn;
-
-                   /* Look back for a death note for the first reg.
-                      If there is one, it is no longer accurate.  */
-                   while (in_insn && GET_CODE (in_insn) != CODE_LABEL)
-                     {
-                       if ((GET_CODE (in_insn) == INSN
-                            || GET_CODE (in_insn) == JUMP_INSN)
-                           && find_regno_note (in_insn, REG_DEAD, dreg))
-                         {
-                           remove_death (dreg, in_insn);
-                           break;
-                         }
-                       in_insn = PREV_INSN (in_insn);
-                     }
-
-                   /* Delete the second load of the value.  */
-                   delete_insn (insn);
-                 }
-             }
-           else if (GET_CODE (body) == PARALLEL)
-             {
-               /* If each part is a set between two identical registers or
-                  a USE or CLOBBER, delete the insn.  */
-               int i, sreg, dreg;
-               rtx tem;
-
-               for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
-                 {
-                   tem = XVECEXP (body, 0, i);
-                   if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
-                     continue;
-
-                   if (GET_CODE (tem) != SET
-                       || (sreg = true_regnum (SET_SRC (tem))) < 0
-                       || (dreg = true_regnum (SET_DEST (tem))) < 0
-                       || dreg != sreg)
-                     break;
-                 }
-                 
-               if (i < 0)
-                 delete_insn (insn);
-             }
-           /* Also delete insns to store bit fields if they are no-ops.  */
-           /* Not worth the hair to detect this in the big-endian case.  */
-           else if (! BYTES_BIG_ENDIAN
-                    && GET_CODE (body) == SET
-                    && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT
-                    && XEXP (SET_DEST (body), 2) == const0_rtx
-                    && XEXP (SET_DEST (body), 0) == SET_SRC (body)
-                    && ! (GET_CODE (SET_SRC (body)) == MEM
-                          && MEM_VOLATILE_P (SET_SRC (body))))
-             delete_insn (insn);
-         }
-      insn = next;
-    }
+    delete_noop_moves (f);
 
   /* If we haven't yet gotten to reload and we have just run regscan,
      delete any insn that sets a register that isn't used elsewhere.
@@ -2371,41 +2032,450 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
     }
 #endif
 
-  /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
-     If so, delete it, and record that this function can drop off the end.  */
+  can_reach_end = calculate_can_reach_end (last_insn, 0, 1);
+
+  /* Show JUMP_CHAIN no longer valid.  */
+  jump_chain = 0;
+}
+\f
+/* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
+   notes whose labels don't occur in the insn any more.  Returns the
+   largest INSN_UID found.  */
+static int
+init_label_info (f)
+     rtx f;
+{
+  int largest_uid = 0;
+  rtx insn;
+
+  for (insn = f; insn; insn = NEXT_INSN (insn))
+    {
+      if (GET_CODE (insn) == CODE_LABEL)
+       LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+      else if (GET_CODE (insn) == JUMP_INSN)
+       JUMP_LABEL (insn) = 0;
+      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+       {
+         rtx note, next;
+
+         for (note = REG_NOTES (insn); note; note = next)
+           {
+             next = XEXP (note, 1);
+             if (REG_NOTE_KIND (note) == REG_LABEL
+                 && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+               remove_note (insn, note);
+           }
+       }
+      if (INSN_UID (insn) > largest_uid)
+       largest_uid = INSN_UID (insn);
+    }
+
+  return largest_uid;
+}
+
+/* Delete insns following barriers, up to next label.  */
+static void
+delete_barrier_successors (f)
+     rtx f;
+{
+  rtx insn;
+
+  for (insn = f; insn;)
+    {
+      if (GET_CODE (insn) == BARRIER)
+       {
+         insn = NEXT_INSN (insn);
+         while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
+           {
+             if (GET_CODE (insn) == NOTE
+                 && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
+               insn = NEXT_INSN (insn);
+             else
+               insn = delete_insn (insn);
+           }
+         /* INSN is now the code_label.  */
+       }
+      else
+       insn = NEXT_INSN (insn);
+    }
+}
+
+/* Mark the label each jump jumps to.
+   Combine consecutive labels, and count uses of labels.
+
+   For each label, make a chain (using `jump_chain')
+   of all the *unconditional* jumps that jump to it;
+   also make a chain of all returns.
+
+   CROSS_JUMP indicates whether we are doing cross jumping
+   and if we are whether we will be paying attention to
+   death notes or not.  */
+
+static void
+mark_all_labels (f, cross_jump)
+     rtx f;
+     int cross_jump;
+{
+  rtx insn;
+
+  for (insn = f; insn; insn = NEXT_INSN (insn))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      {
+       mark_jump_label (PATTERN (insn), insn, cross_jump);
+       if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
+         {
+           if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
+             {
+               jump_chain[INSN_UID (insn)]
+                 = jump_chain[INSN_UID (JUMP_LABEL (insn))];
+               jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
+             }
+           if (GET_CODE (PATTERN (insn)) == RETURN)
+             {
+               jump_chain[INSN_UID (insn)] = jump_chain[0];
+               jump_chain[0] = insn;
+             }
+         }
+      }
+}
+
+/* Delete all labels already not referenced.
+   Also find and return the last insn.  */
+
+static rtx
+delete_unreferenced_labels (f)
+     rtx f;
+{
+  rtx final = NULL_RTX;
+  rtx insn;
+
+  for (insn = f; insn; )
+    {
+      if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0)
+       insn = delete_insn (insn);
+      else
+       {
+         final = insn;
+         insn = NEXT_INSN (insn);
+       }
+    }
+
+  return final;
+}
+
+/* Delete various simple forms of moves which have no necessary
+   side effect.  */
+
+static void
+delete_noop_moves (f)
+     rtx f;
+{
+  rtx insn, next;
+
+  for (insn = f; insn; )
+    {
+      next = NEXT_INSN (insn);
+
+      if (GET_CODE (insn) == INSN)
+       {
+         register rtx body = PATTERN (insn);
+
+/* Combine stack_adjusts with following push_insns.  */
+#ifdef PUSH_ROUNDING
+         if (GET_CODE (body) == SET
+             && SET_DEST (body) == stack_pointer_rtx
+             && GET_CODE (SET_SRC (body)) == PLUS
+             && XEXP (SET_SRC (body), 0) == stack_pointer_rtx
+             && GET_CODE (XEXP (SET_SRC (body), 1)) == CONST_INT
+             && INTVAL (XEXP (SET_SRC (body), 1)) > 0)
+           {
+             rtx p;
+             rtx stack_adjust_insn = insn;
+             int stack_adjust_amount = INTVAL (XEXP (SET_SRC (body), 1));
+             int total_pushed = 0;
+             int pushes = 0;
+
+             /* Find all successive push insns.  */
+             p = insn;
+             /* Don't convert more than three pushes;
+                that starts adding too many displaced addresses
+                and the whole thing starts becoming a losing
+                proposition.  */
+             while (pushes < 3)
+               {
+                 rtx pbody, dest;
+                 p = next_nonnote_insn (p);
+                 if (p == 0 || GET_CODE (p) != INSN)
+                   break;
+                 pbody = PATTERN (p);
+                 if (GET_CODE (pbody) != SET)
+                   break;
+                 dest = SET_DEST (pbody);
+                 /* Allow a no-op move between the adjust and the push.  */
+                 if (GET_CODE (dest) == REG
+                     && GET_CODE (SET_SRC (pbody)) == REG
+                     && REGNO (dest) == REGNO (SET_SRC (pbody)))
+                   continue;
+                 if (! (GET_CODE (dest) == MEM
+                        && GET_CODE (XEXP (dest, 0)) == POST_INC
+                        && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
+                   break;
+                 pushes++;
+                 if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)))
+                     > stack_adjust_amount)
+                   break;
+                 total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
+               }
+
+             /* Discard the amount pushed from the stack adjust;
+                maybe eliminate it entirely.  */
+             if (total_pushed >= stack_adjust_amount)
+               {
+                 delete_computation (stack_adjust_insn);
+                 total_pushed = stack_adjust_amount;
+               }
+             else
+               XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1)
+                 = GEN_INT (stack_adjust_amount - total_pushed);
+
+             /* Change the appropriate push insns to ordinary stores.  */
+             p = insn;
+             while (total_pushed > 0)
+               {
+                 rtx pbody, dest;
+                 p = next_nonnote_insn (p);
+                 if (GET_CODE (p) != INSN)
+                   break;
+                 pbody = PATTERN (p);
+                 if (GET_CODE (pbody) != SET)
+                   break;
+                 dest = SET_DEST (pbody);
+                 /* Allow a no-op move between the adjust and the push.  */
+                 if (GET_CODE (dest) == REG
+                     && GET_CODE (SET_SRC (pbody)) == REG
+                     && REGNO (dest) == REGNO (SET_SRC (pbody)))
+                   continue;
+                 if (! (GET_CODE (dest) == MEM
+                        && GET_CODE (XEXP (dest, 0)) == POST_INC
+                        && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
+                   break;
+                 total_pushed -= GET_MODE_SIZE (GET_MODE (SET_DEST (pbody)));
+                 /* If this push doesn't fully fit in the space
+                    of the stack adjust that we deleted,
+                    make another stack adjust here for what we
+                    didn't use up.  There should be peepholes
+                    to recognize the resulting sequence of insns.  */
+                 if (total_pushed < 0)
+                   {
+                     emit_insn_before (gen_add2_insn (stack_pointer_rtx,
+                                                      GEN_INT (- total_pushed)),
+                                       p);
+                     break;
+                   }
+                 XEXP (dest, 0)
+                   = plus_constant (stack_pointer_rtx, total_pushed);
+               }
+           }
+#endif
+
+         /* Detect and delete no-op move instructions
+            resulting from not allocating a parameter in a register.  */
+
+         if (GET_CODE (body) == SET
+             && (SET_DEST (body) == SET_SRC (body)
+                 || (GET_CODE (SET_DEST (body)) == MEM
+                     && GET_CODE (SET_SRC (body)) == MEM
+                     && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
+             && ! (GET_CODE (SET_DEST (body)) == MEM
+                   && MEM_VOLATILE_P (SET_DEST (body)))
+             && ! (GET_CODE (SET_SRC (body)) == MEM
+                   && MEM_VOLATILE_P (SET_SRC (body))))
+           delete_computation (insn);
+
+         /* Detect and ignore no-op move instructions
+            resulting from smart or fortuitous register allocation.  */
+
+         else if (GET_CODE (body) == SET)
+           {
+             int sreg = true_regnum (SET_SRC (body));
+             int dreg = true_regnum (SET_DEST (body));
+
+             if (sreg == dreg && sreg >= 0)
+               delete_insn (insn);
+             else if (sreg >= 0 && dreg >= 0)
+               {
+                 rtx trial;
+                 rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
+                                           sreg, NULL_PTR, dreg,
+                                           GET_MODE (SET_SRC (body)));
+
+                 if (tem != 0
+                     && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
+                   {
+                     /* DREG may have been the target of a REG_DEAD note in
+                        the insn which makes INSN redundant.  If so, reorg
+                        would still think it is dead.  So search for such a
+                        note and delete it if we find it.  */
+                     if (! find_regno_note (insn, REG_UNUSED, dreg))
+                       for (trial = prev_nonnote_insn (insn);
+                            trial && GET_CODE (trial) != CODE_LABEL;
+                            trial = prev_nonnote_insn (trial))
+                         if (find_regno_note (trial, REG_DEAD, dreg))
+                           {
+                             remove_death (dreg, trial);
+                             break;
+                           }
+
+                     /* Deleting insn could lose a death-note for SREG.  */
+                     if ((trial = find_regno_note (insn, REG_DEAD, sreg)))
+                       {
+                         /* Change this into a USE so that we won't emit
+                            code for it, but still can keep the note.  */
+                         PATTERN (insn)
+                           = gen_rtx_USE (VOIDmode, XEXP (trial, 0));
+                         INSN_CODE (insn) = -1;
+                         /* Remove all reg notes but the REG_DEAD one.  */
+                         REG_NOTES (insn) = trial;
+                         XEXP (trial, 1) = NULL_RTX;
+                       }
+                     else
+                       delete_insn (insn);
+                   }
+               }
+             else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
+                      && find_equiv_reg (SET_SRC (body), insn, 0, dreg,
+                                         NULL_PTR, 0,
+                                         GET_MODE (SET_DEST (body))))
+               {
+                 /* This handles the case where we have two consecutive
+                    assignments of the same constant to pseudos that didn't
+                    get a hard reg.  Each SET from the constant will be
+                    converted into a SET of the spill register and an
+                    output reload will be made following it.  This produces
+                    two loads of the same constant into the same spill
+                    register.  */
+
+                 rtx in_insn = insn;
+
+                 /* Look back for a death note for the first reg.
+                    If there is one, it is no longer accurate.  */
+                 while (in_insn && GET_CODE (in_insn) != CODE_LABEL)
+                   {
+                     if ((GET_CODE (in_insn) == INSN
+                          || GET_CODE (in_insn) == JUMP_INSN)
+                         && find_regno_note (in_insn, REG_DEAD, dreg))
+                       {
+                         remove_death (dreg, in_insn);
+                         break;
+                       }
+                     in_insn = PREV_INSN (in_insn);
+                   }
+
+                 /* Delete the second load of the value.  */
+                 delete_insn (insn);
+               }
+           }
+         else if (GET_CODE (body) == PARALLEL)
+           {
+             /* If each part is a set between two identical registers or
+                a USE or CLOBBER, delete the insn.  */
+             int i, sreg, dreg;
+             rtx tem;
+
+             for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+               {
+                 tem = XVECEXP (body, 0, i);
+                 if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
+                   continue;
+
+                 if (GET_CODE (tem) != SET
+                     || (sreg = true_regnum (SET_SRC (tem))) < 0
+                     || (dreg = true_regnum (SET_DEST (tem))) < 0
+                     || dreg != sreg)
+                   break;
+               }
+                 
+             if (i < 0)
+               delete_insn (insn);
+           }
+         /* Also delete insns to store bit fields if they are no-ops.  */
+         /* Not worth the hair to detect this in the big-endian case.  */
+         else if (! BYTES_BIG_ENDIAN
+                  && GET_CODE (body) == SET
+                  && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT
+                  && XEXP (SET_DEST (body), 2) == const0_rtx
+                  && XEXP (SET_DEST (body), 0) == SET_SRC (body)
+                  && ! (GET_CODE (SET_SRC (body)) == MEM
+                        && MEM_VOLATILE_P (SET_SRC (body))))
+           delete_insn (insn);
+       }
+      insn = next;
+    }
+}
+
+/* See if there is still a NOTE_INSN_FUNCTION_END in this function.
+   If so indicate that this function can drop off the end by returning
+   1, else return 0.
+
+   CHECK_DELETED indicates whether we must check if the note being
+   searched for has the deleted flag set.
+
+   DELETE_FINAL_NOTE indicates whether we should delete the note
+   if we find it.  */
+
+static int
+calculate_can_reach_end (last, check_deleted, delete_final_note)
+     rtx last;
+     int check_deleted;
+     int delete_final_note;
+{
+  rtx insn = last;
+  int n_labels = 1;
+
+  while (insn != NULL_RTX)
+    {
+      int ok = 0;
+
+      /* One label can follow the end-note: the return label.  */
+      if (GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
+       ok = 1;
+      /* Ordinary insns can follow it if returning a structure.  */
+      else if (GET_CODE (insn) == INSN)
+       ok = 1;
+      /* If machine uses explicit RETURN insns, no epilogue,
+        then one of them follows the note.  */
+      else if (GET_CODE (insn) == JUMP_INSN
+              && GET_CODE (PATTERN (insn)) == RETURN)
+       ok = 1;
+      /* A barrier can follow the return insn.  */
+      else if (GET_CODE (insn) == BARRIER)
+       ok = 1;
+      /* Other kinds of notes can follow also.  */
+      else if (GET_CODE (insn) == NOTE
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
+       ok = 1;
+
+      if (ok != 1)
+       break;
 
-  insn = last_insn;
-  {
-    int n_labels = 1;
-    while (insn
-          /* One label can follow the end-note: the return label.  */
-          && ((GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
-              /* Ordinary insns can follow it if returning a structure.  */
-              || GET_CODE (insn) == INSN
-              /* If machine uses explicit RETURN insns, no epilogue,
-                 then one of them follows the note.  */
-              || (GET_CODE (insn) == JUMP_INSN
-                  && GET_CODE (PATTERN (insn)) == RETURN)
-              /* A barrier can follow the return insn.  */
-              || GET_CODE (insn) == BARRIER
-              /* Other kinds of notes can follow also.  */
-              || (GET_CODE (insn) == NOTE
-                  && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)))
       insn = PREV_INSN (insn);
-  }
+    }
 
-  /* Report if control can fall through at the end of the function.  */
-  if (insn && GET_CODE (insn) == NOTE
-      && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
+  /* See if we backed up to the appropriate type of note.  */
+  if (insn != NULL_RTX
+      && GET_CODE (insn) == NOTE
+      && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
+      && (check_deleted != 0
+         && ! INSN_DELETED_P (insn)))
     {
-      can_reach_end = 1;
-      delete_insn (insn);
+      if (delete_final_note)
+       delete_insn (insn);
+      return 1;
     }
 
-  /* Show JUMP_CHAIN no longer valid.  */
-  jump_chain = 0;
+  return 0;
 }
-\f
+
 /* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional
    jump.  Assume that this unconditional jump is to the exit test code.  If
    the code is sufficiently simple, make a copy of it before INSN,
This page took 0.108225 seconds and 5 git commands to generate.