OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 3b6b205..375d4f8 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
-   Contributed by Richard Kenner (kenner@nyu.edu).
+   Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
 This file is part of GNU CC.
@@ -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.
 
@@ -60,6 +61,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    we can hoist insns from the fall-through path for forward branches or
    steal insns from the target of backward branches.
 
+   The TMS320C3x and C4x have three branch delay slots.  When the three
+   slots are filled, the branch penalty is zero.  Most insns can fill the
+   delay slots except jump insns.
+
    Three techniques for filling delay slots have been implemented so far:
 
    (1) `fill_simple_delay_slots' is the simplest, most efficient way
@@ -114,9 +119,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    The HP-PA can conditionally nullify insns, providing a similar
    effect to the ARM, differing mostly in which insn is "in charge".   */
 
-#include <stdio.h>
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
+#include "expr.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "hard-reg-set.h"
@@ -129,6 +135,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "insn-attr.h"
 
+
 #ifdef DELAY_SLOTS
 
 #define obstack_chunk_alloc xmalloc
@@ -162,14 +169,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.  */
@@ -220,11 +228,11 @@ static int stop_search_p  PROTO((rtx, int));
 static int resource_conflicts_p        PROTO((struct resources *,
                                       struct resources *));
 static int insn_references_resource_p PROTO((rtx, struct resources *, int));
-static int insn_sets_resources_p PROTO((rtx, struct resources *, int));
+static int insn_sets_resource_p PROTO((rtx, struct resources *, int));
 static rtx find_end_label      PROTO((void));
-static rtx emit_delay_sequence PROTO((rtx, rtx, int, int));
+static rtx emit_delay_sequence PROTO((rtx, rtx, int));
 static rtx add_to_delay_list   PROTO((rtx, rtx));
-static void delete_from_delay_slot PROTO((rtx));
+static rtx delete_from_delay_slot PROTO((rtx));
 static void delete_scheduled_jump PROTO((rtx));
 static void note_delay_statistics PROTO((int, int));
 static rtx optimize_skip       PROTO((rtx));
@@ -244,24 +252,31 @@ 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 rtx find_dead_or_set_registers PROTO ((rtx, struct resources *, rtx *,
+                                             int, struct resources,
+                                             struct resources));
 static void mark_target_live_regs PROTO((rtx, struct resources *));
-static void fill_simple_delay_slots PROTO((rtx, int));
+static void fill_simple_delay_slots PROTO((int));
 static rtx fill_slots_from_thread PROTO((rtx, rtx, rtx, rtx, int, int,
-                                        int, int, int, int *));
-static void fill_eager_delay_slots PROTO((rtx));
+                                        int, int, int *, rtx));
+static void fill_eager_delay_slots PROTO((void));
 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
+   which resources are references by the insn.  If INCLUDE_DELAYED_EFFECTS
    is TRUE, resources used by the called routine will be included for
    CALL_INSNs.  */
 
@@ -307,7 +322,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);
 
@@ -325,6 +342,10 @@ mark_referenced_resources (x, res, include_delayed_effects)
       res->volatil = 1;
       return;
 
+    case TRAP_IF:
+      res->volatil = 1;
+      break;
+
     case ASM_OPERANDS:
       res->volatil = MEM_VOLATILE_P (x);
 
@@ -376,11 +397,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)
@@ -390,34 +413,53 @@ mark_referenced_resources (x, res, include_delayed_effects)
          res->memory = 1;
          SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM);
          if (frame_pointer_needed)
-           SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);
+           {
+             SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+             SET_HARD_REG_BIT (res->regs, HARD_FRAME_POINTER_REGNUM);
+#endif
+           }
 
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
            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:
@@ -431,6 +473,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
       /* No special processing, just speed up.  */
       mark_referenced_resources (PATTERN (x), res, include_delayed_effects);
       return;
+
+    default:
+      break;
     }
 
   /* Process each sub-expression and flag what it needs.  */
@@ -450,9 +495,10 @@ mark_referenced_resources (x, res, include_delayed_effects)
       }
 }
 \f
-/* Given X, a part of an insn, and a pointer to a `struct resource', RES,
-   indicate which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE
-   is nonzero, also mark resources potentially set by the called routine.
+/* Given X, a part of an insn, and a pointer to a `struct resource',
+   RES, indicate which resources are modified by the insn. If
+   INCLUDE_DELAYED_EFFECTS is nonzero, also mark resources potentially
+   set by the called routine.
 
    If IN_DEST is nonzero, it means we are inside a SET.  Otherwise,
    objects are being referenced instead of set.
@@ -506,23 +552,32 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
       if (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++)
            if (call_used_regs[i] || global_regs[i])
              SET_HARD_REG_BIT (res->regs, i);
 
-         /* 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);
+         /* If X is part of a delay slot sequence, then NEXT should be
+            the first insn after the sequence.  */
+         if (NEXT_INSN (prev) != x)
+           next = NEXT_INSN (NEXT_INSN (prev));
+
+         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.  */
+         if (next && GET_CODE (next) == NOTE
+             && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP)
+           SET_HARD_REG_SET (res->regs);
        }
 
-      /* ... and also what it's RTL says it modifies, if anything.  */
+      /* ... and also what its RTL says it modifies, if anything.  */
 
     case JUMP_INSN:
     case INSN:
@@ -583,17 +638,37 @@ 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++)
          SET_HARD_REG_BIT (res->regs, REGNO (x) + i);
       return;
+
+    default:
+      break;
     }
 
   /* Process each sub-expression and flag what it needs.  */
@@ -658,6 +733,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;
 
@@ -676,7 +752,7 @@ resource_conflicts_p (res1, res2)
 }
 
 /* Return TRUE if any resource marked in RES, a `struct resources', is
-   referenced by INSN.  If INCLUDE_CALLED_ROUTINE is set, return if the called
+   referenced by INSN.  If INCLUDE_DELAYED_EFFECTS is set, return if the called
    routine is using those resources.
 
    We compute this by computing all the resources referenced by INSN and
@@ -698,7 +774,7 @@ insn_references_resource_p (insn, res, include_delayed_effects)
 }
 
 /* Return TRUE if INSN modifies resources that are marked in RES.
-   INCLUDE_CALLED_ROUTINE is set if the actions of that routine should be
+   INCLUDE_DELAYED_EFFECTS is set if the actions of that routine should be
    included.   CC0 is only modified if it is explicitly set; see comments
    in front of mark_set_resources for details.  */
 
