OSDN Git Service

(DUCR.M,DUC.M): Defined.
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index df4d79c..8cd4473 100644 (file)
@@ -1,5 +1,5 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
@@ -17,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* Instruction reorganization pass.
 
@@ -129,6 +130,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "insn-attr.h"
 
+/* Import list of registers used as spill regs from reload.  */
+extern HARD_REG_SET used_spill_regs;
+
+/* Import highest label used in function at end of reload.  */
+extern int max_label_num_after_reload;
+
+
 #ifdef DELAY_SLOTS
 
 #define obstack_chunk_alloc xmalloc
@@ -162,14 +170,15 @@ static rtx *unfilled_firstobj;
 struct resources
 {
   char memory;                 /* Insn sets or needs a memory location.  */
-  char volatil;                        /* Insn sets or needs a volatile memory loc. */
+  char unch_memory;            /* Insn sets of needs a "unchanging" MEM.  */
+  char volatil;                        /* Insn sets or needs a volatile memory loc.  */
   char cc;                     /* Insn sets or needs the condition codes.  */
   HARD_REG_SET regs;           /* Which registers are set or needed.  */
 };
 
 /* Macro to clear all resources.  */
 #define CLEAR_RESOURCE(RES)    \
- do { (RES)->memory = (RES)->volatil = (RES)->cc = 0;  \
+ do { (RES)->memory = (RES)->unch_memory = (RES)->volatil = (RES)->cc = 0; \
       CLEAR_HARD_REG_SET ((RES)->regs); } while (0)
 
 /* Indicates what resources are required at the beginning of the epilogue.  */
@@ -244,12 +253,14 @@ static rtx steal_delay_list_from_fallthrough PROTO((rtx, rtx, rtx, rtx,
                                                    struct resources *,
                                                    int, int *, int *));
 static void try_merge_delay_insns PROTO((rtx, rtx));
-static int redundant_insn_p    PROTO((rtx, rtx, rtx));
+static rtx redundant_insn      PROTO((rtx, rtx, rtx));
 static int own_thread_p                PROTO((rtx, rtx, int));
 static int find_basic_block    PROTO((rtx));
 static void update_block       PROTO((rtx, rtx));
 static int reorg_redirect_jump PROTO((rtx, rtx));
 static void update_reg_dead_notes PROTO((rtx, rtx));
+static void fix_reg_dead_note PROTO((rtx, rtx));
+static void update_reg_unused_notes PROTO((rtx, rtx));
 static void update_live_status PROTO((rtx, rtx));
 static rtx next_insn_no_annul  PROTO((rtx));
 static void mark_target_live_regs PROTO((rtx, struct resources *));
@@ -259,6 +270,8 @@ static rtx fill_slots_from_thread PROTO((rtx, rtx, rtx, rtx, int, int,
 static void fill_eager_delay_slots PROTO((rtx));
 static void relax_delay_slots  PROTO((rtx));
 static void make_return_insns  PROTO((rtx));
+static int redirect_with_delay_slots_safe_p PROTO ((rtx, rtx, rtx));
+static int redirect_with_delay_list_safe_p PROTO ((rtx, rtx, rtx));
 \f
 /* Given X, some rtl, and RES, a pointer to a `struct resource', mark
    which resources are references by the insn.  If INCLUDE_CALLED_ROUTINE
@@ -307,7 +320,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
     case MEM:
       /* If this memory shouldn't change, it really isn't referencing
         memory.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+       res->unch_memory = 1;
+      else
        res->memory = 1;
       res->volatil = MEM_VOLATILE_P (x);
 
@@ -321,6 +336,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
 
     case UNSPEC_VOLATILE:
     case ASM_INPUT:
+    case TRAP_IF:
       /* Traditional asm's are always volatile.  */
       res->volatil = 1;
       return;
@@ -376,11 +392,13 @@ mark_referenced_resources (x, res, include_delayed_effects)
          rtx insn = PREV_INSN (x);
          rtx sequence = 0;
          int seq_size = 0;
+         rtx next = NEXT_INSN (x);
          int i;
 
-         /* If we are part of a delay slot sequence, point at the SEQUENCE. */
+         /* If we are part of a delay slot sequence, point at the SEQUENCE.  */
          if (NEXT_INSN (insn) != x)
            {
+             next = NEXT_INSN (NEXT_INSN (insn));
              sequence = PATTERN (NEXT_INSN (insn));
              seq_size = XVECLEN (sequence, 0);
              if (GET_CODE (sequence) != SEQUENCE)
@@ -401,28 +419,42 @@ mark_referenced_resources (x, res, include_delayed_effects)
            if (global_regs[i])
              SET_HARD_REG_BIT (res->regs, i);
 
-         /* Skip any labels between the CALL_INSN and possible USE insns.  */
-         while (GET_CODE (insn) == CODE_LABEL)
-           insn = PREV_INSN (insn);
+         /* Check for a NOTE_INSN_SETJMP.  If it exists, then we must
+            assume that this call can need any register.
 
-         for ( ; (insn && GET_CODE (insn) == INSN
-                  && GET_CODE (PATTERN (insn)) == USE);
-              insn = PREV_INSN (insn))
-           {
-             for (i = 1; i < seq_size; i++)
+            This is done to be more conservative about how we handle setjmp.
+            We assume that they both use and set all registers.  Using all
+            registers ensures that a register will not be considered dead
+            just because it crosses a setjmp call.  A register should be
+            considered dead only if the setjmp call returns non-zero.  */
+         if (next && GET_CODE (next) == NOTE
+             && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP)
+           SET_HARD_REG_SET (res->regs);
+
+         {
+           rtx link;
+
+           for (link = CALL_INSN_FUNCTION_USAGE (x);
+                link;
+                link = XEXP (link, 1))
+             if (GET_CODE (XEXP (link, 0)) == USE)
                {
-                 rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i));
-                 if (GET_CODE (slot_pat) == SET
-                     && rtx_equal_p (SET_DEST (slot_pat),
-                                     XEXP (PATTERN (insn), 0)))
-                   break;
+                 for (i = 1; i < seq_size; i++)
+                   {
+                     rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i));
+                     if (GET_CODE (slot_pat) == SET
+                         && rtx_equal_p (SET_DEST (slot_pat),
+                                         SET_DEST (XEXP (link, 0))))
+                       break;
+                   }
+                 if (i >= seq_size)
+                   mark_referenced_resources (SET_DEST (XEXP (link, 0)),
+                                              res, 0);
                }
-             if (i >= seq_size)
-               mark_referenced_resources (XEXP (PATTERN (insn), 0), res, 0);
-           }
+         }
        }
 
-      /* ... fall through to other INSN processing ... */
+      /* ... fall through to other INSN processing ...  */
 
     case INSN:
     case JUMP_INSN:
@@ -512,6 +544,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
        {
          rtx next = NEXT_INSN (x);
          rtx prev = PREV_INSN (x);
+         rtx link;
 
          res->cc = res->memory = 1;
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -523,14 +556,10 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
          if (NEXT_INSN (prev) != x)
            next = NEXT_INSN (NEXT_INSN (prev));
 
-         /* Skip any possible labels between the CALL_INSN and CLOBBERs.  */
-         while (GET_CODE (next) == CODE_LABEL)
-           next = NEXT_INSN (next);
-
-         for (; (next && GET_CODE (next) == INSN
-                 && GET_CODE (PATTERN (next)) == CLOBBER);
-              next = NEXT_INSN (next))
-           mark_set_resources (XEXP (PATTERN (next), 0), res, 1, 0);
+         for (link = CALL_INSN_FUNCTION_USAGE (x);
+              link; link = XEXP (link, 1))
+           if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+             mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1, 0);
 
          /* Check for a NOTE_INSN_SETJMP.  If it exists, then we must
             assume that this call can clobber any register.  */
@@ -600,12 +629,29 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
       if (in_dest)
        {
          res->memory = 1;
+         res->unch_memory = RTX_UNCHANGING_P (x);
          res->volatil = MEM_VOLATILE_P (x);
        }
 
       mark_set_resources (XEXP (x, 0), res, 0, 0);
       return;
 
+    case SUBREG:
+      if (in_dest)
+       {
+         if (GET_CODE (SUBREG_REG (x)) != REG)
+           mark_set_resources (SUBREG_REG (x), res,
+                               in_dest, include_delayed_effects);
+         else
+           {
+             int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+             int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+             for (i = regno; i < last_regno; i++)
+               SET_HARD_REG_BIT (res->regs, i);
+           }
+       }
+      return;
+
     case REG:
       if (in_dest)
         for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++)
@@ -675,6 +721,7 @@ resource_conflicts_p (res1, res2)
      struct resources *res1, *res2;
 {
   if ((res1->cc && res2->cc) || (res1->memory && res2->memory)
+      || (res1->unch_memory && res2->unch_memory)
       || res1->volatil || res2->volatil)
     return 1;
 
@@ -766,7 +813,7 @@ find_end_label ()
       end_of_function_label = gen_label_rtx ();
       LABEL_NUSES (end_of_function_label) = 0;
 
-      /* Put the label before an USE insns that may proceed the RETURN insn. */
+      /* Put the label before an USE insns that may proceed the RETURN insn.  */
       while (GET_CODE (temp) == USE)
        temp = PREV_INSN (temp);
 
@@ -823,14 +870,14 @@ emit_delay_sequence (insn, list, length, avail)
   register rtx li;
   int had_barrier = 0;
 
-  /* Allocate the the rtvec to hold the insns and the SEQUENCE. */
+  /* Allocate the the rtvec to hold the insns and the SEQUENCE.  */
   rtvec seqv = rtvec_alloc (length + 1);
   rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);
   rtx seq_insn = make_insn_raw (seq);
   rtx first = get_insns ();
   rtx last = get_last_insn ();
 
-  /* Make a copy of the insn having delay slots. */
+  /* Make a copy of the insn having delay slots.  */
   rtx delay_insn = copy_rtx (insn);
 
   /* If INSN is followed by a BARRIER, delete the BARRIER since it will only
@@ -1180,6 +1227,7 @@ optimize_skip (insn)
 
     Non conditional branches return no direction information and
     are predicted as very likely taken.  */
+
 static int
 get_jump_flags (insn, label)
      rtx insn, label;
@@ -1193,7 +1241,7 @@ get_jump_flags (insn, label)
      If LABEL is zero, then there is no way to determine the branch
      direction.  */
   if (GET_CODE (insn) == JUMP_INSN
-      && condjump_p (insn)
+      && (condjump_p (insn) || condjump_in_parallel_p (insn))
       && INSN_UID (insn) <= max_uid
       && label != 0
       && INSN_UID (label) <= max_uid)
@@ -1209,7 +1257,7 @@ get_jump_flags (insn, label)
 
      Non conditional branches are predicted as very likely taken.  */
   if (GET_CODE (insn) == JUMP_INSN
-      && condjump_p (insn))
+      && (condjump_p (insn) || condjump_in_parallel_p (insn)))
     {
       int prediction;
 
@@ -1302,6 +1350,26 @@ mostly_true_jump (jump_insn, condition)
   int rare_dest = rare_destination (target_label);
   int rare_fallthrough = rare_destination (NEXT_INSN (jump_insn));
 
+  /* If branch probabilities are available, then use that number since it
+     always gives a correct answer.  */
+  if (flag_branch_probabilities)
+    {
+      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);;
+      if (note)
+       {
+         int prob = XINT (note, 0);
+
+         if (prob >= REG_BR_PROB_BASE * 9 / 10)
+           return 2;
+         else if (prob >= REG_BR_PROB_BASE / 2)
+           return 1;
+         else if (prob >= REG_BR_PROB_BASE / 10)
+           return 0;
+         else
+           return -1;
+       }
+    }
+
   /* If this is a branch outside a loop, it is highly unlikely.  */
   if (GET_CODE (PATTERN (jump_insn)) == SET
       && GET_CODE (SET_SRC (PATTERN (jump_insn))) == IF_THEN_ELSE
@@ -1334,8 +1402,8 @@ mostly_true_jump (jump_insn, condition)
          return 1;
     }
 
-  /* Look at the relative rarities of the fallthough and destination.  If
-     they differ, we can predict the branch that way. */
+  /* Look at the relative rarities of the fallthrough and destination.  If
+     they differ, we can predict the branch that way.  */
 
   switch (rare_fallthrough - rare_dest)
     {
@@ -1402,6 +1470,9 @@ get_branch_condition (insn, target)
   rtx pat = PATTERN (insn);
   rtx src;
   
+  if (condjump_in_parallel_p (insn))
+    pat = XVECEXP (pat, 0, 0);
+
   if (GET_CODE (pat) == RETURN)
     return target == 0 ? const_true_rtx : 0;
 
@@ -1494,6 +1565,39 @@ redirect_with_delay_slots_safe_p (jump, newlabel, seq)
   return (i == XVECLEN (pat, 0));
 }
 