@@ -738,8 +814,26 @@ find_end_label ()
                 || GET_CODE (PATTERN (insn)) == CLOBBER)))
     insn = PREV_INSN (insn);
 
-  if (GET_CODE (insn) == CODE_LABEL)
-   end_of_function_label = insn;
+  /* When a target threads its epilogue we might already have a 
+     suitable return insn.  If so put a label before it for the
+     end_of_function_label.  */
+  if (GET_CODE (insn) == BARRIER
+      && GET_CODE (PREV_INSN (insn)) == JUMP_INSN
+      && GET_CODE (PATTERN (PREV_INSN (insn))) == RETURN)
+    {
+      rtx temp = PREV_INSN (PREV_INSN (insn));
+      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.  */
+      while (GET_CODE (temp) == USE)
+       temp = PREV_INSN (temp);
+
+      emit_label_after (end_of_function_label, temp);
+    }
+
+  else if (GET_CODE (insn) == CODE_LABEL)
+    end_of_function_label = insn;
   else
     {
       /* Otherwise, make a new label and emit a RETURN and BARRIER,
@@ -778,24 +872,23 @@ find_end_label ()
    Returns the SEQUENCE that replaces INSN.  */
 
 static rtx
-emit_delay_sequence (insn, list, length, avail)
+emit_delay_sequence (insn, list, length)
      rtx insn;
      rtx list;
      int length;
-     int avail;
 {
   register int i = 1;
   register rtx li;
   int had_barrier = 0;
 
-  /* Allocate the the rtvec to hold the insns and the SEQUENCE. */
+  /* Allocate the rtvec to hold the insns and the SEQUENCE.  */
   rtvec seqv = rtvec_alloc (length + 1);
-  rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);
+  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
@@ -812,15 +905,22 @@ emit_delay_sequence (insn, list, length, avail)
   NEXT_INSN (seq_insn) = NEXT_INSN (insn);
   PREV_INSN (seq_insn) = PREV_INSN (insn);
 
+  if (insn != last)
+    PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;
+
+  if (insn != first)
+    NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;
+
+  /* Note the calls to set_new_first_and_last_insn must occur after
+     SEQ_INSN has been completely spliced into the insn stream.
+
+     Otherwise CUR_INSN_UID will get set to an incorrect value because
+     set_new_first_and_last_insn will not find SEQ_INSN in the chain.  */
   if (insn == last)
     set_new_first_and_last_insn (first, seq_insn);
-  else
-    PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;
 
   if (insn == first)
     set_new_first_and_last_insn (seq_insn, last);
-  else
-    NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;
 
   /* Build our SEQUENCE and rebuild the insn chain.  */
   XVECEXP (seq, 0, 0) = delay_insn;
@@ -881,7 +981,7 @@ add_to_delay_list (insn, delay_list)
      rtx delay_list;
 {
   /* If we have an empty list, just make a new list element.  If
-     INSN has it's block number recorded, clear it since we may
+     INSN has its block number recorded, clear it since we may
      be moving the insn to a new block.  */
 
   if (delay_list == 0)
@@ -896,7 +996,7 @@ add_to_delay_list (insn, delay_list)
       if (tinfo)
        tinfo->block = -1;
 
-      return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+      return gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
     }
 
   /* Otherwise this must be an INSN_LIST.  Add INSN to the end of the
@@ -906,10 +1006,10 @@ add_to_delay_list (insn, delay_list)
   return delay_list;
 }   
 \f
-/* Delete INSN from the the delay slot of the insn that it is in.  This may
+/* Delete INSN from the delay slot of the insn that it is in.  This may
    produce an insn without anything in its delay slots.  */
 
-static void
+static rtx
 delete_from_delay_slot (insn)
      rtx insn;
 {
@@ -950,7 +1050,7 @@ delete_from_delay_slot (insn)
   /* If there are any delay insns, remit them.  Otherwise clear the
      annul flag.  */
   if (delay_list)
-    trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2, 0);
+    trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2);
   else
     INSN_ANNULLED_BRANCH_P (trial) = 0;
 
@@ -958,6 +1058,8 @@ delete_from_delay_slot (insn)
 
   /* Show we need to fill this insn again.  */
   obstack_ptr_grow (&unfilled_slots_obstack, trial);
+
+  return trial;
 }
 \f
 /* Delete INSN, a JUMP_INSN.  If it is a conditional jump, we must track down
@@ -1122,7 +1224,14 @@ optimize_skip (insn)
          target_label = JUMP_LABEL (next_trial);
          if (target_label == 0)
            target_label = find_end_label ();
-         reorg_redirect_jump (insn, target_label);
+
+         /* Recompute the flags based on TARGET_LABEL since threading
+            the jump to TARGET_LABEL may change the direction of the
+            jump (which may change the circumstances in which the
+            delay slot is nullified).  */
+         flags = get_jump_flags (insn, target_label);
+         if (eligible_for_annul_true (insn, 0, trial, flags))
+           reorg_redirect_jump (insn, target_label);
        }
 
       INSN_ANNULLED_BRANCH_P (insn) = 1;
@@ -1138,6 +1247,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;
@@ -1151,7 +1261,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)
@@ -1167,7 +1277,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;
 
@@ -1197,7 +1307,7 @@ get_jump_flags (insn, label)
   return flags;
 }
 
-/* Return 1 if DEST is a destination that will be branched to rarely (the
+/* Return 1 if INSN is a destination that will be branched to rarely (the
    return point of a function); return 2 if DEST will be branched to very
    rarely (a call to a function that doesn't return).  Otherwise,
    return 0.  */