+/* Return non-zero if redirecting JUMP to NEWLABEL does not invalidate
+   any insns we wish to place in the delay slot of JUMP.  */
+
+static int
+redirect_with_delay_list_safe_p (jump, newlabel, delay_list)
+     rtx jump, newlabel, delay_list;
+{
+  int flags, i;
+  rtx li;
+
+  /* Make sure all the insns in DELAY_LIST would still be
+     valid after threading the jump.  If they are still
+     valid, then return non-zero.  */
+
+  flags = get_jump_flags (jump, newlabel);
+  for (li = delay_list, i = 0; li; li = XEXP (li, 1), i++)
+    if (! (
+#ifdef ANNUL_IFFALSE_SLOTS
+          (INSN_ANNULLED_BRANCH_P (jump)
+           && INSN_FROM_TARGET_P (XEXP (li, 0)))
+          ? eligible_for_annul_false (jump, i, XEXP (li, 0), flags) :
+#endif
+#ifdef ANNUL_IFTRUE_SLOTS
+          (INSN_ANNULLED_BRANCH_P (jump)
+           && ! INSN_FROM_TARGET_P (XEXP (li, 0)))
+          ? eligible_for_annul_true (jump, i, XEXP (li, 0), flags) :
+#endif
+          eligible_for_delay (jump, i, XEXP (li, 0), flags)))
+      break;
+
+  return (li == NULL);
+}
+
 \f
 /* INSN branches to an insn whose pattern SEQ is a SEQUENCE.  Given that
    the condition tested by INSN is CONDITION and the resources shown in
@@ -1538,12 +1642,17 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
 
   /* We can't do anything if there are more delay slots in SEQ than we
      can handle, or if we don't know that it will be a taken branch.
-
      We know that it will be a taken branch if it is either an unconditional
-     branch or a conditional branch with a stricter branch condition.  */
+     branch or a conditional branch with a stricter branch condition.
+
+     Also, exit if the branch has more than one set, since then it is computing
+     other results that can't be ignored, e.g. the HPPA mov&branch instruction.
+     ??? It may be possible to move other sets into INSN in addition to
+     moving the instructions in the delay slots.  */
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
-      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0)))
+      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))
+      || ! single_set (XVECEXP (seq, 0, 0)))
     return delay_list;
 
   for (i = 1; i < XVECLEN (seq, 0); i++)
@@ -1567,7 +1676,7 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
 
       /* If this insn was already done (usually in a previous delay slot),
         pretend we put it in our delay slot.  */
-      if (redundant_insn_p (trial, insn, new_delay_list))
+      if (redundant_insn (trial, insn, new_delay_list))
        continue;
 
       /* We will end up re-vectoring this branch, so compute flags
@@ -1657,7 +1766,7 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
        break;
 
       /* If this insn was already done, we don't need it.  */
-      if (redundant_insn_p (trial, insn, delay_list))
+      if (redundant_insn (trial, insn, delay_list))
        {
          delete_from_delay_slot (trial);
          continue;
@@ -1725,6 +1834,7 @@ try_merge_delay_insns (insn, thread)
   for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
     {
       rtx pat = PATTERN (trial);
+      rtx oldtrial = trial;
 
       next_trial = next_nonnote_insn (trial);
 
@@ -1744,6 +1854,8 @@ try_merge_delay_insns (insn, thread)
          && (trial = try_split (pat, trial, 0)) != 0
          /* Update next_trial, in case try_split succeeded.  */
          && (next_trial = next_nonnote_insn (trial))
+         /* Likewise THREAD.  */
+         && (thread = oldtrial == thread ? trial : thread)
          && rtx_equal_p (PATTERN (next_to_match), PATTERN (trial))
          /* Have to test this condition if annul condition is different
             from (and less restrictive than) non-annulling one.  */
@@ -1753,6 +1865,9 @@ try_merge_delay_insns (insn, thread)
          if (! annul_p)
            {
              update_block (trial, thread);
+             if (trial == thread)
+               thread = next_active_insn (thread);
+
              delete_insn (trial);
              INSN_FROM_TARGET_P (next_to_match) = 0;
            }
@@ -1779,6 +1894,11 @@ try_merge_delay_insns (insn, thread)
       && ! INSN_ANNULLED_BRANCH_P (XVECEXP (PATTERN (trial), 0, 0)))
     {
       rtx pat = PATTERN (trial);
+      rtx filled_insn = XVECEXP (pat, 0, 0);
+
+      /* Account for resources set/needed by the filled insn.  */
+      mark_set_resources (filled_insn, &set, 0, 1);
+      mark_referenced_resources (filled_insn, &needed, 1);
 
       for (i = 1; i < XVECLEN (pat, 0); i++)
        {
@@ -1858,8 +1978,8 @@ try_merge_delay_insns (insn, thread)
    redundant insn, but the cost of splitting seems greater than the possible
    gain in rare cases.  */
 
-static int
-redundant_insn_p (insn, target, delay_list)
+static rtx
+redundant_insn (insn, target, delay_list)
      rtx insn;
      rtx target;
      rtx delay_list;
@@ -1949,6 +2069,7 @@ redundant_insn_p (insn, target, delay_list)
   /* Insns we pass may not set either NEEDED or SET, so merge them for
      simpler tests.  */
   needed.memory |= set.memory;
+  needed.unch_memory |= set.unch_memory;
   IOR_HARD_REG_SET (needed.regs, set.regs);
 
   /* This insn isn't redundant if it conflicts with an insn that either is
@@ -2015,7 +2136,7 @@ redundant_insn_p (insn, target, delay_list)
                {
                  /* Show that this insn will be used in the sequel.  */
                  INSN_FROM_TARGET_P (candidate) = 0;
-                 return 1;
+                 return candidate;
                }
 
              /* Unless this is an annulled insn from the target of a branch,
@@ -2037,7 +2158,7 @@ redundant_insn_p (insn, target, delay_list)
          /* See if TRIAL is the same as INSN.  */
          pat = PATTERN (trial);
          if (rtx_equal_p (pat, ipat))
-           return 1;
+           return trial;
 
          /* Can't go any further if TRIAL conflicts with INSN.  */
          if (insn_sets_resource_p (trial, &needed, 1))
@@ -2212,6 +2333,65 @@ update_reg_dead_notes (insn, delayed_insn)
          }
       }
 }
+
+/* Called when an insn redundant with start_insn is deleted.  If there
+   is a REG_DEAD note for the target of start_insn between start_insn
+   and stop_insn, then the REG_DEAD note needs to be deleted since the
+   value no longer dies there.
+
+   If the REG_DEAD note isn't deleted, then mark_target_live_regs may be
+   confused into thinking the register is dead.  */
+
+static void
+fix_reg_dead_note (start_insn, stop_insn)
+     rtx start_insn, stop_insn;
+{
+  rtx p, link, next;
+
+  for (p = next_nonnote_insn (start_insn); p != stop_insn;
+       p = next_nonnote_insn (p))
+    for (link = REG_NOTES (p); link; link = next)
+      {
+       next = XEXP (link, 1);
+
+       if (REG_NOTE_KIND (link) != REG_DEAD
+           || GET_CODE (XEXP (link, 0)) != REG)
+         continue;
+
+       if (reg_set_p (XEXP (link, 0), PATTERN (start_insn)))
+         {
+           remove_note (p, link);
+           return;
+         }
+      }
+}
+
+/* Delete any REG_UNUSED notes that exist on INSN but not on REDUNDANT_INSN.
+
+   This handles the case of udivmodXi4 instructions which optimize their
+   output depending on whether any REG_UNUSED notes are present.
+   we must make sure that INSN calculates as many results as REDUNDANT_INSN
+   does.  */
+
+static void
+update_reg_unused_notes (insn, redundant_insn)
+     rtx insn, redundant_insn;
+{
+  rtx p, link, next;
+
+  for (link = REG_NOTES (insn); link; link = next)
+    {
+      next = XEXP (link, 1);
+
+      if (REG_NOTE_KIND (link) != REG_UNUSED
+         || GET_CODE (XEXP (link, 0)) != REG)
+       continue;
+
+      if (! find_regno_note (redundant_insn, REG_UNUSED,
+                            REGNO (XEXP (link, 0))))
+       remove_note (insn, link);
+    }
+}
 \f
 /* Marks registers possibly live at the current place being scanned by
    mark_target_live_regs.  Used only by next two function.    */
@@ -2281,6 +2461,188 @@ next_insn_no_annul (insn)
   return insn;
 }
 \f
+/* A subroutine of mark_target_live_regs.  Search forward from TARGET
+   looking for registers that are set before they are used.  These are dead. 
+   Stop after passing a few conditional jumps, and/or a small
+   number of unconditional branches.  */
+
+static rtx
+find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
+     rtx target;
+     struct resources *res;
+     rtx *jump_target;
+     int jump_count;
+     struct resources set, needed;
+{
+  HARD_REG_SET scratch;
+  rtx insn, next;
+  rtx jump_insn = 0;
+  int i;
+
+  for (insn = target; insn; insn = next)
+    {
+      rtx this_jump_insn = insn;
+
+      next = NEXT_INSN (insn);
+      switch (GET_CODE (insn))
+       {
+       case CODE_LABEL:
+         /* After a label, any pending dead registers that weren't yet
+            used can be made dead.  */
+         AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
+         AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
+         CLEAR_HARD_REG_SET (pending_dead_regs);
+
+         if (CODE_LABEL_NUMBER (insn) < max_label_num_after_reload)
+           {
+             /* All spill registers are dead at a label, so kill all of the
+                ones that aren't needed also.  */
+             COPY_HARD_REG_SET (scratch, used_spill_regs);
+             AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+             AND_COMPL_HARD_REG_SET (res->regs, scratch);
+           }
+         continue;
+
+       case BARRIER:
+       case NOTE:
+         continue;
+
+       case INSN:
+         if (GET_CODE (PATTERN (insn)) == USE)
+           {
+             /* If INSN is a USE made by update_block, we care about the
+                underlying insn.  Any registers set by the underlying insn
+                are live since the insn is being done somewhere else.  */
+             if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
+               mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
+
+             /* All other USE insns are to be ignored.  */
+             continue;
+           }
+         else if (GET_CODE (PATTERN (insn)) == CLOBBER)
+           continue;
+         else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+           {
+             /* An unconditional jump can be used to fill the delay slot
+                of a call, so search for a JUMP_INSN in any position.  */
+             for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+               {
+                 this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
+                 if (GET_CODE (this_jump_insn) == JUMP_INSN)
+                   break;
+               }
+           }
+       }
+
+      if (GET_CODE (this_jump_insn) == JUMP_INSN)
+       {
+         if (jump_count++ < 10)
+           {
+             if (simplejump_p (this_jump_insn)
+                 || GET_CODE (PATTERN (this_jump_insn)) == RETURN)
+               {
+                 next = JUMP_LABEL (this_jump_insn);
+                 if (jump_insn == 0)
+                   {
+                     jump_insn = insn;
+                     if (jump_target)
+                       *jump_target = JUMP_LABEL (this_jump_insn);
+                   }
+               }
+             else if (condjump_p (this_jump_insn)
+                      || condjump_in_parallel_p (this_jump_insn))
+               {
+                 struct resources target_set, target_res;
+                 struct resources fallthrough_res;
+
+                 /* We can handle conditional branches here by following
+                    both paths, and then IOR the results of the two paths
+                    together, which will give us registers that are dead
+                    on both paths.  Since this is expensive, we give it
+                    a much higher cost than unconditional branches.  The
+                    cost was chosen so that we will follow at most 1
+                    conditional branch.  */
+
+                 jump_count += 4;
+                 if (jump_count >= 10)
+                   break;
+
+                 mark_referenced_resources (insn, &needed, 1);
+
+                 /* For an annulled branch, mark_set_resources ignores slots
+                    filled by instructions from the target.  This is correct
+                    if the branch is not taken.  Since we are following both
+                    paths from the branch, we must also compute correct info
+                    if the branch is taken.  We do this by inverting all of
+                    the INSN_FROM_TARGET_P bits, calling mark_set_resources,
+                    and then inverting the INSN_FROM_TARGET_P bits again.  */
+
+                 if (GET_CODE (PATTERN (insn)) == SEQUENCE
+                     && INSN_ANNULLED_BRANCH_P (this_jump_insn))
+                   {
+                     for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+                       INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+                         = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+                     target_set = set;
+                     mark_set_resources (insn, &target_set, 0, 1);
+
+                     for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+                       INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+                         = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+                     mark_set_resources (insn, &set, 0, 1);
+                   }
+                 else
+                   {
+                     mark_set_resources (insn, &set, 0, 1);
+                     target_set = set;
+                   }
+
+                 target_res = *res;
+                 COPY_HARD_REG_SET (scratch, target_set.regs);
+                 AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+                 AND_COMPL_HARD_REG_SET (target_res.regs, scratch);
+
+                 fallthrough_res = *res;
+                 COPY_HARD_REG_SET (scratch, set.regs);
+                 AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+                 AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch);
+
+                 find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
+                                             &target_res, 0, jump_count,
+                                             target_set, needed);
+                 find_dead_or_set_registers (next,
+                                             &fallthrough_res, 0, jump_count,
+                                             set, needed);
+                 IOR_HARD_REG_SET (fallthrough_res.regs, target_res.regs);
+                 AND_HARD_REG_SET (res->regs, fallthrough_res.regs);
+                 break;
+               }
+             else
+               break;
+           }
+         else
+           {
+             /* Don't try this optimization if we expired our jump count
+                above, since that would mean there may be an infinite loop
+                in the function being compiled.  */
+             jump_insn = 0;
+             break;
+           }
+       }
+
+      mark_referenced_resources (insn, &needed, 1);
+      mark_set_resources (insn, &set, 0, 1);
+
+      COPY_HARD_REG_SET (scratch, set.regs);
+      AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+      AND_COMPL_HARD_REG_SET (res->regs, scratch);
+    }
+
+  return jump_insn;
+}
+
 /* Set the resources that are live at TARGET.
 
    If TARGET is zero, we refer to the end of the current function and can
@@ -2343,7 +2705,7 @@ mark_target_live_regs (target, res)
 
   /* We have to assume memory is needed, but the CC isn't.  */
   res->memory = 1;