@@ -1207,12 +1317,15 @@ rare_destination (insn)
      rtx insn;
 {
   int jump_count = 0;
+  rtx next;
 
-  for (; insn; insn = NEXT_INSN (insn))
+  for (; insn; insn = next)
     {
       if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
        insn = XVECEXP (PATTERN (insn), 0, 0);
 
+      next = NEXT_INSN (insn);
+
       switch (GET_CODE (insn))
        {
        case CODE_LABEL:
@@ -1228,9 +1341,12 @@ rare_destination (insn)
            return 1;
          else if (simplejump_p (insn)
                   && jump_count++ < 10)
-           insn = JUMP_LABEL (insn);
+           next = JUMP_LABEL (insn);
          else
            return 0;
+
+       default:
+         break;
        }
     }
 
@@ -1257,6 +1373,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
@@ -1289,8 +1425,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)
     {
@@ -1333,6 +1469,9 @@ mostly_true_jump (jump_insn, condition)
       if (XEXP (condition, 1) == const0_rtx)
        return 1;
       break;
+
+    default:
+      break;
     }
 
   /* Predict backward branches usually take, forward branches usually not.  If
@@ -1357,6 +1496,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;
 
@@ -1379,9 +1521,9 @@ get_branch_condition (insn, target)
               || (GET_CODE (XEXP (src, 2)) == LABEL_REF
                   && XEXP (XEXP (src, 2), 0) == target))
           && XEXP (src, 1) == pc_rtx)
-    return gen_rtx (reverse_condition (GET_CODE (XEXP (src, 0))),
-                   GET_MODE (XEXP (src, 0)),
-                   XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
+    return gen_rtx_fmt_ee (reverse_condition (GET_CODE (XEXP (src, 0))),
+                          GET_MODE (XEXP (src, 0)),
+                          XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
 
   return 0;
 }
@@ -1413,6 +1555,100 @@ condition_dominates_p (condition, insn)
 
   return comparison_dominates_p (code, other_code);
 }
+
+/* Return non-zero if redirecting JUMP to NEWLABEL does not invalidate
+   any insns already in the delay slot of JUMP.  */
+
+static int
+redirect_with_delay_slots_safe_p (jump, newlabel, seq)
+     rtx jump, newlabel, seq;
+{
+  int flags, i;
+  rtx pat = PATTERN (seq);
+
+  /* Make sure all the delay slots of this jump would still
+     be valid after threading the jump.  If they are still
+     valid, then return non-zero.  */
+
+  flags = get_jump_flags (jump, newlabel);
+  for (i = 1; i < XVECLEN (pat, 0); i++)
+    if (! (
+#ifdef ANNUL_IFFALSE_SLOTS
+          (INSN_ANNULLED_BRANCH_P (jump)
+           && INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)))
+          ? eligible_for_annul_false (jump, i - 1,
+                                      XVECEXP (pat, 0, i), flags) :
+#endif
+#ifdef ANNUL_IFTRUE_SLOTS
+          (INSN_ANNULLED_BRANCH_P (jump)
+           && ! INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)))
+          ? eligible_for_annul_true (jump, i - 1,
+                                     XVECEXP (pat, 0, i), flags) :
+#endif
+          eligible_for_delay (jump, i -1, XVECEXP (pat, 0, i), flags)))
+      break;
+
+  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);
+}
+
+/* DELAY_LIST is a list of insns that have already been placed into delay
+   slots.  See if all of them have the same annulling status as ANNUL_TRUE_P.
+   If not, return 0; otherwise return 1.  */
+
+static int
+check_annul_list_true_false (annul_true_p, delay_list)
+     int annul_true_p;
+     rtx delay_list;
+{
+  rtx temp;
+
+  if (delay_list)
+    {
+      for (temp = delay_list; temp; temp = XEXP (temp, 1))
+        {
+          rtx trial = XEXP (temp, 0);
+          if ((annul_true_p && INSN_FROM_TARGET_P (trial))
+             || (!annul_true_p && !INSN_FROM_TARGET_P (trial)))
+           return 0;
+        }
+    }
+  return 1;
+}
+
 \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
@@ -1454,15 +1690,38 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   rtx new_delay_list = 0;
   int must_annul = *pannul_p;
   int i;
+  int used_annul = 0;
+  struct resources cc_set;
 
   /* 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.
+
+     We can not steal the delay list if one of the instructions in the
+     current delay_list modifies the condition codes and the jump in the 
+     sequence is a conditional jump. We can not do this because we can
+     not change the direction of the jump because the condition codes
+     will effect the direction of the jump in the sequence. */
+
+  CLEAR_RESOURCE (&cc_set);
+  for (temp = delay_list; temp; temp = XEXP (temp, 1))
+    {
+      rtx trial = XEXP (temp, 0);
+
+      mark_set_resources (trial, &cc_set, 0, 1);
+      if (insn_references_resource_p (XVECEXP (seq , 0, 0), &cc_set, 0))
+        return delay_list;
+    }
 
   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++)
@@ -1486,7 +1745,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
@@ -1498,9 +1757,15 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
          ? eligible_for_delay (insn, total_slots_filled, trial, flags)