-  res->volatil = 0;
+  res->volatil = res->unch_memory = 0;
   res->cc = 0;
 
   /* See if we have computed this value already.  */
@@ -2551,92 +2913,18 @@ mark_target_live_regs (target, res)
        in use.  This should happen only extremely rarely.  */
     SET_HARD_REG_SET (res->regs);
 
-  /* Now step forward from TARGET looking for registers that are set before
-     they are used.  These are dead.  If we pass a label, any pending dead
-     registers that weren't yet used can be made dead.  Stop when we pass a
-     conditional JUMP_INSN; follow the first few unconditional branches.  */
-
   CLEAR_RESOURCE (&set);
   CLEAR_RESOURCE (&needed);
 
-  for (insn = target; insn; insn = next)
-    {
-      rtx this_jump_insn = insn;
-
-      next = NEXT_INSN (insn);
-      switch (GET_CODE (insn))
-       {
-       case CODE_LABEL:
-         AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
-         AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
-         CLEAR_HARD_REG_SET (pending_dead_regs);
-         continue;
-
-       case BARRIER:
-       case NOTE:
-         continue;
-
-       case INSN:
-         if (GET_CODE (PATTERN (insn)) == USE)
-           {
-             /* If INSN is a USE made by update_block, we care about the
-                underlying insn.  Any registers set by the underlying insn
-                are live since the insn is being done somewhere else.  */
-             if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
-               mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
-
-             /* All other USE insns are to be ignored.  */
-             continue;
-           }
-         else if (GET_CODE (PATTERN (insn)) == CLOBBER)
-           continue;
-         else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
-           {
-             /* An unconditional jump can be used to fill the delay slot
-                of a call, so search for a JUMP_INSN in any position.  */
-             for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
-               {
-                 this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
-                 if (GET_CODE (this_jump_insn) == JUMP_INSN)
-                   break;
-               }
-           }
-       }
-
-      if (GET_CODE (this_jump_insn) == JUMP_INSN)
-       {
-         if (jump_count++ < 10
-             && (simplejump_p (this_jump_insn)
-                 || GET_CODE (PATTERN (this_jump_insn)) == RETURN))
-           {
-             next = next_active_insn (JUMP_LABEL (this_jump_insn));
-             if (jump_insn == 0)
-               {
-                 jump_insn = insn;
-                 jump_target = JUMP_LABEL (this_jump_insn);
-               }
-           }
-         else
-           break;
-       }
-
-      mark_referenced_resources (insn, &needed, 1);
-      mark_set_resources (insn, &set, 0, 1);
-
-      COPY_HARD_REG_SET (scratch, set.regs);
-      AND_COMPL_HARD_REG_SET (scratch, needed.regs);
-      AND_COMPL_HARD_REG_SET (res->regs, scratch);
-    }
+  jump_insn = find_dead_or_set_registers (target, res, &jump_target, 0,
+                                         set, needed);
 
   /* If we hit an unconditional branch, we have another way of finding out
      what is live: we can see what is live at the branch target and include
      anything used but not set before the branch.  The only things that are
-     live are those that are live using the above test and the test below.
+     live are those that are live using the above test and the test below.  */
 
-     Don't try this if we expired our jump count above, since that would
-     mean there may be an infinite loop in the function being compiled.  */
-
-  if (jump_insn && jump_count < 10)
+  if (jump_insn)
     {
       struct resources new_resources;
       rtx stop_insn = next_active_insn (jump_insn);
@@ -2686,7 +2974,7 @@ fill_simple_delay_slots (first, non_jumps_p)
   register int i, j;
   int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
   struct resources needed, set;
-  register int slots_to_fill, slots_filled;
+  int slots_to_fill, slots_filled;
   rtx delay_list;
 
   for (i = 0; i < num_unfilled_slots; i++)
@@ -2739,12 +3027,24 @@ fill_simple_delay_slots (first, non_jumps_p)
          && eligible_for_delay (insn, slots_filled, trial, flags)
          && no_labels_between_p (insn, trial))
        {
+         rtx *tmp;
          slots_filled++;
          delay_list = add_to_delay_list (trial, delay_list);
+
+         /* TRIAL may have had its delay slot filled, then unfilled.  When
+            the delay slot is unfilled, TRIAL is placed back on the unfilled
+            slots obstack.  Unfortunately, it is placed on the end of the
+            obstack, not in its original location.  Therefore, we must search
+            from entry i + 1 to the end of the unfilled slots obstack to
+            try and find TRIAL.  */
+         tmp = &unfilled_slots_base[i + 1];
+         while (*tmp != trial && tmp != unfilled_slots_next)
+           tmp++;
+
          /* Remove the unconditional jump from consideration for delay slot
-            filling and unthread it.  */
-         if (unfilled_slots_base[i + 1] == trial)
-           unfilled_slots_base[i + 1] = 0;
+            filling and unthread it.   */
+         if (*tmp == trial)
+           *tmp = 0;
          {
            rtx next = NEXT_INSN (trial);
            rtx prev = PREV_INSN (trial);
@@ -2829,7 +3129,8 @@ fill_simple_delay_slots (first, non_jumps_p)
 #if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS)
       if (slots_filled != slots_to_fill
          && delay_list == 0
-         && GET_CODE (insn) == JUMP_INSN && condjump_p (insn))
+         && GET_CODE (insn) == JUMP_INSN 
+         && (condjump_p (insn) || condjump_in_parallel_p (insn)))
        {
          delay_list = optimize_skip (insn);
          if (delay_list)
@@ -2843,24 +3144,21 @@ fill_simple_delay_slots (first, non_jumps_p)
         is a CALL_INSN (or a CALL_INSN is passed), cannot trap (because the
         call might not return).
 
-        If this is a conditional jump, see if it merges back to us early
-        enough for us to pick up insns from the merge point.  Don't do
-        this if there is another branch to our label unless we pass all of
-        them.
-
-        Another similar merge is if we jump to the same place that a
-        later unconditional jump branches to.  In that case, we don't
-        care about the number of uses of our label.  */
+        There used to be code which continued past the target label if
+        we saw all uses of the target label.  This code did not work,
+        because it failed to account for some instructions which were
+        both annulled and marked as from the target.  This can happen as a
+        result of optimize_skip.  Since this code was redundant with
+        fill_eager_delay_slots anyways, it was just deleted.  */
 
       if (slots_filled != slots_to_fill
           && (GET_CODE (insn) != JUMP_INSN
-             || (condjump_p (insn) && ! simplejump_p (insn)
+             || ((condjump_p (insn) || condjump_in_parallel_p (insn))
+                  && ! simplejump_p (insn)
                   && JUMP_LABEL (insn) != 0)))
        {
          rtx target = 0;
          int maybe_never = 0;
-         int passed_label = 0;
-         int target_uses;
          struct resources needed_at_jump;
 
          CLEAR_RESOURCE (&needed);
@@ -2877,13 +3175,7 @@ fill_simple_delay_slots (first, non_jumps_p)
              mark_set_resources (insn, &set, 0, 1);
              mark_referenced_resources (insn, &needed, 1);
              if (GET_CODE (insn) == JUMP_INSN)
-               {
-                 /* Get our target and show how many more uses we want to
-                    see before we hit the label.  */
-                 target = JUMP_LABEL (insn);
-                 target_uses = LABEL_NUSES (target) - 1;
-               }
-               
+               target = JUMP_LABEL (insn);
            }
 
          for (trial = next_nonnote_insn (insn); trial; trial = next_trial)
@@ -2892,22 +3184,8 @@ fill_simple_delay_slots (first, non_jumps_p)
 
              next_trial = next_nonnote_insn (trial);
 
-             if (GET_CODE (trial) == CODE_LABEL)
-               {
-                 passed_label = 1;
-
-                 /* If this is our target, see if we have seen all its uses.
-                    If so, indicate we have passed our target and ignore it.
-                    All other labels cause us to stop our search.  */
-                 if (trial == target && target_uses == 0)
-                   {
-                     target = 0;
-                     continue;
-                   }
-                 else
-                   break;
-               }
-             else if (GET_CODE (trial) == BARRIER)
+             if (GET_CODE (trial) == CODE_LABEL
+                 || GET_CODE (trial) == BARRIER)
                break;
 
              /* We must have an INSN, JUMP_INSN, or CALL_INSN.  */
@@ -2932,14 +3210,13 @@ fill_simple_delay_slots (first, non_jumps_p)
                {
                  if (target == 0)
                    break;
-                 else if (JUMP_LABEL (trial_delay) == target)
-                   target_uses--;
-                 else
+                 else if (JUMP_LABEL (trial_delay) != target)
                    {
                      mark_target_live_regs
                        (next_active_insn (JUMP_LABEL (trial_delay)),
                         &needed_at_jump);
                      needed.memory |= needed_at_jump.memory;
+                     needed.unch_memory |= needed_at_jump.unch_memory;
                      IOR_HARD_REG_SET (needed.regs, needed_at_jump.regs);
                    }
                }
@@ -2966,8 +3243,6 @@ fill_simple_delay_slots (first, non_jumps_p)
                    link_cc0_insns (trial);
 #endif
 
-                 if (passed_label)
-                   update_block (trial, trial);
                  delete_insn (trial);
                  if (slots_to_fill == ++slots_filled)
                    break;
@@ -2983,14 +3258,16 @@ fill_simple_delay_slots (first, non_jumps_p)
              set.cc = 1;
 
              /* If this is a call or jump, we might not get here.  */
-             if (GET_CODE (trial) == CALL_INSN
-                 || GET_CODE (trial) == JUMP_INSN)
+             if (GET_CODE (trial_delay) == CALL_INSN
+                 || GET_CODE (trial_delay) == JUMP_INSN)
                maybe_never = 1;
            }
 
          /* If there are slots left to fill and our search was stopped by an
             unconditional branch, try the insn at the branch target.  We can
-            redirect the branch if it works.  */
+            redirect the branch if it works. 
+
+            Don't do this if the insn at the branch target is a branch.  */
          if (slots_to_fill != slots_filled
              && trial
              && GET_CODE (trial) == JUMP_INSN
@@ -2999,6 +3276,7 @@ fill_simple_delay_slots (first, non_jumps_p)
              && (next_trial = next_active_insn (JUMP_LABEL (trial))) != 0
              && ! (GET_CODE (next_trial) == INSN
                    && GET_CODE (PATTERN (next_trial)) == SEQUENCE)
+             && GET_CODE (next_trial) != JUMP_INSN
              && ! insn_references_resource_p (next_trial, &set, 1)
              && ! insn_sets_resource_p (next_trial, &set, 1)
              && ! insn_sets_resource_p (next_trial, &needed, 1)
@@ -3028,6 +3306,19 @@ fill_simple_delay_slots (first, non_jumps_p)
            }
        }
 
+      /* If this is an unconditional jump, then try to get insns from the
+        target of the jump.  */
+      if (GET_CODE (insn) == JUMP_INSN
+         && simplejump_p (insn)
+         && slots_filled != slots_to_fill)
+       delay_list
+         = fill_slots_from_thread (insn, const_true_rtx,
+                                   next_active_insn (JUMP_LABEL (insn)),
+                                   NULL, 1, 1,
+                                   own_thread_p (JUMP_LABEL (insn),
+                                                 JUMP_LABEL (insn), 0),
+                                   0, slots_to_fill, &slots_filled);
+
       if (delay_list)
        unfilled_slots_base[i]
          = emit_delay_sequence (insn, delay_list,
@@ -3052,9 +3343,35 @@ fill_simple_delay_slots (first, non_jumps_p)
     return;
 
   slots_filled = 0;
-  needed = end_of_function_needs;
   CLEAR_RESOURCE (&set);
 
+  /* The frame pointer and stack pointer are needed at the beginning of
+     the epilogue, so instructions setting them can not be put in the
+     epilogue delay slot.  However, everything else needed at function
+     end is safe, so we don't want to use end_of_function_needs here.  */
+  CLEAR_RESOURCE (&needed);
+  if (frame_pointer_needed)
+    {
+      SET_HARD_REG_BIT (needed.regs, FRAME_POINTER_REGNUM);
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+      SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
+#endif
+#ifdef EXIT_IGNORE_STACK
+      if (! EXIT_IGNORE_STACK)
+#endif
+       SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
+    }
+  else
+    SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
+
+#ifdef EPILOGUE_USES
+  for (i = 0; i <FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (EPILOGUE_USES (i))
+       SET_HARD_REG_BIT (needed.regs, i);
+    }
+#endif
+
   for (trial = get_last_insn (); ! stop_search_p (trial, 1);
        trial = PREV_INSN (trial))
     {
@@ -3066,6 +3383,7 @@ fill_simple_delay_slots (first, non_jumps_p)
 
       if (! insn_references_resource_p (trial, &set, 1)
          && ! insn_sets_resource_p (trial, &needed, 1)
+         && ! insn_sets_resource_p (trial, &set, 1)
 #ifdef HAVE_cc0
          /* Don't want to mess with cc0 here.  */
          && ! reg_mentioned_p (cc0_rtx, pat)
@@ -3213,18 +3531,31 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 #endif
          )
        {
+         rtx prior_insn;
+
          /* If TRIAL is redundant with some insn before INSN, we don't
             actually need to add it to the delay list; we can merely pretend
             we did.  */
-         if (redundant_insn_p (trial, insn, delay_list))
+         if (prior_insn = redundant_insn (trial, insn, delay_list))
            {
+             fix_reg_dead_note (prior_insn, insn);
              if (own_thread)
                {
                  update_block (trial, thread);
+                 if (trial == thread)
+                   {
+                     thread = next_active_insn (thread);
+                     if (new_thread == trial)
+                       new_thread = thread;
+                   }
+
                  delete_insn (trial);
                }
              else
-               new_thread = next_active_insn (trial);
+               {
+                 update_reg_unused_notes (prior_insn, trial);
+                 new_thread = next_active_insn (trial);
+               }
 
              continue;
            }
@@ -3240,6 +3571,8 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              trial = try_split (pat, trial, 0);
              if (new_thread == old_trial)
                new_thread = trial;
+             if (thread == old_trial)
+               thread = trial;
              pat = PATTERN (trial);
              if (eligible_for_delay (insn, *pslots_filled, trial, flags))
                goto winner;
@@ -3257,6 +3590,8 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              trial = try_split (pat, trial, 0);
              if (new_thread == old_trial)
                new_thread = trial;
+             if (thread == old_trial)
+               thread = trial;
              pat = PATTERN (trial);
              if ((thread_if_true
                   ? eligible_for_annul_false (insn, *pslots_filled, trial, flags)
@@ -3279,6 +3614,12 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
                  if (own_thread)
                    {
                      update_block (trial, thread);
+                     if (trial == thread)
+                       {
+                         thread = next_active_insn (thread);
+                         if (new_thread == trial)
+                           new_thread = thread;
+                       }
                      delete_insn (trial);
                    }
                  else
@@ -3300,8 +3641,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
                             && ! insn_sets_resource_p (new_thread, &needed, 1)
                             && ! insn_references_resource_p (new_thread,
                                                              &set, 1)
-                            && redundant_insn_p (new_thread, insn,
-                                                 delay_list))
+                            && redundant_insn (new_thread, insn, delay_list))
                        new_thread = next_active_insn (new_thread);
                      break;
                    }
@@ -3382,7 +3722,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
      depend on the destination register.  If so, try to place the opposite
      arithmetic insn after the jump insn and put the arithmetic insn in the
      delay slot.  If we can't do this, return.  */
-  if (delay_list == 0 && likely && new_thread && GET_CODE (new_thread) == INSN)
+  if (delay_list == 0 && likely && new_thread
+      && GET_CODE (new_thread) == INSN
+      && GET_CODE (PATTERN (new_thread)) != ASM_INPUT
+      && asm_noperands (PATTERN (new_thread)) < 0)
     {
       rtx pat = PATTERN (new_thread);
       rtx dest;
@@ -3428,6 +3771,12 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          if (own_thread)
            {
              update_block (trial, thread);
+             if (trial == thread)
+               {
+                 thread = next_active_insn (thread);
+                 if (new_thread == trial)
+                   new_thread = thread;
+               }
              delete_insn (trial);
            }
          else
@@ -3457,7 +3806,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 
       if (new_thread && GET_CODE (new_thread) == JUMP_INSN
          && (simplejump_p (new_thread)
-             || GET_CODE (PATTERN (new_thread)) == RETURN))
+             || GET_CODE (PATTERN (new_thread)) == RETURN)
+         && redirect_with_delay_list_safe_p (insn,
+                                             JUMP_LABEL (new_thread),
+                                             delay_list))
        new_thread = follow_jumps (JUMP_LABEL (new_thread));
 
       if (new_thread == 0)
@@ -3504,7 +3856,7 @@ fill_eager_delay_slots (first)
       if (insn == 0
          || INSN_DELETED_P (insn)
          || GET_CODE (insn) != JUMP_INSN
-         || ! condjump_p (insn))
+         || ! (condjump_p (insn) || condjump_in_parallel_p (insn)))
        continue;
 
       slots_to_fill = num_delay_slots (insn);
@@ -3518,7 +3870,7 @@ fill_eager_delay_slots (first)
       if (condition == 0)
        continue;
 
-      /* Get the next active fallthough and target insns and see if we own
+      /* Get the next active fallthrough and target insns and see if we own
         them.  Then see whether the branch is likely true.  We don't need
         to do a lot of this for unconditional branches.  */
 
@@ -3617,7 +3969,7 @@ relax_delay_slots (first)
         the next insn, or jumps to a label that is not the last of a
         group of consecutive labels.  */
       if (GET_CODE (insn) == JUMP_INSN
-         && condjump_p (insn)
+         && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && (target_label = JUMP_LABEL (insn)) != 0)
        {
          target_label = follow_jumps (target_label);
@@ -3626,7 +3978,8 @@ relax_delay_slots (first)
          if (target_label == 0)
            target_label = find_end_label ();
 
-         if (next_active_insn (target_label) == next)
+         if (next_active_insn (target_label) == next
+             && ! condjump_in_parallel_p (insn))
            {
              delete_jump (insn);
              continue;
@@ -3683,7 +4036,7 @@ relax_delay_slots (first)
       if (GET_CODE (insn) == JUMP_INSN
          && (simplejump_p (insn) || GET_CODE (PATTERN (insn)) == RETURN)
          && (other = prev_active_insn (insn)) != 0
-         && condjump_p (other)
+         && (condjump_p (other) || condjump_in_parallel_p (other))
          && no_labels_between_p (other, insn)
          && 0 < mostly_true_jump (other,
                                   get_branch_condition (other,
@@ -3715,7 +4068,7 @@ relax_delay_slots (first)
       /* See if the first insn in the delay slot is redundant with some
         previous insn.  Remove it from the delay slot if so; then set up
         to reprocess this insn.  */
-      if (redundant_insn_p (XVECEXP (pat, 0, 1), delay_insn, 0))
+      if (redundant_insn (XVECEXP (pat, 0, 1), delay_insn, 0))
        {
          delete_from_delay_slot (XVECEXP (pat, 0, 1));
          next = prev_active_insn (next);
@@ -3724,7 +4077,8 @@ relax_delay_slots (first)
 
       /* Now look only at the cases where we have a filled JUMP_INSN.  */
       if (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN
-         || ! condjump_p (XVECEXP (PATTERN (insn), 0, 0)))
+         || ! (condjump_p (XVECEXP (PATTERN (insn), 0, 0))
+               || condjump_in_parallel_p (XVECEXP (PATTERN (insn), 0, 0))))
        continue;
 
       target_label = JUMP_LABEL (delay_insn);
@@ -3734,7 +4088,12 @@ relax_delay_slots (first)
          /* If this jump goes to another unconditional jump, thread it, but
             don't convert a jump into a RETURN here.  */
          trial = follow_jumps (target_label);
-         trial = prev_label (next_active_insn (trial));
+         /* We use next_real_insn instead of next_active_insn, so that
+            the special USE insns emitted by reorg won't be ignored.
+            If they are ignored, then they will get deleted if target_label
+            is now unreachable, and that would cause mark_target_live_regs
+            to fail.  */
+         trial = prev_label (next_real_insn (trial));
          if (trial == 0 && target_label != 0)
            trial = find_end_label ();
 
@@ -3749,13 +4108,22 @@ relax_delay_slots (first)
             insn, redirect the jump to the following insn process again.  */
          trial = next_active_insn (target_label);
          if (trial && GET_CODE (PATTERN (trial)) != SEQUENCE
-             && redundant_insn_p (trial, insn, 0))
+             && redundant_insn (trial, insn, 0))
            {
-             trial = next_active_insn (trial);
-             if (trial == 0)
-               target_label = find_end_label ();
-             else
-               target_label = get_label_before (trial);
+             rtx tmp;
+
+             /* Figure out where to emit the special USE insn so we don't
+                later incorrectly compute register live/death info.  */
+             tmp = next_active_insn (trial);
+             if (tmp == 0)
+               tmp = find_end_label ();
+
+             /* Insert the special USE insn and update dataflow info.  */
+              update_block (trial, tmp);
+
+             /* Now emit a label before the special USE insn, and
+                redirect our jump to the new label.  */ 
+             target_label = get_label_before (PREV_INSN (tmp));
              reorg_redirect_jump (delay_insn, target_label);
              next = insn;
              continue;
@@ -3768,7 +4136,7 @@ relax_delay_slots (first)
              && GET_CODE (XVECEXP (PATTERN (trial), 0, 0)) == JUMP_INSN
              && (simplejump_p (XVECEXP (PATTERN (trial), 0, 0))
                  || GET_CODE (PATTERN (XVECEXP (PATTERN (trial), 0, 0))) == RETURN)
-             && redundant_insn_p (XVECEXP (PATTERN (trial), 0, 1), insn, 0))
+             && redundant_insn (XVECEXP (PATTERN (trial), 0, 1), insn, 0))
            {
              target_label = JUMP_LABEL (XVECEXP (PATTERN (trial), 0, 0));
              if (target_label == 0)
@@ -3786,6 +4154,7 @@ relax_delay_slots (first)
 
       if (! INSN_ANNULLED_BRANCH_P (delay_insn)
          && prev_active_insn (target_label) == insn
+         && ! condjump_in_parallel_p (delay_insn)
 #ifdef HAVE_cc0
          /* If the last insn in the delay slot sets CC0 for some insn,
             various code assumes that it is in a delay slot.  We could
@@ -3859,6 +4228,17 @@ relax_delay_slots (first)
 
              if (invert_jump (delay_insn, label))
                {
+                 int i;
+
+                 /* Must update the INSN_FROM_TARGET_P bits now that
+                    the branch is reversed, so that mark_target_live_regs
+                    will handle the delay slot insn correctly.  */
+                 for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+                   {
+                     rtx slot = XVECEXP (PATTERN (insn), 0, i);
+                     INSN_FROM_TARGET_P (slot) = ! INSN_FROM_TARGET_P (slot);
+                   }
+
                  delete_insn (next);
                  next = insn;
                }
@@ -3930,11 +4310,16 @@ make_return_insns (first)
       pat = PATTERN (insn);
       jump_insn = XVECEXP (pat, 0, 0);
 
-      /* If we can't make the jump into a RETURN, redirect it to the best
+      /* If we can't make the jump into a RETURN, try to redirect it to the best
         RETURN and go on to the next insn.  */
       if (! reorg_redirect_jump (jump_insn, NULL_RTX))
        {
-         reorg_redirect_jump (jump_insn, real_return_label);
+         /* Make sure redirecting the jump will not invalidate the delay
+            slot insns.  */
+         if (redirect_with_delay_slots_safe_p (jump_insn,
+                                               real_return_label,
+                                               insn))
+           reorg_redirect_jump (jump_insn, real_return_label);
          continue;
        }
 
@@ -4068,7 +4453,8 @@ dbr_schedule (first, file)
        obstack_ptr_grow (&unfilled_slots_obstack, insn);
 
       /* Ensure all jumps go to the last of a set of consecutive labels.  */
-      if (GET_CODE (insn) == JUMP_INSN && condjump_p (insn)
+      if (GET_CODE (insn) == JUMP_INSN 
+         && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && JUMP_LABEL (insn) != 0
          && ((target = prev_label (next_active_insn (JUMP_LABEL (insn))))
              != JUMP_LABEL (insn)))
@@ -4084,6 +4470,7 @@ dbr_schedule (first, file)
 
   end_of_function_needs.cc = 0;
   end_of_function_needs.memory = 1;
+  end_of_function_needs.unch_memory = 0;
   CLEAR_HARD_REG_SET (end_of_function_needs.regs);
 
   if (frame_pointer_needed)
@@ -4106,7 +4493,11 @@ dbr_schedule (first, file)
                               &end_of_function_needs, 1);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (global_regs[i])
+    if (global_regs[i]
+#ifdef EPILOGUE_USES
+       || EPILOGUE_USES (i)
+#endif
+       )
       SET_HARD_REG_BIT (end_of_function_needs.regs, i);
 
   /* The registers required to be live at the end of the function are
@@ -4138,14 +4529,15 @@ dbr_schedule (first, file)
   target_hash_table
     = (struct target_info **) alloca ((TARGET_HASH_PRIME
                                       * sizeof (struct target_info *)));
-  bzero (target_hash_table, TARGET_HASH_PRIME * sizeof (struct target_info *));
+  bzero ((char *) target_hash_table,
+        TARGET_HASH_PRIME * sizeof (struct target_info *));
 
   bb_ticks = (int *) alloca (n_basic_blocks * sizeof (int));
-  bzero (bb_ticks, n_basic_blocks * sizeof (int));
+  bzero ((char *) bb_ticks, n_basic_blocks * sizeof (int));
 
   /* Initialize the statistics for this function.  */
-  bzero (num_insns_needing_delays, sizeof num_insns_needing_delays);
-  bzero (num_filled_delays, sizeof num_filled_delays);
+  bzero ((char *) num_insns_needing_delays, sizeof num_insns_needing_delays);
+  bzero ((char *) num_filled_delays, sizeof num_filled_delays);
 
   /* Now do the delay slot filling.  Try everything twice in case earlier
      changes make more slots fillable.  */