-         : (must_annul = 1,
-            eligible_for_annul_false (insn, total_slots_filled, trial, flags)))
+         : (must_annul || (delay_list == NULL && new_delay_list == NULL))
+            && (must_annul = 1,
+                check_annul_list_true_false (0, delay_list)
+                && check_annul_list_true_false (0, new_delay_list)
+                && eligible_for_annul_false (insn, total_slots_filled,
+                                             trial, flags)))
        {
+         if (must_annul)
+           used_annul = 1;
          temp = copy_rtx (trial);
          INSN_FROM_TARGET_P (temp) = 1;
          new_delay_list = add_to_delay_list (temp, new_delay_list);
@@ -1519,7 +1784,8 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   /* Add any new insns to the delay list and update the count of the
      number of slots filled.  */
   *pslots_filled = total_slots_filled;
-  *pannul_p = must_annul;
+  if (used_annul)
+    *pannul_p = 1;
 
   if (delay_list == 0)
     return new_delay_list;
@@ -1549,6 +1815,8 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
 {
   int i;
   int flags;
+  int must_annul = *pannul_p;
+  int used_annul = 0;
 
   flags = get_jump_flags (insn, JUMP_LABEL (insn));
 
@@ -1576,20 +1844,23 @@ 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;
        }
 
-      if (! *pannul_p
+      if (! must_annul
          && ((condition == const_true_rtx
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
          ? eligible_for_delay (insn, *pslots_filled, trial, flags)
-         : (*pannul_p = 1,
-            eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
+         : (must_annul || delay_list == NULL) && (must_annul = 1,
+            check_annul_list_true_false (1, delay_list)
+            && eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
        {
+         if (must_annul)
+           used_annul = 1;
          delete_from_delay_slot (trial);
          delay_list = add_to_delay_list (trial, delay_list);
 
@@ -1600,8 +1871,11 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
        break;
     }
 
+  if (used_annul)
+    *pannul_p = 1;
   return delay_list;
 }
+
 \f
 /* Try merging insns starting at THREAD which match exactly the insns in
    INSN's delay list.
@@ -1627,23 +1901,26 @@ try_merge_delay_insns (insn, thread)
   int i;
   int flags;
 
-  flags = get_jump_flags (insn, JUMP_LABEL (insn));
+  flags = get_jump_flags (delay_insn, JUMP_LABEL (delay_insn));
 
   CLEAR_RESOURCE (&needed);
   CLEAR_RESOURCE (&set);
 
   /* If this is not an annulling branch, take into account anything needed in
-     NEXT_TO_MATCH.  This prevents two increments from being incorrectly
+     INSN's delay slot.  This prevents two increments from being incorrectly
      folded into one.  If we are annulling, this would be the correct
      thing to do.  (The alternative, looking at things set in NEXT_TO_MATCH
      will essentially disable this optimization.  This method is somewhat of
      a kludge, but I don't see a better way.)  */
   if (! annul_p)
-    mark_referenced_resources (next_to_match, &needed, 1);
+    for (i = 1 ; i < num_slots ; i++)
+      if (XVECEXP (PATTERN (insn), 0, i))
+        mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, 1);
 
   for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
     {
       rtx pat = PATTERN (trial);
+      rtx oldtrial = trial;
 
       next_trial = next_nonnote_insn (trial);
 
@@ -1661,28 +1938,32 @@ try_merge_delay_insns (insn, thread)
          && ! insn_sets_resource_p (trial, &set, 1)
          && ! insn_sets_resource_p (trial, &needed, 1)
          && (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.  */
          && eligible_for_delay (delay_insn, slot_number - 1, trial, flags))
        {
-         next_trial = next_nonnote_insn (trial);
 
          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;
            }
          else
-           merged_insns = gen_rtx (INSN_LIST, VOIDmode, trial, merged_insns);
+           merged_insns = gen_rtx_INSN_LIST (VOIDmode, trial, merged_insns);
 
          if (++slot_number == num_slots)
            break;
 
          next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
-         if (! annul_p)
-           mark_referenced_resources (next_to_match, &needed, 1);
        }
 
       mark_set_resources (trial, &set, 0, 1);
@@ -1697,6 +1978,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++)
        {
@@ -1713,35 +1999,50 @@ try_merge_delay_insns (insn, thread)
            {
              if (! annul_p)
                {
+                 rtx new;
+
                  update_block (dtrial, thread);
-                 delete_from_delay_slot (dtrial);
+                 new = delete_from_delay_slot (dtrial);
+                 if (INSN_DELETED_P (thread))
+                   thread = new;
                  INSN_FROM_TARGET_P (next_to_match) = 0;
                }
              else
-               merged_insns = gen_rtx (INSN_LIST, SImode, dtrial,
-                                       merged_insns);
+               merged_insns = gen_rtx_INSN_LIST (SImode, dtrial,
+                                                 merged_insns);
 
              if (++slot_number == num_slots)
                break;
 
              next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
            }
+         else
+           {
+             /* Keep track of the set/referenced resources for the delay
+                slots of any trial insns we encounter.  */
+              mark_set_resources (dtrial, &set, 0, 1);
+              mark_referenced_resources (dtrial, &needed, 1);
+           }
        }
     }
 
   /* If all insns in the delay slot have been matched and we were previously
      annulling the branch, we need not any more.  In that case delete all the
-     merged insns.  Also clear the INSN_FROM_TARGET_P bit of each insn the
+     merged insns.  Also clear the INSN_FROM_TARGET_P bit of each insn in
      the delay list so that we know that it isn't only being used at the
      target.  */
-  if (next_to_match == 0 && annul_p)
+  if (slot_number == num_slots && annul_p)
     {
       for (; merged_insns; merged_insns = XEXP (merged_insns, 1))
        {
          if (GET_MODE (merged_insns) == SImode)
            {
+             rtx new;
+
              update_block (XEXP (merged_insns, 0), thread);
-             delete_from_delay_slot (XEXP (merged_insns, 0));
+             new = delete_from_delay_slot (XEXP (merged_insns, 0));
+             if (INSN_DELETED_P (thread))
+               thread = new;
            }
          else
            {
@@ -1776,8 +2077,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;
@@ -1788,6 +2089,11 @@ redundant_insn_p (insn, target, delay_list)
   struct resources needed, set;
   int i;
 
+  /* If INSN has any REG_UNUSED notes, it can't match anything since we
+     are allowed to not actually assign to such a register.  */
+  if (find_reg_note (insn, REG_UNUSED, NULL_RTX) != 0)
+    return 0;
+
   /* Scan backwards looking for a match.  */
   for (trial = PREV_INSN (target); trial; trial = PREV_INSN (trial))
     {
@@ -1826,7 +2132,8 @@ redundant_insn_p (insn, target, delay_list)
             resource requirements as we go.  */
          for (i = XVECLEN (pat, 0) - 1; i > 0; i--)
            if (GET_CODE (XVECEXP (pat, 0, i)) == GET_CODE (insn)
-               && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat))
+               && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat)
+               && ! find_reg_note (XVECEXP (pat, 0, i), REG_UNUSED, NULL_RTX))
              break;
 
          /* If found a match, exit this loop early.  */
@@ -1834,7 +2141,8 @@ redundant_insn_p (insn, target, delay_list)
            break;
        }
 
-      else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat))
+      else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat)
+              && ! find_reg_note (trial, REG_UNUSED, NULL_RTX))
        break;
     }
 
@@ -1867,6 +2175,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
@@ -1906,7 +2215,7 @@ redundant_insn_p (insn, target, delay_list)
          if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN)
            return 0;
 
-         /* If this this is an INSN or JUMP_INSN with delayed effects, it
+         /* If this is an INSN or JUMP_INSN with delayed effects, it
             is hard to track the resource needs properly, so give up.  */
 
 #ifdef INSN_SETS_ARE_DELAYED
@@ -1933,7 +2242,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,
@@ -1955,7 +2264,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))
@@ -2068,7 +2377,7 @@ update_block (insn, where)
   if (INSN_FROM_TARGET_P (insn))
     return;
 
-  emit_insn_before (gen_rtx (USE, VOIDmode, insn), where);
+  emit_insn_before (gen_rtx_USE (VOIDmode, insn), where);
 
   /* INSN might be making a value live in a block where it didn't use to
      be.  So recompute liveness information for this block.  */
@@ -2130,6 +2439,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 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.    */
@@ -2199,6 +2567,183 @@ 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);
+
+         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;
+               }
+           }
+
+       default:
+         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
@@ -2245,12 +2790,11 @@ mark_target_live_regs (target, res)
   int b = -1;
   int i;
   struct target_info *tinfo;
-  rtx insn, next;
+  rtx insn;
   rtx jump_insn = 0;
   rtx jump_target;
   HARD_REG_SET scratch;
   struct resources set, needed;
-  int jump_count = 0;
 
   /* Handle end of function.  */
   if (target == 0)
@@ -2261,7 +2805,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.  */
@@ -2309,8 +2853,7 @@ mark_target_live_regs (target, res)
   if (b != -1)
     {
       regset regs_live = basic_block_live_at_start[b];
-      int offset, j;
-      REGSET_ELT_TYPE bit;
+      int j;
       int regno;
       rtx start_insn, stop_insn;
 
@@ -2318,26 +2861,18 @@ mark_target_live_regs (target, res)
         marked live, plus live pseudo regs that have been renumbered to
         hard regs.  */
 
-#ifdef HARD_REG_SET
-      current_live_regs = *regs_live;
-#else
-      COPY_HARD_REG_SET (current_live_regs, regs_live);
-#endif
+      REG_SET_TO_HARD_REG_SET (current_live_regs, regs_live);
 
-      for (offset = 0, i = 0; offset < regset_size; offset++)
-       {
-         if (regs_live[offset] == 0)
-           i += REGSET_ELT_BITS;
-         else
-           for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
-             if ((regs_live[offset] & bit)
-                 && (regno = reg_renumber[i]) >= 0)
-               for (j = regno;
-                    j < regno + HARD_REGNO_NREGS (regno,
-                                                  PSEUDO_REGNO_MODE (i));
-                    j++)
-                 SET_HARD_REG_BIT (current_live_regs, j);
-       }
+      EXECUTE_IF_SET_IN_REG_SET
+       (regs_live, FIRST_PSEUDO_REGISTER, i,
+        {
+          if ((regno = reg_renumber[i]) >= 0)
+            for (j = regno;
+                 j < regno + HARD_REGNO_NREGS (regno,
+                                               PSEUDO_REGNO_MODE (i));
+                 j++)
+              SET_HARD_REG_BIT (current_live_regs, j);
+        });
 
       /* Get starting and ending insn, handling the case where each might
         be a SEQUENCE.  */
@@ -2379,6 +2914,9 @@ mark_target_live_regs (target, res)
                if (call_used_regs[i]
                    && i != STACK_POINTER_REGNUM && i != FRAME_POINTER_REGNUM
                    && i != ARG_POINTER_REGNUM
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+                   && i != HARD_FRAME_POINTER_REGNUM
+#endif
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
                    && ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
 #endif
@@ -2401,7 +2939,8 @@ mark_target_live_regs (target, res)
             clobber registers used for parameters.  It isn't worth bothering
             with the unlikely case when it won't.  */
          if ((GET_CODE (real_insn) == INSN
-              && GET_CODE (PATTERN (real_insn)) != USE)
+              && GET_CODE (PATTERN (real_insn)) != USE
+              && GET_CODE (PATTERN (real_insn)) != CLOBBER)
              || GET_CODE (real_insn) == JUMP_INSN
              || GET_CODE (real_insn) == CALL_INSN)
            {
@@ -2465,92 +3004,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.
-
-     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.  */
+     live are those that are live using the above test and the test below.  */
 
-  if (jump_insn && jump_count < 10)
+  if (jump_insn)
     {
       struct resources new_resources;
       rtx stop_insn = next_active_insn (jump_insn);
@@ -2592,15 +3057,14 @@ mark_target_live_regs (target, res)
    through FINAL_SEQUENCE.  */
 
 static void
-fill_simple_delay_slots (first, non_jumps_p)
-     rtx first;
+fill_simple_delay_slots (non_jumps_p)
      int non_jumps_p;
 {
   register rtx insn, pat, trial, next_trial;
-  register int i, j;
+  register int i;
   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++)
@@ -2618,10 +3082,25 @@ fill_simple_delay_slots (first, non_jumps_p)
          || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p))
        continue;
      
-      flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      if (GET_CODE (insn) == JUMP_INSN)
+       flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      else
+       flags = get_jump_flags (insn, NULL_RTX);
       slots_to_fill = num_delay_slots (insn);
+
+      /* Some machine description have defined instructions to have
+        delay slots only in certain circumstances which may depend on
+        nearby insns (which change due to reorg's actions).
+
+        For example, the PA port normally has delay slots for unconditional
+        jumps.
+
+        However, the PA port claims such jumps do not have a delay slot
+        if they are immediate successors of certain CALL_INSNs.  This
+        allows the port to favor filling the delay slot of the call with
+        the unconditional jump.  */
       if (slots_to_fill == 0)
-       abort ();
+       continue;
 
       /* This insn needs, or can use, some delay slots.  SLOTS_TO_FILL
         says how many.  After initialization, first try optimizing
@@ -2635,24 +3114,39 @@ fill_simple_delay_slots (first, non_jumps_p)
         the unconditional jump.  This is done first to avoid having the
         delay slot of the call filled in the backward scan.  Also, since
         the unconditional jump is likely to also have a delay slot, that
-        insn must exist when it is subsequently scanned.  */
+        insn must exist when it is subsequently scanned.
+
+        This is tried on each insn with delay slots as some machines
+        have insns which perform calls, but are not represented as 
+        CALL_INSNs.  */
 
       slots_filled = 0;
       delay_list = 0;
 
-      if (GET_CODE (insn) == CALL_INSN
-         && (trial = next_active_insn (insn))
+      if ((trial = next_active_insn (insn))
          && GET_CODE (trial) == JUMP_INSN
          && simplejump_p (trial)
          && 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);
@@ -2702,7 +3196,7 @@ fill_simple_delay_slots (first, non_jumps_p)
 #ifdef HAVE_cc0
                  /* Can't separate set of cc0 from its use.  */
                  && ! (reg_mentioned_p (cc0_rtx, pat)
-                       && ! sets_cc0_p (cc0_rtx, pat))
+                       && ! sets_cc0_p (pat))
 #endif
                  )
                {
@@ -2716,8 +3210,8 @@ fill_simple_delay_slots (first, non_jumps_p)
                         tail, of the list.  */
 
                      update_reg_dead_notes (trial, insn);
-                     delay_list = gen_rtx (INSN_LIST, VOIDmode,
-                                           trial, delay_list);
+                     delay_list = gen_rtx_INSN_LIST (VOIDmode,
+                                                     trial, delay_list);
                      update_block (trial, trial);
                      delete_insn (trial);
                      if (slots_to_fill == ++slots_filled)
@@ -2737,7 +3231,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)
@@ -2751,24 +3246,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);
@@ -2785,13 +3277,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)
@@ -2800,22 +3286,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.  */
@@ -2840,14 +3312,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);
                    }
                }
@@ -2874,8 +3345,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;
@@ -2891,14 +3360,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
@@ -2907,6 +3378,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)
@@ -2921,6 +3393,8 @@ fill_simple_delay_slots (first, non_jumps_p)
 
              if (new_label != 0)
                new_label = get_label_before (new_label);
+             else
+               new_label = find_end_label ();
 
              delay_list 
                = add_to_delay_list (copy_rtx (next_trial), delay_list);
@@ -2934,10 +3408,23 @@ 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),
+                                   slots_to_fill, &slots_filled,
+                                   delay_list);
+
       if (delay_list)
        unfilled_slots_base[i]
-         = emit_delay_sequence (insn, delay_list,
-                                slots_filled, slots_to_fill);
+         = emit_delay_sequence (insn, delay_list, slots_filled);
 
       if (slots_to_fill == slots_filled)
        unfilled_slots_base[i] = 0;
@@ -2958,9 +3445,36 @@ fill_simple_delay_slots (first, non_jumps_p)
     return;
 
   slots_filled = 0;
-  CLEAR_RESOURCE (&needed);
   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
+         || current_function_sp_is_unchanging)
+#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))
     {
@@ -2972,6 +3486,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)
@@ -2985,8 +3500,8 @@ fill_simple_delay_slots (first, non_jumps_p)
                 insns we find on the head of the list.  */
 
              current_function_epilogue_delay_list
-               = gen_rtx (INSN_LIST, VOIDmode, trial,
-                          current_function_epilogue_delay_list);
+               = gen_rtx_INSN_LIST (VOIDmode, trial,
+                                    current_function_epilogue_delay_list);
              mark_referenced_resources (trial, &end_of_function_needs, 1);
              update_block (trial, trial);
              delete_insn (trial);
@@ -3034,18 +3549,18 @@ fill_simple_delay_slots (first, non_jumps_p)
 
 static rtx
 fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
-                       thread_if_true, own_thread, own_opposite_thread,
-                       slots_to_fill, pslots_filled)
+                       thread_if_true, own_thread,
+                       slots_to_fill, pslots_filled, delay_list)
      rtx insn;
      rtx condition;
      rtx thread, opposite_thread;
      int likely;
      int thread_if_true;
-     int own_thread, own_opposite_thread;
+     int own_thread;
      int slots_to_fill, *pslots_filled;
+     rtx delay_list;
 {
   rtx new_thread;
-  rtx delay_list = 0;
   struct resources opposite_needed, set, needed;
   rtx trial;
   int lose = 0;
@@ -3062,7 +3577,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
   /* If our thread is the end of subroutine, we can't get any delay
      insns from that.  */
   if (thread == 0)
-    return 0;
+      return delay_list;
 
   /* If this is an unconditional branch, nothing is needed at the
      opposite thread.  Otherwise, compute what is needed there.  */
@@ -3119,18 +3634,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;
            }
@@ -3138,14 +3666,17 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          /* There are two ways we can win:  If TRIAL doesn't set anything
             needed at the opposite thread and can't trap, or if it can
             go into an annulled delay slot.  */
-         if (condition == const_true_rtx
-             || (! insn_sets_resource_p (trial, &opposite_needed, 1)
-                 && ! may_trap_p (pat)))
+         if (!must_annul
+             && (condition == const_true_rtx
+                 || (! insn_sets_resource_p (trial, &opposite_needed, 1)
+                     && ! may_trap_p (pat))))
            {
              old_trial = trial;
              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;
@@ -3163,10 +3694,14 @@ 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)
-                  : eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
+             if ((must_annul || delay_list == NULL) && (thread_if_true
+                  ? check_annul_list_true_false (0, delay_list)
+                    && eligible_for_annul_false (insn, *pslots_filled, trial, flags)
+                  : check_annul_list_true_false (1, delay_list)
+                    && eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
                {
                  rtx temp;
 
@@ -3185,6 +3720,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
@@ -3206,9 +3747,16 @@ 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))
-                       new_thread = next_active_insn (new_thread);
+                            && (prior_insn
+                                = redundant_insn (new_thread, insn,
+                                                  delay_list)))
+                       {
+                         /* We know we do not own the thread, so no need
+                            to call update_block and delete_insn.  */
+                         fix_reg_dead_note (prior_insn, insn);
+                         update_reg_unused_notes (prior_insn, new_thread);
+                         new_thread = next_active_insn (new_thread);
+                       }
                      break;
                    }
 
@@ -3237,9 +3785,11 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
         but it doesn't seem worth it.  It might also be a good idea to try
         to swap the two insns.  That might do better.
 
-        We can't do this if the next insn modifies our source, because that
-        would make the replacement into the insn invalid.  This also
-        prevents updating the contents of a PRE_INC.  */
+        We can't do this if the next insn modifies our destination, because
+        that would make the replacement into the insn invalid.  We also can't
+        do this if it modifies our source, because it might be an earlyclobber
+        operand.  This latter test also prevents updating the contents of
+        a PRE_INC.  */
 
       if (GET_CODE (trial) == INSN && GET_CODE (pat) == SET
          && GET_CODE (SET_SRC (pat)) == REG
@@ -3250,6 +3800,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          if (next && GET_CODE (next) == INSN
              && GET_CODE (PATTERN (next)) != USE
              && ! reg_set_p (SET_DEST (pat), next)
+             && ! reg_set_p (SET_SRC (pat), next)
              && reg_referenced_p (SET_DEST (pat), PATTERN (next)))
            validate_replace_rtx (SET_DEST (pat), SET_SRC (pat), next);
        }
@@ -3285,7 +3836,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;
@@ -3311,18 +3865,17 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
             the negated constant.  Otherwise, reverse the sense of the
             arithmetic.  */
          if (GET_CODE (other) == CONST_INT)
-           new_arith = gen_rtx (GET_CODE (src), GET_MODE (src), dest,
-                                negate_rtx (GET_MODE (src), other));
+           new_arith = gen_rtx_fmt_ee (GET_CODE (src), GET_MODE (src), dest,
+                                       negate_rtx (GET_MODE (src), other));
          else
-           new_arith = gen_rtx (GET_CODE (src) == PLUS ? MINUS : PLUS,
-                                GET_MODE (src), dest, other);
+           new_arith = gen_rtx_fmt_ee (GET_CODE (src) == PLUS ? MINUS : PLUS,
+                                       GET_MODE (src), dest, other);
 
-         ninsn = emit_insn_after (gen_rtx (SET, VOIDmode, dest, new_arith),
+         ninsn = emit_insn_after (gen_rtx_SET (VOIDmode, dest, new_arith),
                                   insn);
 
          if (recog_memoized (ninsn) < 0
-             || (insn_extract (ninsn),
-                 ! constrain_operands (INSN_CODE (ninsn), 1)))
+             || (extract_insn (ninsn), ! constrain_operands (1)))
            {
              delete_insn (ninsn);
              return 0;
@@ -3331,6 +3884,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
@@ -3360,7 +3919,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)
@@ -3387,8 +3949,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
    if safe.  */
 
 static void
-fill_eager_delay_slots (first)
-     rtx first;
+fill_eager_delay_slots ()
 {
   register rtx insn;
   register int i;
@@ -3407,12 +3968,23 @@ 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);
+      /* Some machine description have defined instructions to have
+        delay slots only in certain circumstances which may depend on
+        nearby insns (which change due to reorg's actions).
+
+        For example, the PA port normally has delay slots for unconditional
+        jumps.
+
+        However, the PA port claims such jumps do not have a delay slot
+        if they are immediate successors of certain CALL_INSNs.  This
+        allows the port to favor filling the delay slot of the call with
+        the unconditional jump.  */
       if (slots_to_fill == 0)
-       abort ();
+        continue;
 
       slots_filled = 0;
       target_label = JUMP_LABEL (insn);
@@ -3421,7 +3993,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.  */
 
@@ -3450,8 +4022,8 @@ fill_eager_delay_slots (first)
          delay_list
            = fill_slots_from_thread (insn, condition, insn_at_target,
                                      fallthrough_insn, prediction == 2, 1,
-                                     own_target, own_fallthrough,
-                                     slots_to_fill, &slots_filled);
+                                     own_target,
+                                     slots_to_fill, &slots_filled, delay_list);
 
          if (delay_list == 0 && own_fallthrough)
            {
@@ -3465,8 +4037,9 @@ fill_eager_delay_slots (first)
              delay_list
                = fill_slots_from_thread (insn, condition, fallthrough_insn,
                                          insn_at_target, 0, 0,
-                                         own_fallthrough, own_target,
-                                         slots_to_fill, &slots_filled);
+                                         own_fallthrough,
+                                         slots_to_fill, &slots_filled,
+                                         delay_list);
            }
        }
       else
@@ -3475,21 +4048,22 @@ fill_eager_delay_slots (first)
            delay_list
              = fill_slots_from_thread (insn, condition, fallthrough_insn,
                                        insn_at_target, 0, 0,
-                                       own_fallthrough, own_target,
-                                       slots_to_fill, &slots_filled);
+                                       own_fallthrough,
+                                       slots_to_fill, &slots_filled,
+                                       delay_list);
 
          if (delay_list == 0)
            delay_list
              = fill_slots_from_thread (insn, condition, insn_at_target,
                                        next_active_insn (insn), 0, 1,
-                                       own_target, own_fallthrough,
-                                       slots_to_fill, &slots_filled);
+                                       own_target,
+                                       slots_to_fill, &slots_filled,
+                                       delay_list);
        }
 
       if (delay_list)
        unfilled_slots_base[i]
-         = emit_delay_sequence (insn, delay_list,
-                                slots_filled, slots_to_fill);
+         = emit_delay_sequence (insn, delay_list, slots_filled);
 
       if (slots_to_fill == slots_filled)
        unfilled_slots_base[i] = 0;
@@ -3520,7 +4094,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);
@@ -3529,7 +4103,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;
@@ -3586,9 +4161,9 @@ 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,
+         && 0 > mostly_true_jump (other,
                                   get_branch_condition (other,
                                                         JUMP_LABEL (other))))
        {
@@ -3618,16 +4193,51 @@ 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);
          continue;
        }
 
+      /* See if we have a RETURN insn with a filled delay slot followed
+        by a RETURN insn with an unfilled a delay slot.  If so, we can delete
+        the first RETURN (but not it's delay insn).  This gives the same
+        effect in fewer instructions.
+
+        Only do so if optimizing for size since this results in slower, but
+        smaller code.  */
+      if (optimize_size
+         && GET_CODE (PATTERN (delay_insn)) == RETURN
+         && next
+         && GET_CODE (next) == JUMP_INSN
+         && GET_CODE (PATTERN (next)) == RETURN)
+       {
+         int i;
+
+         /* Delete the RETURN and just execute the delay list insns.
+
+            We do this by deleting the INSN containing the SEQUENCE, then
+            re-emitting the insns separately, and then deleting the RETURN.
+            This allows the count of the jump target to be properly
+            decremented.  */
+
+         /* Clear the from target bit, since these insns are no longer
+            in delay slots.  */
+         for (i = 0; i < XVECLEN (pat, 0); i++)
+           INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
+
+         trial = PREV_INSN (insn);
+         delete_insn (insn);
+         emit_insn_after (pat, trial);
+         delete_scheduled_jump (delay_insn);
+         continue;
+       }
+
       /* 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);
@@ -3637,11 +4247,17 @@ 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 ();
 
-         if (trial != target_label)
+         if (trial != target_label 
+             && redirect_with_delay_slots_safe_p (delay_insn, trial, insn))
            {
              reorg_redirect_jump (delay_insn, trial);
              target_label = trial;
@@ -3651,13 +4267,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;
@@ -3670,19 +4295,25 @@ 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)
                target_label = find_end_label ();
-             reorg_redirect_jump (delay_insn, target_label);
-             next = insn;
-             continue;
+
+             if (redirect_with_delay_slots_safe_p (delay_insn, target_label, 
+                                                   insn))
+               {
+                 reorg_redirect_jump (delay_insn, target_label);
+                 next = insn;
+                 continue;
+               }
            }
        }
 
       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
@@ -3746,20 +4377,35 @@ relax_delay_slots (first)
          if (label == 0)
            label = find_end_label ();
 
-         /* Be careful how we do this to avoid deleting code or labels
-            that are momentarily dead.  See similar optimization in jump.c  */
-         if (old_label)
-           ++LABEL_NUSES (old_label);
-
-         if (invert_jump (delay_insn, label))
+         if (redirect_with_delay_slots_safe_p (delay_insn, label, insn))
            {
-             delete_insn (next);
-             next = insn;
-           }
+             /* Be careful how we do this to avoid deleting code or labels
+                that are momentarily dead.  See similar optimization in
+                jump.c  */
+             if (old_label)
+               ++LABEL_NUSES (old_label);
 
-         if (old_label && --LABEL_NUSES (old_label) == 0)
-           delete_insn (old_label);
-         continue;
+             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;
+               }
+
+             if (old_label && --LABEL_NUSES (old_label) == 0)
+               delete_insn (old_label);
+             continue;
+           }
        }
 
       /* If we own the thread opposite the way this insn branches, see if we
@@ -3823,11 +4469,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;
        }
 
@@ -3891,8 +4542,8 @@ make_return_insns (first)
   if (--LABEL_NUSES (real_return_label) == 0)
     delete_insn (real_return_label);
 
-  fill_simple_delay_slots (first, 1);
-  fill_simple_delay_slots (first, 0);
+  fill_simple_delay_slots (1);
+  fill_simple_delay_slots (0);
 }
 #endif
 \f
@@ -3933,7 +4584,7 @@ dbr_schedule (first, file)
        epilogue_insn = insn;
     }
 
-  uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int *));
+  uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int));
   for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn))
     uid_to_ruid[INSN_UID (insn)] = i;
   
@@ -3961,7 +4612,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)))
@@ -3977,26 +4629,34 @@ 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)
     {
       SET_HARD_REG_BIT (end_of_function_needs.regs, FRAME_POINTER_REGNUM);
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+      SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
+#endif
 #ifdef EXIT_IGNORE_STACK
-      if (! EXIT_IGNORE_STACK)
+      if (! EXIT_IGNORE_STACK
+         || current_function_sp_is_unchanging)
 #endif
        SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
     }
   else
     SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
 
-  if (current_function_return_rtx != 0
-      && GET_CODE (current_function_return_rtx) == REG)
+  if (current_function_return_rtx != 0)
     mark_referenced_resources (current_function_return_rtx,
                               &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
@@ -4018,7 +4678,7 @@ dbr_schedule (first, file)
 
   start_of_epilogue_needs = end_of_function_needs;
 
-  while (epilogue_insn = next_nonnote_insn (epilogue_insn))
+  while ((epilogue_insn = next_nonnote_insn (epilogue_insn)))
     mark_set_resources (epilogue_insn, &end_of_function_needs, 0, 1);
 
   /* Show we haven't computed an end-of-function label yet.  */
@@ -4028,14 +4688,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.  */
@@ -4044,9 +4705,9 @@ dbr_schedule (first, file)
        reorg_pass_number < MAX_REORG_PASSES;
        reorg_pass_number++)
     {
-      fill_simple_delay_slots (first, 1);
-      fill_simple_delay_slots (first, 0);
-      fill_eager_delay_slots (first);
+      fill_simple_delay_slots (1);
+      fill_simple_delay_slots (0);
+      fill_eager_delay_slots ();
       relax_delay_slots (first);
     }
 
@@ -4111,5 +4772,30 @@ dbr_schedule (first, file)
            }
        }
     }
+
+  /* For all JUMP insns, fill in branch prediction notes, so that during
+     assembler output a target can set branch prediction bits in the code.
+     We have to do this now, as up until this point the destinations of
+     JUMPS can be moved around and changed, but past right here that cannot
+     happen.  */
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    {
+      int pred_flags;
+
+      if (GET_CODE (insn) == INSN)
+        {
+         rtx pat = PATTERN (insn);
+
+         if (GET_CODE (pat) == SEQUENCE)
+           insn = XVECEXP (pat, 0, 0);
+       }
+      if (GET_CODE (insn) != JUMP_INSN)
+       continue;
+
+      pred_flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_BR_PRED,
+                                           GEN_INT (pred_flags),
+                                           REG_NOTES (insn));
+    }
 }
 #endif /* DELAY_SLOTS */