OSDN Git Service

(DUCR.M,DUC.M): Defined.
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 778090e..8cd4473 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992 Free Software Foundation, Inc.
-   Contributed by Richard Kenner (kenner@nyu.edu).
+   Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
 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.
 
@@ -53,6 +54,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    target that would only be safe to execute knowing that the branch
    is taken.
 
+   The HP-PA always has a branch delay slot.  For unconditional branches
+   its effects can be annulled when the branch is taken.  The effects 
+   of the delay slot in a conditional branch can be nullified for forward
+   taken branches, or for untaken backward branches.  This means
+   we can hoist insns from the fall-through path for forward branches or
+   steal insns from the target of backward branches.
+
    Three techniques for filling delay slots have been implemented so far:
 
    (1) `fill_simple_delay_slots' is the simplest, most efficient way
@@ -70,7 +78,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    this strategy, but it helps (by keeping more options open).
    `fill_eager_delay_slots' tries to guess the direction the branch
    will go; if it guesses right 100% of the time, it can reduce the
-   branch penalty as much as `fill_eager_delay_slots' does.  If it
+   branch penalty as much as `fill_simple_delay_slots' does.  If it
    guesses wrong 100% of the time, it might as well schedule nops (or
    on the m88k, unexpose the branch slot).  When
    `fill_eager_delay_slots' takes insns from the fall-through path of
@@ -122,16 +130,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "insn-attr.h"
 
+/* Import list of registers used as spill regs from reload.  */
+extern HARD_REG_SET used_spill_regs;
+
+/* Import highest label used in function at end of reload.  */
+extern int max_label_num_after_reload;
+
+
 #ifdef DELAY_SLOTS
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
 #ifndef ANNUL_IFTRUE_SLOTS
-#define eligible_for_annul_true(INSN, SLOTS, TRIAL) 0
+#define eligible_for_annul_true(INSN, SLOTS, TRIAL, FLAGS) 0
 #endif
 #ifndef ANNUL_IFFALSE_SLOTS
-#define eligible_for_annul_false(INSN, SLOTS, TRIAL) 0
+#define eligible_for_annul_false(INSN, SLOTS, TRIAL, FLAGS) 0
 #endif
 
 /* Insns which have delay slots that have not yet been filled.  */
@@ -155,16 +170,20 @@ 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.  */
+static struct resources start_of_epilogue_needs;
+
 /* Indicates what resources are required at function end.  */
 static struct resources end_of_function_needs;
 
@@ -204,10 +223,55 @@ static int *uid_to_ruid;
 /* Highest valid index in `uid_to_ruid'.  */
 static int max_uid;
 
-/* Forward references: */
-
-static int redundant_insn_p ();
-static void update_block ();
+static void mark_referenced_resources PROTO((rtx, struct resources *, int));
+static void mark_set_resources PROTO((rtx, struct resources *, int, int));
+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 rtx find_end_label      PROTO((void));
+static rtx emit_delay_sequence PROTO((rtx, rtx, int, int));
+static rtx add_to_delay_list   PROTO((rtx, rtx));
+static void 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));
+static int get_jump_flags PROTO((rtx, rtx));
+static int rare_destination PROTO((rtx));
+static int mostly_true_jump    PROTO((rtx, rtx));
+static rtx get_branch_condition        PROTO((rtx, rtx));
+static int condition_dominates_p PROTO((rtx, rtx));
+static rtx steal_delay_list_from_target PROTO((rtx, rtx, rtx, rtx,
+                                              struct resources *,
+                                              struct resources *,
+                                              struct resources *,
+                                              int, int *, int *, rtx *));
+static rtx steal_delay_list_from_fallthrough PROTO((rtx, rtx, rtx, rtx,
+                                                   struct resources *,
+                                                   struct resources *,
+                                                   struct resources *,
+                                                   int, int *, int *));
+static void try_merge_delay_insns PROTO((rtx, rtx));
+static rtx redundant_insn      PROTO((rtx, rtx, rtx));
+static int own_thread_p                PROTO((rtx, rtx, int));
+static int find_basic_block    PROTO((rtx));
+static void update_block       PROTO((rtx, rtx));
+static int reorg_redirect_jump PROTO((rtx, rtx));
+static void update_reg_dead_notes PROTO((rtx, rtx));
+static void fix_reg_dead_note PROTO((rtx, rtx));
+static void update_reg_unused_notes PROTO((rtx, rtx));
+static void update_live_status PROTO((rtx, rtx));
+static rtx next_insn_no_annul  PROTO((rtx));
+static void mark_target_live_regs PROTO((rtx, struct resources *));
+static void fill_simple_delay_slots PROTO((rtx, 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));
+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
@@ -215,10 +279,10 @@ static void update_block ();
    CALL_INSNs.  */
 
 static void
-mark_referenced_resources (x, res, include_called_routine)
+mark_referenced_resources (x, res, include_delayed_effects)
      register rtx x;
      register struct resources *res;
-     register int include_called_routine;
+     register int include_delayed_effects;
 {
   register enum rtx_code code = GET_CODE (x);
   register int i, j;
@@ -256,7 +320,9 @@ mark_referenced_resources (x, res, include_called_routine)
     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);
 
@@ -270,6 +336,7 @@ mark_referenced_resources (x, res, include_called_routine)
 
     case UNSPEC_VOLATILE:
     case ASM_INPUT:
+    case TRAP_IF:
       /* Traditional asm's are always volatile.  */
       res->volatil = 1;
       return;
@@ -313,7 +380,7 @@ mark_referenced_resources (x, res, include_called_routine)
       return;
 
     case CALL_INSN:
-      if (include_called_routine)
+      if (include_delayed_effects)
        {
          /* A CALL references memory, the frame pointer if it exists, the
             stack pointer, any global registers and any registers given in
@@ -325,11 +392,13 @@ mark_referenced_resources (x, res, include_called_routine)
          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)
@@ -339,39 +408,65 @@ mark_referenced_resources (x, res, include_called_routine)
          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:
+
+#ifdef INSN_REFERENCES_ARE_DELAYED
+      if (! include_delayed_effects
+         && INSN_REFERENCES_ARE_DELAYED (x))
+       return;
+#endif
+
       /* No special processing, just speed up.  */
-      mark_referenced_resources (PATTERN (x), res, include_called_routine);
+      mark_referenced_resources (PATTERN (x), res, include_delayed_effects);
       return;
     }
 
@@ -381,20 +476,23 @@ mark_referenced_resources (x, res, include_called_routine)
     switch (*format_ptr++)
       {
       case 'e':
-       mark_referenced_resources (XEXP (x, i), res, include_called_routine);
+       mark_referenced_resources (XEXP (x, i), res, include_delayed_effects);
        break;
 
       case 'E':
        for (j = 0; j < XVECLEN (x, i); j++)
          mark_referenced_resources (XVECEXP (x, i, j), res,
-                                    include_called_routine);
+                                    include_delayed_effects);
        break;
       }
 }
 \f
-/* Given an insn, INSN, and a pointer to a `struct resource', RES, indicate
-   which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE
-   is TRUE, 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_CALLED_ROUTINE
+   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.
 
    We never mark the insn as modifying the condition code unless it explicitly
    SETs CC0 even though this is not totally correct.  The reason for this is
@@ -403,102 +501,179 @@ mark_referenced_resources (x, res, include_called_routine)
    our computation and thus may be placed in a delay slot.   */
 
 static void
-mark_set_resources (insn, res, include_called_routine)
-     register rtx insn;
+mark_set_resources (x, res, in_dest, include_delayed_effects)
+     register rtx x;
      register struct resources *res;
-     int include_called_routine;
+     int in_dest;
+     int include_delayed_effects;
 {
-  register int i;
+  register enum rtx_code code;
+  register int i, j;
+  register char *format_ptr;
 
-  switch (GET_CODE (insn))
+ restart:
+
+  code = GET_CODE (x);
+
+  switch (code)
     {
     case NOTE:
     case BARRIER:
     case CODE_LABEL:
+    case USE:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST:
+    case PC:
       /* These don't set any resources.  */
       return;
 
+    case CC0:
+      if (in_dest)
+       res->cc = 1;
+      return;
+
     case CALL_INSN:
       /* Called routine modifies the condition code, memory, any registers
         that aren't saved across calls, global registers and anything
         explicitly CLOBBERed immediately after the CALL_INSN.  */
 
-      if (include_called_routine)
+      if (include_delayed_effects)
        {
-         rtx next = NEXT_INSN (insn);
+         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_referenced_resources (XEXP (PATTERN (next), 0), res, 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.  */
 
     case JUMP_INSN:
     case INSN:
-      {
-       register rtx body = PATTERN (insn);
-       register rtx note;
-
-       /* An insn consisting of just a CLOBBER (or USE) is
-          just for flow and doesn't actually do anything, so we don't check
-          for it.
 
-          If the source of a SET is a CALL, this is actually done by
-          the called routine.  So only include it if we are to include the
-          effects of the calling routine.  */
+       /* An insn consisting of just a CLOBBER (or USE) is just for flow
+          and doesn't actually do anything, so we ignore it.  */
 
-       if (GET_CODE (body) == SET
-           && (include_called_routine || GET_CODE (SET_SRC (body)) != CALL))
-         mark_referenced_resources (SET_DEST (body), res, 0);
-       else if (GET_CODE (body) == PARALLEL)
-         {
-           for (i = 0; i < XVECLEN (body, 0); i++)
-             if ((GET_CODE (XVECEXP (body, 0, i)) == SET
-                  && (include_called_routine
-                      || GET_CODE (SET_SRC (XVECEXP (body, 0, i))) != CALL))
-                 || GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
-               mark_referenced_resources (SET_DEST (XVECEXP (body, 0, i)),
-                                          res, 0);
-         }
-       else if (GET_CODE (body) == SEQUENCE)
-         for (i = 0; i < XVECLEN (body, 0); i++)
-           if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0))
-                  && INSN_FROM_TARGET_P (XVECEXP (body, 0, i))))
-             mark_set_resources (XVECEXP (body, 0, i), res,
-                                 include_called_routine);
-
-#ifdef AUTO_INC_DEC
-       /* If any register are incremented or decremented in an address,
-          they are set here.  */
-       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
-         if (REG_NOTE_KIND (note) == REG_INC)
-           mark_referenced_resources (XEXP (note, 0), res, 0);
+#ifdef INSN_SETS_ARE_DELAYED
+      if (! include_delayed_effects
+         && INSN_SETS_ARE_DELAYED (x))
+       return;
 #endif
 
-#ifdef PUSH_ROUNDING
-       /* An insn that has a PRE_DEC on SP will not have a REG_INC note.
-          Until we fix this correctly, consider all insns as modifying
-          SP on such machines.  So far, we don't have delay slot scheduling
-          on any machines with PUSH_ROUNDING.  */
-       SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM);
-#endif
-       return;
-      }
+      x = PATTERN (x);
+      if (GET_CODE (x) != USE && GET_CODE (x) != CLOBBER)
+       goto restart;
+      return;
 
-    default:
-      abort ();
+    case SET:
+      /* If the source of a SET is a CALL, this is actually done by
+        the called routine.  So only include it if we are to include the
+        effects of the calling routine.  */
+
+      mark_set_resources (SET_DEST (x), res,
+                         (include_delayed_effects
+                          || GET_CODE (SET_SRC (x)) != CALL),
+                         0);
+
+      mark_set_resources (SET_SRC (x), res, 0, 0);
+      return;
+
+    case CLOBBER:
+      mark_set_resources (XEXP (x, 0), res, 1, 0);
+      return;
+      
+    case SEQUENCE:
+      for (i = 0; i < XVECLEN (x, 0); i++)
+       if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (x, 0, 0))
+              && INSN_FROM_TARGET_P (XVECEXP (x, 0, i))))
+         mark_set_resources (XVECEXP (x, 0, i), res, 0,
+                             include_delayed_effects);
+      return;
+
+    case POST_INC:
+    case PRE_INC:
+    case POST_DEC:
+    case PRE_DEC:
+      mark_set_resources (XEXP (x, 0), res, 1, 0);
+      return;
+
+    case ZERO_EXTRACT:
+      mark_set_resources (XEXP (x, 0), res, in_dest, 0);
+      mark_set_resources (XEXP (x, 1), res, 0, 0);
+      mark_set_resources (XEXP (x, 2), res, 0, 0);
+      return;
+
+    case MEM:
+      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;
     }
+
+  /* Process each sub-expression and flag what it needs.  */
+  format_ptr = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+    switch (*format_ptr++)
+      {
+      case 'e':
+       mark_set_resources (XEXP (x, i), res, in_dest, include_delayed_effects);
+       break;
+
+      case 'E':
+       for (j = 0; j < XVECLEN (x, i); j++)
+         mark_set_resources (XVECEXP (x, i, j), res, in_dest,
+                             include_delayed_effects);
+       break;
+      }
 }
 \f
 /* Return TRUE if this insn should stop the search for insn to fill delay
@@ -546,6 +721,7 @@ resource_conflicts_p (res1, res2)
      struct resources *res1, *res2;
 {
   if ((res1->cc && res2->cc) || (res1->memory && res2->memory)
+      || (res1->unch_memory && res2->unch_memory)
       || res1->volatil || res2->volatil)
     return 1;
 
@@ -573,15 +749,15 @@ resource_conflicts_p (res1, res2)
    a large block of complex code.  */
 
 static int
-insn_references_resource_p (insn, res, include_called_routine)
+insn_references_resource_p (insn, res, include_delayed_effects)
      register rtx insn;
      register struct resources *res;
-     int include_called_routine;
+     int include_delayed_effects;
 {
   struct resources insn_res;
 
   CLEAR_RESOURCE (&insn_res);
-  mark_referenced_resources (insn, &insn_res, include_called_routine);
+  mark_referenced_resources (insn, &insn_res, include_delayed_effects);
   return resource_conflicts_p (&insn_res, res);
 }
 
@@ -591,15 +767,15 @@ insn_references_resource_p (insn, res, include_called_routine)
    in front of mark_set_resources for details.  */
 
 static int
-insn_sets_resource_p (insn, res, include_called_routine)
+insn_sets_resource_p (insn, res, include_delayed_effects)
      register rtx insn;
      register struct resources *res;
-     int include_called_routine;
+     int include_delayed_effects;
 {
   struct resources insn_sets;
 
   CLEAR_RESOURCE (&insn_sets);
-  mark_set_resources (insn, &insn_sets, include_called_routine);
+  mark_set_resources (insn, &insn_sets, 0, include_delayed_effects);
   return resource_conflicts_p (&insn_sets, res);
 }
 \f
@@ -626,8 +802,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,
@@ -638,8 +832,12 @@ find_end_label ()
 #ifdef HAVE_return
       if (HAVE_return)
        {
-         emit_jump_insn (gen_return ());
+         /* The return we make may have delay slots too.  */
+         rtx insn = gen_return ();
+         insn = emit_jump_insn (insn);
          emit_barrier ();
+          if (num_delay_slots (insn) > 0)
+           obstack_ptr_grow (&unfilled_slots_obstack, insn);
        }
 #endif
     }
@@ -672,14 +870,14 @@ emit_delay_sequence (insn, list, length, avail)
   register rtx li;
   int had_barrier = 0;
 
-  /* Allocate the the rtvec to hold the insns and the SEQUENCE. */
+  /* Allocate the the rtvec to hold the insns and the SEQUENCE.  */
   rtvec seqv = rtvec_alloc (length + 1);
   rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);
   rtx seq_insn = make_insn_raw (seq);
   rtx first = get_insns ();
   rtx last = get_last_insn ();
 
-  /* Make a copy of the insn having delay slots. */
+  /* Make a copy of the insn having delay slots.  */
   rtx delay_insn = copy_rtx (insn);
 
   /* If INSN is followed by a BARRIER, delete the BARRIER since it will only
@@ -764,9 +962,24 @@ add_to_delay_list (insn, delay_list)
      rtx insn;
      rtx delay_list;
 {
-  /* If we have an empty list, just make a new list element.  */
+  /* 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
+     be moving the insn to a new block.  */
+
   if (delay_list == 0)
-    return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+    {
+      struct target_info *tinfo;
+      
+      for (tinfo = target_hash_table[INSN_UID (insn) % TARGET_HASH_PRIME];
+          tinfo; tinfo = tinfo->next)
+       if (tinfo->uid == INSN_UID (insn))
+         break;
+
+      if (tinfo)
+       tinfo->block = -1;
+
+      return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+    }
 
   /* Otherwise this must be an INSN_LIST.  Add INSN to the end of the
      list.  */
@@ -942,13 +1155,16 @@ optimize_skip (insn)
   rtx next_trial = next_active_insn (trial);
   rtx delay_list = 0;
   rtx target_label;
+  int flags;
+
+  flags = get_jump_flags (insn, JUMP_LABEL (insn));
 
   if (trial == 0
       || GET_CODE (trial) != INSN
       || GET_CODE (PATTERN (trial)) == SEQUENCE
       || recog_memoized (trial) < 0
-      || (! eligible_for_annul_false (insn, 0, trial)
-         && ! eligible_for_annul_true (insn, 0, trial)))
+      || (! eligible_for_annul_false (insn, 0, trial, flags)
+         && ! eligible_for_annul_true (insn, 0, trial, flags)))
     return 0;
 
   /* There are two cases where we are just executing one insn (we assume
@@ -964,11 +1180,11 @@ optimize_skip (insn)
          && (simplejump_p (next_trial)
              || GET_CODE (PATTERN (next_trial)) == RETURN)))
     {
-      if (eligible_for_annul_false (insn, 0, trial))
+      if (eligible_for_annul_false (insn, 0, trial, flags))
        {
          if (invert_jump (insn, JUMP_LABEL (insn)))
            INSN_FROM_TARGET_P (trial) = 1;
-         else if (! eligible_for_annul_true (insn, 0, trial))
+         else if (! eligible_for_annul_true (insn, 0, trial, flags))
            return 0;
        }
 
@@ -988,7 +1204,14 @@ optimize_skip (insn)
          target_label = JUMP_LABEL (next_trial);
          if (target_label == 0)
            target_label = find_end_label ();
-         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;
@@ -998,10 +1221,123 @@ optimize_skip (insn)
 }
 #endif
 \f
+
+/*  Encode and return branch direction and prediction information for
+    INSN assuming it will jump to LABEL.
+
+    Non conditional branches return no direction information and
+    are predicted as very likely taken.  */
+
+static int
+get_jump_flags (insn, label)
+     rtx insn, label;
+{
+  int flags;
+
+  /* get_jump_flags can be passed any insn with delay slots, these may
+     be INSNs, CALL_INSNs, or JUMP_INSNs.  Only JUMP_INSNs have branch
+     direction information, and only if they are conditional jumps.
+
+     If LABEL is zero, then there is no way to determine the branch
+     direction.  */
+  if (GET_CODE (insn) == JUMP_INSN
+      && (condjump_p (insn) || condjump_in_parallel_p (insn))
+      && INSN_UID (insn) <= max_uid
+      && label != 0
+      && INSN_UID (label) <= max_uid)
+    flags 
+      = (uid_to_ruid[INSN_UID (label)] > uid_to_ruid[INSN_UID (insn)])
+        ? ATTR_FLAG_forward : ATTR_FLAG_backward;
+  /* No valid direction information.  */
+  else
+    flags = 0;
+  
+  /* If insn is a conditional branch call mostly_true_jump to get
+     determine the branch prediction.  
+
+     Non conditional branches are predicted as very likely taken.  */
+  if (GET_CODE (insn) == JUMP_INSN
+      && (condjump_p (insn) || condjump_in_parallel_p (insn)))
+    {
+      int prediction;
+
+      prediction = mostly_true_jump (insn, get_branch_condition (insn, label));
+      switch (prediction)
+       {
+         case 2:
+           flags |= (ATTR_FLAG_very_likely | ATTR_FLAG_likely);
+           break;
+         case 1:
+           flags |= ATTR_FLAG_likely;
+           break;
+         case 0:
+           flags |= ATTR_FLAG_unlikely;
+           break;
+         case -1:
+           flags |= (ATTR_FLAG_very_unlikely | ATTR_FLAG_unlikely);
+           break;
+
+         default:
+           abort();
+       }
+    }
+  else
+    flags |= (ATTR_FLAG_very_likely | ATTR_FLAG_likely);
+
+  return flags;
+}
+
+/* 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.  */
+
+static int
+rare_destination (insn)
+     rtx insn;
+{
+  int jump_count = 0;
+  rtx next;
+
+  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:
+         return 0;
+       case BARRIER:
+         /* A BARRIER can either be after a JUMP_INSN or a CALL_INSN.  We 
+            don't scan past JUMP_INSNs, so any barrier we find here must
+            have been after a CALL_INSN and hence mean the call doesn't
+            return.  */
+         return 2;
+       case JUMP_INSN:
+         if (GET_CODE (PATTERN (insn)) == RETURN)
+           return 1;
+         else if (simplejump_p (insn)
+                  && jump_count++ < 10)
+           next = JUMP_LABEL (insn);
+         else
+           return 0;
+       }
+    }
+
+  /* If we got here it means we hit the end of the function.  So this
+     is an unlikely destination.  */
+
+  return 1;
+}
+
 /* Return truth value of the statement that this branch
    is mostly taken.  If we think that the branch is extremely likely
    to be taken, we return 2.  If the branch is slightly more likely to be
-   taken, return 1.  Otherwise, return 0.
+   taken, return 1.  If the branch is slightly less likely to be taken,
+   return 0 and if the branch is highly unlikely to be taken, return -1.
 
    CONDITION, if non-zero, is the condition that JUMP_INSN is testing.  */
 
@@ -1011,29 +1347,77 @@ mostly_true_jump (jump_insn, condition)
 {
   rtx target_label = JUMP_LABEL (jump_insn);
   rtx insn;
+  int rare_dest = rare_destination (target_label);
+  int rare_fallthrough = rare_destination (NEXT_INSN (jump_insn));
 
-  /* If this is a conditional return insn, assume it won't return.  */
-  if (target_label == 0)
-    return 0;
+  /* 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 TARGET_LABEL has no jumps between it and the end of the function,
-     this is essentially a conditional return, so predict it as false.  */
-  for (insn = NEXT_INSN (target_label);
-       insn && GET_CODE (insn) != JUMP_INSN;
-       insn = NEXT_INSN (insn))
-    ;
+         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 (insn == 0)
-    return 0;
+  /* 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
+      && ((GET_CODE (XEXP (SET_SRC (PATTERN (jump_insn)), 1)) == LABEL_REF
+          && LABEL_OUTSIDE_LOOP_P (XEXP (SET_SRC (PATTERN (jump_insn)), 1)))
+         || (GET_CODE (XEXP (SET_SRC (PATTERN (jump_insn)), 2)) == LABEL_REF
+             && LABEL_OUTSIDE_LOOP_P (XEXP (SET_SRC (PATTERN (jump_insn)), 2)))))
+    return -1;
+
+  if (target_label)
+    {
+      /* If this is the test of a loop, it is very likely true.  We scan
+        backwards from the target label.  If we find a NOTE_INSN_LOOP_BEG
+        before the next real insn, we assume the branch is to the top of 
+        the loop.  */
+      for (insn = PREV_INSN (target_label);
+          insn && GET_CODE (insn) == NOTE;
+          insn = PREV_INSN (insn))
+       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+         return 2;
+
+      /* If this is a jump to the test of a loop, it is likely true.  We scan
+        forwards from the target label.  If we find a NOTE_INSN_LOOP_VTOP
+        before the next real insn, we assume the branch is to the loop branch
+        test.  */
+      for (insn = NEXT_INSN (target_label);
+          insn && GET_CODE (insn) == NOTE;
+          insn = PREV_INSN (insn))
+       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP)
+         return 1;
+    }
+
+  /* Look at the relative rarities of the fallthrough and destination.  If
+     they differ, we can predict the branch that way.  */
 
-  /* If this is the test of a loop, it is very likely true.  We scan backwards
-     from the target label.  If we find a NOTE_INSN_LOOP_BEG before the next
-     real insn, we assume the branch is to the top of the loop.  */
-  for (insn = PREV_INSN (target_label);
-       insn && GET_CODE (insn) == NOTE;
-       insn = PREV_INSN (insn))
-    if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+  switch (rare_fallthrough - rare_dest)
+    {
+    case -2:
+      return -1;
+    case -1:
+      return 0;
+    case 0:
+      break;
+    case 1:
+      return 1;
+    case 2:
       return 2;
+    }
 
   /* If we couldn't figure out what this jump was, assume it won't be 
      taken.  This should be rare.  */
@@ -1067,7 +1451,8 @@ mostly_true_jump (jump_insn, condition)
   /* Predict backward branches usually take, forward branches usually not.  If
      we don't know whether this is forward or backward, assume the branch
      will be taken, since most are.  */
-  return (INSN_UID (jump_insn) > max_uid || INSN_UID (target_label) > max_uid
+  return (target_label == 0 || INSN_UID (jump_insn) > max_uid
+         || INSN_UID (target_label) > max_uid
          || (uid_to_ruid[INSN_UID (jump_insn)]
              > uid_to_ruid[INSN_UID (target_label)]));;
 }
@@ -1085,6 +1470,9 @@ get_branch_condition (insn, target)
   rtx pat = PATTERN (insn);
   rtx src;
   
+  if (condjump_in_parallel_p (insn))
+    pat = XVECEXP (pat, 0, 0);
+
   if (GET_CODE (pat) == RETURN)
     return target == 0 ? const_true_rtx : 0;
 
@@ -1110,6 +1498,8 @@ get_branch_condition (insn, target)
     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 0;
 }
 
 /* Return non-zero if CONDITION is more strict than the condition of
@@ -1139,6 +1529,75 @@ 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, slots, 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);
+}
+
 \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
@@ -1183,17 +1642,23 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
 
   /* We can't do anything if there are more delay slots in SEQ than we
      can handle, or if we don't know that it will be a taken branch.
-
      We know that it will be a taken branch if it is either an unconditional
-     branch or a conditional branch with a stricter branch condition.  */
+     branch or a conditional branch with a stricter branch condition.
+
+     Also, exit if the branch has more than one set, since then it is computing
+     other results that can't be ignored, e.g. the HPPA mov&branch instruction.
+     ??? It may be possible to move other sets into INSN in addition to
+     moving the instructions in the delay slots.  */
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
-      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0)))
+      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))
+      || ! single_set (XVECEXP (seq, 0, 0)))
     return delay_list;
 
   for (i = 1; i < XVECLEN (seq, 0); i++)
     {
       rtx trial = XVECEXP (seq, 0, i);
+      int flags;
 
       if (insn_references_resource_p (trial, sets, 0)
          || insn_sets_resource_p (trial, needed, 0)
@@ -1211,16 +1676,20 @@ 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
+        based on jumping to the new label.  */
+      flags = get_jump_flags (insn, JUMP_LABEL (XVECEXP (seq, 0, 0)));
+
       if (! must_annul
          && ((condition == const_true_rtx
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
-         ? eligible_for_delay (insn, total_slots_filled, trial)
+         ? eligible_for_delay (insn, total_slots_filled, trial, flags)
          : (must_annul = 1,
-            eligible_for_annul_false (insn, total_slots_filled, trial)))
+            eligible_for_annul_false (insn, total_slots_filled, trial, flags)))
        {
          temp = copy_rtx (trial);
          INSN_FROM_TARGET_P (temp) = 1;
@@ -1269,6 +1738,9 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
      int *pannul_p;
 {
   int i;
+  int flags;
+
+  flags = get_jump_flags (insn, JUMP_LABEL (insn));
 
   /* We can't do anything if SEQ's delay insn isn't an
      unconditional branch.  */
@@ -1294,7 +1766,7 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
        break;
 
       /* If this insn was already done, we don't need it.  */
-      if (redundant_insn_p (trial, insn, delay_list))
+      if (redundant_insn (trial, insn, delay_list))
        {
          delete_from_delay_slot (trial);
          continue;
@@ -1304,9 +1776,9 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
          && ((condition == const_true_rtx
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
-         ? eligible_for_delay (insn, *pslots_filled, trial)
+         ? eligible_for_delay (insn, *pslots_filled, trial, flags)
          : (*pannul_p = 1,
-            eligible_for_annul_true (insn, *pslots_filled, trial)))
+            eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
        {
          delete_from_delay_slot (trial);
          delay_list = add_to_delay_list (trial, delay_list);
@@ -1343,6 +1815,9 @@ try_merge_delay_insns (insn, thread)
   struct resources set, needed;
   rtx merged_insns = 0;
   int i;
+  int flags;
+
+  flags = get_jump_flags (delay_insn, JUMP_LABEL (delay_insn));
 
   CLEAR_RESOURCE (&needed);
   CLEAR_RESOURCE (&set);
@@ -1359,6 +1834,7 @@ try_merge_delay_insns (insn, thread)
   for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
     {
       rtx pat = PATTERN (trial);
+      rtx oldtrial = trial;
 
       next_trial = next_nonnote_insn (trial);
 
@@ -1376,16 +1852,22 @@ 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))
+         && 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;
            }
@@ -1400,7 +1882,7 @@ try_merge_delay_insns (insn, thread)
            mark_referenced_resources (next_to_match, &needed, 1);
        }
 
-      mark_set_resources (trial, &set, 1);
+      mark_set_resources (trial, &set, 0, 1);
       mark_referenced_resources (trial, &needed, 1);
     }
 
@@ -1412,6 +1894,11 @@ try_merge_delay_insns (insn, thread)
       && ! INSN_ANNULLED_BRANCH_P (XVECEXP (PATTERN (trial), 0, 0)))
     {
       rtx pat = PATTERN (trial);
+      rtx filled_insn = XVECEXP (pat, 0, 0);
+
+      /* Account for resources set/needed by the filled insn.  */
+      mark_set_resources (filled_insn, &set, 0, 1);
+      mark_referenced_resources (filled_insn, &needed, 1);
 
       for (i = 1; i < XVECLEN (pat, 0); i++)
        {
@@ -1424,7 +1911,7 @@ try_merge_delay_insns (insn, thread)
              && ! sets_cc0_p (PATTERN (dtrial))
 #endif
              && rtx_equal_p (PATTERN (next_to_match), PATTERN (dtrial))
-             && eligible_for_delay (delay_insn, slot_number - 1, dtrial))
+             && eligible_for_delay (delay_insn, slot_number - 1, dtrial, flags))
            {
              if (! annul_p)
                {
@@ -1449,7 +1936,7 @@ try_merge_delay_insns (insn, thread)
      merged insns.  Also clear the INSN_FROM_TARGET_P bit of each insn the
      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))
        {
@@ -1491,8 +1978,8 @@ try_merge_delay_insns (insn, thread)
    redundant insn, but the cost of splitting seems greater than the possible
    gain in rare cases.  */
 
-static int
-redundant_insn_p (insn, target, delay_list)
+static rtx
+redundant_insn (insn, target, delay_list)
      rtx insn;
      rtx target;
      rtx delay_list;
@@ -1509,8 +1996,7 @@ redundant_insn_p (insn, target, delay_list)
       if (GET_CODE (trial) == CODE_LABEL)
        return 0;
 
-      if (GET_CODE (trial) != INSN && GET_CODE (trial) != JUMP_INSN
-         && GET_CODE (trial) != JUMP_INSN)
+      if (GET_RTX_CLASS (GET_CODE (trial)) != 'i')
        continue;
 
       pat = PATTERN (trial);
@@ -1519,11 +2005,27 @@ redundant_insn_p (insn, target, delay_list)
 
       if (GET_CODE (pat) == SEQUENCE)
        {
-         /* Stop for a CALL and its delay slots because it difficult to track
-            its resource needs correctly.  */
+         /* Stop for a CALL and its delay slots because it is difficult to
+            track its resource needs correctly.  */
          if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN)
            return 0;
 
+         /* Stop for an INSN or JUMP_INSN with delayed effects and its delay
+            slots because it is difficult to track its resource needs 
+            correctly.  */
+
+#ifdef INSN_SETS_ARE_DELAYED
+         if (INSN_SETS_ARE_DELAYED (XVECEXP (pat, 0, 0)))
+           return 0; 
+#endif
+
+#ifdef INSN_REFERENCES_ARE_DELAYED
+         if (INSN_REFERENCES_ARE_DELAYED (XVECEXP (pat, 0, 0)))
+           return 0; 
+#endif
+
+         /* See if any of the insns in the delay slot match, updating
+            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))
@@ -1547,7 +2049,7 @@ redundant_insn_p (insn, target, delay_list)
 
   CLEAR_RESOURCE (&needed);
   CLEAR_RESOURCE (&set);
-  mark_set_resources (insn, &set, 1);
+  mark_set_resources (insn, &set, 0, 1);
   mark_referenced_resources (insn, &needed, 1);
 
   /* If TARGET is a SEQUENCE, get the main insn.  */
@@ -1567,6 +2069,7 @@ redundant_insn_p (insn, target, delay_list)
   /* Insns we pass may not set either NEEDED or SET, so merge them for
      simpler tests.  */
   needed.memory |= set.memory;
+  needed.unch_memory |= set.unch_memory;
   IOR_HARD_REG_SET (needed.regs, set.regs);
 
   /* This insn isn't redundant if it conflicts with an insn that either is
@@ -1606,6 +2109,19 @@ 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
+            is hard to track the resource needs properly, so give up.  */
+
+#ifdef INSN_SETS_ARE_DELAYED
+         if (INSN_SETS_ARE_DELAYED (XVECEXP (pat, 0, 0)))
+           return 0; 
+#endif
+
+#ifdef INSN_REFERENCES_ARE_DELAYED
+         if (INSN_REFERENCES_ARE_DELAYED (XVECEXP (pat, 0, 0)))
+           return 0; 
+#endif
+
          /* See if any of the insns in the delay slot match, updating
             resource requirements as we go.  */
          for (i = XVECLEN (pat, 0) - 1; i > 0; i--)
@@ -1620,7 +2136,7 @@ redundant_insn_p (insn, target, delay_list)
                {
                  /* Show that this insn will be used in the sequel.  */
                  INSN_FROM_TARGET_P (candidate) = 0;
-                 return 1;
+                 return candidate;
                }
 
              /* Unless this is an annulled insn from the target of a branch,
@@ -1642,7 +2158,7 @@ redundant_insn_p (insn, target, delay_list)
          /* See if TRIAL is the same as INSN.  */
          pat = PATTERN (trial);
          if (rtx_equal_p (pat, ipat))
-           return 1;
+           return trial;
 
          /* Can't go any further if TRIAL conflicts with INSN.  */
          if (insn_sets_resource_p (trial, &needed, 1))
@@ -1764,26 +2280,138 @@ update_block (insn, where)
   if (b != -1)
     bb_ticks[b]++;
 }
-\f
-/* Marks registers possibly live at the current place being scanned by
-   mark_target_live_regs.  Used only by next two function.    */
 
-static HARD_REG_SET current_live_regs;
+/* Similar to REDIRECT_JUMP except that we update the BB_TICKS entry for
+   the basic block containing the jump.  */
 
-/* Marks registers for which we have seen a REG_DEAD note but no assignment.
-   Also only used by the next two functions.  */
+static int
+reorg_redirect_jump (jump, nlabel)
+     rtx jump;
+     rtx nlabel;
+{
+  int b = find_basic_block (jump);
 
-static HARD_REG_SET pending_dead_regs;
+  if (b != -1)
+    bb_ticks[b]++;
 
-/* Utility function called from mark_target_live_regs via note_stores.
-   It deadens any CLOBBERed registers and livens any SET registers.  */
+  return redirect_jump (jump, nlabel);
+}
+
+/* Called when INSN is being moved forward into a delay slot of DELAYED_INSN.
+   We check every instruction between INSN and DELAYED_INSN for REG_DEAD notes
+   that reference values used in INSN.  If we find one, then we move the
+   REG_DEAD note to INSN.
+
+   This is needed to handle the case where an later insn (after INSN) has a
+   REG_DEAD note for a register used by INSN, and this later insn subsequently
+   gets moved before a CODE_LABEL because it is a redundant insn.  In this
+   case, mark_target_live_regs may be confused into thinking the register
+   is dead because it sees a REG_DEAD note immediately before a CODE_LABEL.  */
 
 static void
-update_live_status (dest, x)
-     rtx dest;
-     rtx x;
+update_reg_dead_notes (insn, delayed_insn)
+     rtx insn, delayed_insn;
 {
-  int first_regno, last_regno;
+  rtx p, link, next;
+
+  for (p = next_nonnote_insn (insn); p != delayed_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_referenced_p (XEXP (link, 0), PATTERN (insn)))
+         {
+           /* Move the REG_DEAD note from P to INSN.  */
+           remove_note (p, link);
+           XEXP (link, 1) = REG_NOTES (insn);
+           REG_NOTES (insn) = link;
+         }
+      }
+}
+
+/* Called when an insn redundant with start_insn is deleted.  If there
+   is a REG_DEAD note for the target of start_insn between start_insn
+   and stop_insn, then the REG_DEAD note needs to be deleted since the
+   value no longer dies there.
+
+   If the REG_DEAD note isn't deleted, then mark_target_live_regs may be
+   confused into thinking the register is dead.  */
+
+static void
+fix_reg_dead_note (start_insn, stop_insn)
+     rtx start_insn, stop_insn;
+{
+  rtx p, link, next;
+
+  for (p = next_nonnote_insn (start_insn); p != stop_insn;
+       p = next_nonnote_insn (p))
+    for (link = REG_NOTES (p); link; link = next)
+      {
+       next = XEXP (link, 1);
+
+       if (REG_NOTE_KIND (link) != REG_DEAD
+           || GET_CODE (XEXP (link, 0)) != REG)
+         continue;
+
+       if (reg_set_p (XEXP (link, 0), PATTERN (start_insn)))
+         {
+           remove_note (p, link);
+           return;
+         }
+      }
+}
+
+/* Delete any REG_UNUSED notes that exist on INSN but not on REDUNDANT_INSN.
+
+   This handles the case of udivmodXi4 instructions which optimize their
+   output depending on whether any REG_UNUSED notes are present.
+   we must make sure that INSN calculates as many results as REDUNDANT_INSN
+   does.  */
+
+static void
+update_reg_unused_notes (insn, redundant_insn)
+     rtx insn, redundant_insn;
+{
+  rtx p, link, next;
+
+  for (link = REG_NOTES (insn); link; link = next)
+    {
+      next = XEXP (link, 1);
+
+      if (REG_NOTE_KIND (link) != REG_UNUSED
+         || GET_CODE (XEXP (link, 0)) != REG)
+       continue;
+
+      if (! find_regno_note (redundant_insn, REG_UNUSED,
+                            REGNO (XEXP (link, 0))))
+       remove_note (insn, link);
+    }
+}
+\f
+/* Marks registers possibly live at the current place being scanned by
+   mark_target_live_regs.  Used only by next two function.    */
+
+static HARD_REG_SET current_live_regs;
+
+/* Marks registers for which we have seen a REG_DEAD note but no assignment.
+   Also only used by the next two functions.  */
+
+static HARD_REG_SET pending_dead_regs;
+
+/* Utility function called from mark_target_live_regs via note_stores.
+   It deadens any CLOBBERed registers and livens any SET registers.  */
+
+static void
+update_live_status (dest, x)
+     rtx dest;
+     rtx x;
+{
+  int first_regno, last_regno;
   int i;
 
   if (GET_CODE (dest) != REG
@@ -1833,6 +2461,188 @@ next_insn_no_annul (insn)
   return insn;
 }
 \f
+/* A subroutine of mark_target_live_regs.  Search forward from TARGET
+   looking for registers that are set before they are used.  These are dead. 
+   Stop after passing a few conditional jumps, and/or a small
+   number of unconditional branches.  */
+
+static rtx
+find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
+     rtx target;
+     struct resources *res;
+     rtx *jump_target;
+     int jump_count;
+     struct resources set, needed;
+{
+  HARD_REG_SET scratch;
+  rtx insn, next;
+  rtx jump_insn = 0;
+  int i;
+
+  for (insn = target; insn; insn = next)
+    {
+      rtx this_jump_insn = insn;
+
+      next = NEXT_INSN (insn);
+      switch (GET_CODE (insn))
+       {
+       case CODE_LABEL:
+         /* After a label, any pending dead registers that weren't yet
+            used can be made dead.  */
+         AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
+         AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
+         CLEAR_HARD_REG_SET (pending_dead_regs);
+
+         if (CODE_LABEL_NUMBER (insn) < max_label_num_after_reload)
+           {
+             /* All spill registers are dead at a label, so kill all of the
+                ones that aren't needed also.  */
+             COPY_HARD_REG_SET (scratch, used_spill_regs);
+             AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+             AND_COMPL_HARD_REG_SET (res->regs, scratch);
+           }
+         continue;
+
+       case BARRIER:
+       case NOTE:
+         continue;
+
+       case INSN:
+         if (GET_CODE (PATTERN (insn)) == USE)
+           {
+             /* If INSN is a USE made by update_block, we care about the
+                underlying insn.  Any registers set by the underlying insn
+                are live since the insn is being done somewhere else.  */
+             if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
+               mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
+
+             /* All other USE insns are to be ignored.  */
+             continue;
+           }
+         else if (GET_CODE (PATTERN (insn)) == CLOBBER)
+           continue;
+         else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+           {
+             /* An unconditional jump can be used to fill the delay slot
+                of a call, so search for a JUMP_INSN in any position.  */
+             for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+               {
+                 this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
+                 if (GET_CODE (this_jump_insn) == JUMP_INSN)
+                   break;
+               }
+           }
+       }
+
+      if (GET_CODE (this_jump_insn) == JUMP_INSN)
+       {
+         if (jump_count++ < 10)
+           {
+             if (simplejump_p (this_jump_insn)
+                 || GET_CODE (PATTERN (this_jump_insn)) == RETURN)
+               {
+                 next = JUMP_LABEL (this_jump_insn);
+                 if (jump_insn == 0)
+                   {
+                     jump_insn = insn;
+                     if (jump_target)
+                       *jump_target = JUMP_LABEL (this_jump_insn);
+                   }
+               }
+             else if (condjump_p (this_jump_insn)
+                      || condjump_in_parallel_p (this_jump_insn))
+               {
+                 struct resources target_set, target_res;
+                 struct resources fallthrough_res;
+
+                 /* We can handle conditional branches here by following
+                    both paths, and then IOR the results of the two paths
+                    together, which will give us registers that are dead
+                    on both paths.  Since this is expensive, we give it
+                    a much higher cost than unconditional branches.  The
+                    cost was chosen so that we will follow at most 1
+                    conditional branch.  */
+
+                 jump_count += 4;
+                 if (jump_count >= 10)
+                   break;
+
+                 mark_referenced_resources (insn, &needed, 1);
+
+                 /* For an annulled branch, mark_set_resources ignores slots
+                    filled by instructions from the target.  This is correct
+                    if the branch is not taken.  Since we are following both
+                    paths from the branch, we must also compute correct info
+                    if the branch is taken.  We do this by inverting all of
+                    the INSN_FROM_TARGET_P bits, calling mark_set_resources,
+                    and then inverting the INSN_FROM_TARGET_P bits again.  */
+
+                 if (GET_CODE (PATTERN (insn)) == SEQUENCE
+                     && INSN_ANNULLED_BRANCH_P (this_jump_insn))
+                   {
+                     for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+                       INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+                         = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+                     target_set = set;
+                     mark_set_resources (insn, &target_set, 0, 1);
+
+                     for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+                       INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+                         = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+                     mark_set_resources (insn, &set, 0, 1);
+                   }
+                 else
+                   {
+                     mark_set_resources (insn, &set, 0, 1);
+                     target_set = set;
+                   }
+
+                 target_res = *res;
+                 COPY_HARD_REG_SET (scratch, target_set.regs);
+                 AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+                 AND_COMPL_HARD_REG_SET (target_res.regs, scratch);
+
+                 fallthrough_res = *res;
+                 COPY_HARD_REG_SET (scratch, set.regs);
+                 AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+                 AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch);
+
+                 find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
+                                             &target_res, 0, jump_count,
+                                             target_set, needed);
+                 find_dead_or_set_registers (next,
+                                             &fallthrough_res, 0, jump_count,
+                                             set, needed);
+                 IOR_HARD_REG_SET (fallthrough_res.regs, target_res.regs);
+                 AND_HARD_REG_SET (res->regs, fallthrough_res.regs);
+                 break;
+               }
+             else
+               break;
+           }
+         else
+           {
+             /* Don't try this optimization if we expired our jump count
+                above, since that would mean there may be an infinite loop
+                in the function being compiled.  */
+             jump_insn = 0;
+             break;
+           }
+       }
+
+      mark_referenced_resources (insn, &needed, 1);
+      mark_set_resources (insn, &set, 0, 1);
+
+      COPY_HARD_REG_SET (scratch, set.regs);
+      AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+      AND_COMPL_HARD_REG_SET (res->regs, scratch);
+    }
+
+  return jump_insn;
+}
+
 /* Set the resources that are live at TARGET.
 
    If TARGET is zero, we refer to the end of the current function and can
@@ -1881,6 +2691,7 @@ mark_target_live_regs (target, res)
   struct target_info *tinfo;
   rtx insn, next;
   rtx jump_insn = 0;
+  rtx jump_target;
   HARD_REG_SET scratch;
   struct resources set, needed;
   int jump_count = 0;
@@ -1894,7 +2705,7 @@ mark_target_live_regs (target, res)
 
   /* We have to assume memory is needed, but the CC isn't.  */
   res->memory = 1;
-  res->volatil = 0;
+  res->volatil = res->unch_memory = 0;
   res->cc = 0;
 
   /* See if we have computed this value already.  */
@@ -2000,9 +2811,7 @@ mark_target_live_regs (target, res)
          /* If this insn is a USE made by update_block, we care about the
             underlying insn.  */
          if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE
-             && (GET_CODE (XEXP (PATTERN (insn), 0)) == INSN
-                 || GET_CODE (XEXP (PATTERN (insn), 0)) == CALL_INSN
-                 || GET_CODE (XEXP (PATTERN (insn), 0)) == JUMP_INSN))
+             && GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
              real_insn = XEXP (PATTERN (insn), 0);
 
          if (GET_CODE (real_insn) == CALL_INSN)
@@ -2014,6 +2823,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
@@ -2036,7 +2848,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)
            {
@@ -2075,13 +2888,20 @@ mark_target_live_regs (target, res)
                  }
            }
 
-         if (GET_CODE (real_insn) == CODE_LABEL)
+         else if (GET_CODE (real_insn) == CODE_LABEL)
            {
              /* A label clobbers the pending dead registers since neither
                 reload nor jump will propagate a value across a label.  */
              AND_COMPL_HARD_REG_SET (current_live_regs, pending_dead_regs);
              CLEAR_HARD_REG_SET (pending_dead_regs);
            }
+
+         /* The beginning of the epilogue corresponds to the end of the
+            RTL chain when there are no epilogue insns.  Certain resources
+            are implicitly required at that point.  */
+         else if (GET_CODE (real_insn) == NOTE
+                  && NOTE_LINE_NUMBER (real_insn) == NOTE_INSN_EPILOGUE_BEG)
+           IOR_HARD_REG_SET (current_live_regs, start_of_epilogue_needs.regs);
        }
 
       COPY_HARD_REG_SET (res->regs, current_live_regs);
@@ -2093,74 +2913,19 @@ 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 main_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
-             || GET_CODE (PATTERN (insn)) == CLOBBER)
-           continue;
-         if (GET_CODE (PATTERN (insn)) == SEQUENCE)
-           main_insn = XVECEXP (PATTERN (insn), 0, 0);
-       }
-
-      if (GET_CODE (main_insn) == JUMP_INSN)
-       {
-         if (jump_count++ < 10
-             && (simplejump_p (main_insn)
-                 || GET_CODE (PATTERN (main_insn)) == RETURN))
-           {
-             next = next_active_insn (JUMP_LABEL (main_insn));
-             if (jump_insn == 0)
-               jump_insn = insn;
-           }
-         else
-           break;
-       }
-
-      mark_referenced_resources (insn, &needed, 1);
-      mark_set_resources (insn, &set, 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)
     {
-      rtx jump_target = (GET_CODE (jump_insn) == INSN
-                        ? JUMP_LABEL (XVECEXP (PATTERN (jump_insn), 0, 0))
-                        : JUMP_LABEL (jump_insn));
       struct resources new_resources;
       rtx stop_insn = next_active_insn (jump_insn);
 
@@ -2177,7 +2942,7 @@ mark_target_live_regs (target, res)
          AND_COMPL_HARD_REG_SET (scratch, set.regs);
          IOR_HARD_REG_SET (new_resources.regs, scratch);
 
-         mark_set_resources (insn, &set, 1);
+         mark_set_resources (insn, &set, 0, 1);
        }
 
       AND_HARD_REG_SET (res->regs, new_resources.regs);
@@ -2203,16 +2968,18 @@ mark_target_live_regs (target, res)
 static void
 fill_simple_delay_slots (first, non_jumps_p)
      rtx first;
+     int non_jumps_p;
 {
   register rtx insn, pat, trial, next_trial;
-  register int i;
+  register int i, j;
   int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
   struct resources needed, set;
-  register int slots_to_fill, slots_filled;
+  int slots_to_fill, slots_filled;
   rtx delay_list;
 
   for (i = 0; i < num_unfilled_slots; i++)
     {
+      int flags;
       /* Get the next insn to fill.  If it has already had any slots assigned,
         we can't do anything with it.  Maybe we'll improve this later.  */
 
@@ -2224,16 +2991,73 @@ fill_simple_delay_slots (first, non_jumps_p)
          || (GET_CODE (insn) == JUMP_INSN && non_jumps_p)
          || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p))
        continue;
-
+     
+      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);
       if (slots_to_fill == 0)
        abort ();
 
       /* This insn needs, or can use, some delay slots.  SLOTS_TO_FILL
-        says how many.  After initialization, scan backwards from the
-        insn to search for a potential delay-slot candidate.  Stop
-        searching when a label or jump is hit.
-        
+        says how many.  After initialization, first try optimizing
+
+        call _foo              call _foo
+        nop                    add %o7,.-L1,%o7
+        b,a L1
+        nop
+
+        If this case applies, the delay slot of the call is filled with
+        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.
+
+        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 ((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 (*tmp == trial)
+           *tmp = 0;
+         {
+           rtx next = NEXT_INSN (trial);
+           rtx prev = PREV_INSN (trial);
+           if (prev)
+             NEXT_INSN (prev) = next;
+           if (next)
+             PREV_INSN (next) = prev;
+         }
+       }
+
+      /* Now, scan backwards from the insn to search for a potential
+        delay-slot candidate.  Stop searching when a label or jump is hit.
+
         For each candidate, if it is to go into the delay slot (moved
         forward in execution sequence), it must not need or set any resources
         that were set by later insns and must not set any resources that
@@ -2243,69 +3067,70 @@ fill_simple_delay_slots (first, non_jumps_p)
         (in which case the called routine, not the insn itself, is doing
         the setting).  */
 
-      slots_filled = 0;
-      delay_list = 0;
-      CLEAR_RESOURCE (&needed);
-      CLEAR_RESOURCE (&set);
-      mark_set_resources (insn, &set, 0);
-      mark_referenced_resources (insn, &needed, 0);
-
-      for (trial = prev_nonnote_insn (insn); ! stop_search_p (trial, 1);
-          trial = next_trial)
+      if (slots_filled < slots_to_fill)
        {
-         next_trial = prev_nonnote_insn (trial);
+         CLEAR_RESOURCE (&needed);
+         CLEAR_RESOURCE (&set);
+         mark_set_resources (insn, &set, 0, 0);
+         mark_referenced_resources (insn, &needed, 0);
 
-         /* This must be an INSN or CALL_INSN.  */
-         pat = PATTERN (trial);
+         for (trial = prev_nonnote_insn (insn); ! stop_search_p (trial, 1);
+              trial = next_trial)
+           {
+             next_trial = prev_nonnote_insn (trial);
 
-         /* USE and CLOBBER at this level was just for flow; ignore it.  */
-         if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
-           continue;
+             /* This must be an INSN or CALL_INSN.  */
+             pat = PATTERN (trial);
+
+             /* USE and CLOBBER at this level was just for flow; ignore it.  */
+             if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+               continue;
 
-         /* Check for resource conflict first, to avoid unnecessary 
-            splitting.  */
-         if (! insn_references_resource_p (trial, &set, 1)
-             && ! insn_sets_resource_p (trial, &set, 1)
-             && ! insn_sets_resource_p (trial, &needed, 1)
+             /* Check for resource conflict first, to avoid unnecessary 
+                splitting.  */
+             if (! insn_references_resource_p (trial, &set, 1)
+                 && ! insn_sets_resource_p (trial, &set, 1)
+                 && ! insn_sets_resource_p (trial, &needed, 1)
 #ifdef HAVE_cc0
-             /* Can't separate set of cc0 from its use.  */
-             && ! (reg_mentioned_p (cc0_rtx, pat)
-                   && ! sets_cc0_p (cc0_rtx, pat))
+                 /* Can't separate set of cc0 from its use.  */
+                 && ! (reg_mentioned_p (cc0_rtx, pat)
+                       && ! sets_cc0_p (cc0_rtx, pat))
 #endif
-             )
-           {
-             trial = try_split (pat, trial, 1);
-             next_trial = prev_nonnote_insn (trial);
-             if (eligible_for_delay (insn, slots_filled, trial))
+                 )
                {
-                 /* In this case, we are searching backward, so if we
-                    find insns to put on the delay list, we want
-                    to put them at the head, rather than the
-                    tail, of the list.  */
-
-                 delay_list = gen_rtx (INSN_LIST, VOIDmode,
-                                       trial, delay_list);
-                 update_block (trial, trial);
-                 delete_insn (trial);
-                 if (slots_to_fill == ++slots_filled)
-                   break;
-                 continue;
+                 trial = try_split (pat, trial, 1);
+                 next_trial = prev_nonnote_insn (trial);
+                 if (eligible_for_delay (insn, slots_filled, trial, flags))
+                   {
+                     /* In this case, we are searching backward, so if we
+                        find insns to put on the delay list, we want
+                        to put them at the head, rather than the
+                        tail, of the list.  */
+
+                     update_reg_dead_notes (trial, insn);
+                     delay_list = gen_rtx (INSN_LIST, VOIDmode,
+                                           trial, delay_list);
+                     update_block (trial, trial);
+                     delete_insn (trial);
+                     if (slots_to_fill == ++slots_filled)
+                       break;
+                     continue;
+                   }
                }
-           }
 
-         mark_set_resources (trial, &set, 1);
-         mark_referenced_resources (trial, &needed, 1);
+             mark_set_resources (trial, &set, 0, 1);
+             mark_referenced_resources (trial, &needed, 1);
+           }
        }
 
-      if (slots_filled == slots_to_fill)
-       /* happy.  */ ;
-
       /* If all needed slots haven't been filled, we come here.  */
 
       /* Try to optimize case of jumping around a single insn.  */
 #if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS)
-      else if (delay_list == 0
-              && GET_CODE (insn) == JUMP_INSN && condjump_p (insn))
+      if (slots_filled != slots_to_fill
+         && delay_list == 0
+         && GET_CODE (insn) == JUMP_INSN 
+         && (condjump_p (insn) || condjump_in_parallel_p (insn)))
        {
          delay_list = optimize_skip (insn);
          if (delay_list)
@@ -2313,38 +3138,27 @@ fill_simple_delay_slots (first, non_jumps_p)
        }
 #endif
 
-      /* @@ This would be a good place to optimize:
-
-        call _foo              call _foo
-        nop                    add %o7,.-L1,%o7
-        b,a L1
-        nop
-
-        Someday... */
-
       /* Try to get insns from beyond the insn needing the delay slot.
         These insns can neither set or reference resources set in insns being
         skipped, cannot set resources in the insn being skipped, and, if this
         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.  */
-
-      else if (GET_CODE (insn) != JUMP_INSN
-              || (condjump_p (insn) && ! simplejump_p (insn)
-                  && JUMP_LABEL (insn) != 0))
+        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) || 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);
@@ -2352,16 +3166,16 @@ fill_simple_delay_slots (first, non_jumps_p)
 
          if (GET_CODE (insn) == CALL_INSN)
            {
-             mark_set_resources (insn, &set, 1);
+             mark_set_resources (insn, &set, 0, 1);
              mark_referenced_resources (insn, &needed, 1);
              maybe_never = 1;
            }
-         else if (GET_CODE (insn) == JUMP_INSN)
+         else 
            {
-             /* 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;
+             mark_set_resources (insn, &set, 0, 1);
+             mark_referenced_resources (insn, &needed, 1);
+             if (GET_CODE (insn) == JUMP_INSN)
+               target = JUMP_LABEL (insn);
            }
 
          for (trial = next_nonnote_insn (insn); trial; trial = next_trial)
@@ -2370,22 +3184,8 @@ fill_simple_delay_slots (first, non_jumps_p)
 
              next_trial = next_nonnote_insn (trial);
 
-             if (GET_CODE (trial) == CODE_LABEL)
-               {
-                 passed_label = 1;
-
-                 /* If this is our target, see if we have seen all its uses.
-                    If so, indicate we have passed our target and ignore it.
-                    All other labels cause us to stop our search.  */
-                 if (trial == target && target_uses == 0)
-                   {
-                     target = 0;
-                     continue;
-                   }
-                 else
-                   break;
-               }
-             else if (GET_CODE (trial) == BARRIER)
+             if (GET_CODE (trial) == CODE_LABEL
+                 || GET_CODE (trial) == BARRIER)
                break;
 
              /* We must have an INSN, JUMP_INSN, or CALL_INSN.  */
@@ -2410,14 +3210,13 @@ fill_simple_delay_slots (first, non_jumps_p)
                {
                  if (target == 0)
                    break;
-                 else if (JUMP_LABEL (trial_delay) == target)
-                   target_uses--;
-                 else
+                 else if (JUMP_LABEL (trial_delay) != target)
                    {
                      mark_target_live_regs
                        (next_active_insn (JUMP_LABEL (trial_delay)),
                         &needed_at_jump);
                      needed.memory |= needed_at_jump.memory;
+                     needed.unch_memory |= needed_at_jump.unch_memory;
                      IOR_HARD_REG_SET (needed.regs, needed_at_jump.regs);
                    }
                }
@@ -2434,7 +3233,7 @@ fill_simple_delay_slots (first, non_jumps_p)
 #endif
                  && ! (maybe_never && may_trap_p (pat))
                  && (trial = try_split (pat, trial, 0))
-                 && eligible_for_delay (insn, slots_filled, trial))
+                 && eligible_for_delay (insn, slots_filled, trial, flags))
                {
                  next_trial = next_nonnote_insn (trial);
                  delay_list = add_to_delay_list (trial, delay_list);
@@ -2444,15 +3243,13 @@ 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;
                  continue;
                }
 
-             mark_set_resources (trial, &set, 1);
+             mark_set_resources (trial, &set, 0, 1);
              mark_referenced_resources (trial, &needed, 1);
 
              /* Ensure we don't put insns between the setting of cc and the
@@ -2461,14 +3258,16 @@ fill_simple_delay_slots (first, non_jumps_p)
              set.cc = 1;
 
              /* If this is a call or jump, we might not get here.  */
-             if (GET_CODE (trial) == CALL_INSN
-                 || GET_CODE (trial) == JUMP_INSN)
+             if (GET_CODE (trial_delay) == CALL_INSN
+                 || GET_CODE (trial_delay) == JUMP_INSN)
                maybe_never = 1;
            }
 
          /* If there are slots left to fill and our search was stopped by an
             unconditional branch, try the insn at the branch target.  We can
-            redirect the branch if it works.  */
+            redirect the branch if it works. 
+
+            Don't do this if the insn at the branch target is a branch.  */
          if (slots_to_fill != slots_filled
              && trial
              && GET_CODE (trial) == JUMP_INSN
@@ -2477,34 +3276,49 @@ 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)
 #ifdef HAVE_cc0
-             && ! (reg_mentioned_p (cc0_rtx, PATTERN (next_trial))
-                   && ! sets_cc0_p (PATTERN (next_trial)))
+             && ! reg_mentioned_p (cc0_rtx, PATTERN (next_trial))
 #endif
              && ! (maybe_never && may_trap_p (PATTERN (next_trial)))
              && (next_trial = try_split (PATTERN (next_trial), next_trial, 0))
-             && eligible_for_delay (insn, slots_filled, next_trial))
+             && eligible_for_delay (insn, slots_filled, next_trial, flags))
            {
              rtx new_label = next_active_insn (next_trial);
 
              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);
              slots_filled++;
-             redirect_jump (trial, new_label);
+             reorg_redirect_jump (trial, new_label);
 
              /* If we merged because we both jumped to the same place,
                 redirect the original insn also.  */
              if (target)
-               redirect_jump (insn, new_label);
+               reorg_redirect_jump (insn, new_label);
            }
        }
 
+      /* If this is an unconditional jump, then try to get insns from the
+        target of the jump.  */
+      if (GET_CODE (insn) == JUMP_INSN
+         && simplejump_p (insn)
+         && slots_filled != slots_to_fill)
+       delay_list
+         = fill_slots_from_thread (insn, const_true_rtx,
+                                   next_active_insn (JUMP_LABEL (insn)),
+                                   NULL, 1, 1,
+                                   own_thread_p (JUMP_LABEL (insn),
+                                                 JUMP_LABEL (insn), 0),
+                                   0, slots_to_fill, &slots_filled);
+
       if (delay_list)
        unfilled_slots_base[i]
          = emit_delay_sequence (insn, delay_list,
@@ -2529,9 +3343,35 @@ 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)
+#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))
     {
@@ -2543,6 +3383,7 @@ fill_simple_delay_slots (first, non_jumps_p)
 
       if (! insn_references_resource_p (trial, &set, 1)
          && ! insn_sets_resource_p (trial, &needed, 1)
+         && ! insn_sets_resource_p (trial, &set, 1)
 #ifdef HAVE_cc0
          /* Don't want to mess with cc0 here.  */
          && ! reg_mentioned_p (cc0_rtx, pat)
@@ -2571,7 +3412,7 @@ fill_simple_delay_slots (first, non_jumps_p)
            }
        }
 
-      mark_set_resources (trial, &set, 1);
+      mark_set_resources (trial, &set, 0, 1);
       mark_referenced_resources (trial, &needed, 1);
     }
 
@@ -2621,12 +3462,15 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
   rtx trial;
   int lose = 0;
   int must_annul = 0;
+  int flags;
 
   /* Validate our arguments.  */
   if ((condition == const_true_rtx && ! thread_if_true)
       || (! own_thread && ! thread_if_true))
     abort ();
 
+  flags = get_jump_flags (insn, JUMP_LABEL (insn));
+
   /* If our thread is the end of subroutine, we can't get any delay
      insns from that.  */
   if (thread == 0)
@@ -2663,7 +3507,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
        ! stop_search_p (trial, ! thread_if_true) && (! lose || own_thread);
        trial = next_nonnote_insn (trial))
     {
-      rtx pat;
+      rtx pat, old_trial;
 
       /* If we have passed a label, we no longer own this thread.  */
       if (GET_CODE (trial) == CODE_LABEL)
@@ -2687,18 +3531,31 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 #endif
          )
        {
+         rtx prior_insn;
+
          /* If TRIAL is redundant with some insn before INSN, we don't
             actually need to add it to the delay list; we can merely pretend
             we did.  */
-         if (redundant_insn_p (trial, insn, delay_list))
+         if (prior_insn = redundant_insn (trial, insn, delay_list))
            {
+             fix_reg_dead_note (prior_insn, insn);
              if (own_thread)
                {
                  update_block (trial, thread);
+                 if (trial == thread)
+                   {
+                     thread = next_active_insn (thread);
+                     if (new_thread == trial)
+                       new_thread = thread;
+                   }
+
                  delete_insn (trial);
                }
              else
-               new_thread = next_active_insn (trial);
+               {
+                 update_reg_unused_notes (prior_insn, trial);
+                 new_thread = next_active_insn (trial);
+               }
 
              continue;
            }
@@ -2710,9 +3567,14 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              || (! 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))
+             if (eligible_for_delay (insn, *pslots_filled, trial, flags))
                goto winner;
            }
          else if (0
@@ -2724,11 +3586,16 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 #endif
                   )
            {
+             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 ((thread_if_true
-                  ? eligible_for_annul_false (insn, *pslots_filled, trial)
-                  : eligible_for_annul_true (insn, *pslots_filled, trial)))
+                  ? eligible_for_annul_false (insn, *pslots_filled, trial, flags)
+                  : eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
                {
                  rtx temp;
 
@@ -2747,6 +3614,12 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
                  if (own_thread)
                    {
                      update_block (trial, thread);
+                     if (trial == thread)
+                       {
+                         thread = next_active_insn (thread);
+                         if (new_thread == trial)
+                           new_thread = thread;
+                       }
                      delete_insn (trial);
                    }
                  else
@@ -2768,8 +3641,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
                             && ! insn_sets_resource_p (new_thread, &needed, 1)
                             && ! insn_references_resource_p (new_thread,
                                                              &set, 1)
-                            && redundant_insn_p (new_thread, insn,
-                                                 delay_list))
+                            && redundant_insn (new_thread, insn, delay_list))
                        new_thread = next_active_insn (new_thread);
                      break;
                    }
@@ -2781,7 +3653,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 
       /* This insn can't go into a delay slot.  */
       lose = 1;
-      mark_set_resources (trial, &set, 1);
+      mark_set_resources (trial, &set, 0, 1);
       mark_referenced_resources (trial, &needed, 1);
 
       /* Ensure we don't put insns between the setting of cc and the comparison
@@ -2799,9 +3671,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
@@ -2812,6 +3686,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);
        }
@@ -2847,7 +3722,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
      depend on the destination register.  If so, try to place the opposite
      arithmetic insn after the jump insn and put the arithmetic insn in the
      delay slot.  If we can't do this, return.  */
-  if (delay_list == 0 && likely && new_thread && GET_CODE (new_thread) == INSN)
+  if (delay_list == 0 && likely && new_thread
+      && GET_CODE (new_thread) == INSN
+      && GET_CODE (PATTERN (new_thread)) != ASM_INPUT
+      && asm_noperands (PATTERN (new_thread)) < 0)
     {
       rtx pat = PATTERN (new_thread);
       rtx dest;
@@ -2857,7 +3735,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
       pat = PATTERN (trial);
 
       if (GET_CODE (trial) != INSN || GET_CODE (pat) != SET
-         || ! eligible_for_delay (insn, 0, trial))
+         || ! eligible_for_delay (insn, 0, trial, flags))
        return 0;
 
       dest = SET_DEST (pat), src = SET_SRC (pat);
@@ -2893,6 +3771,12 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          if (own_thread)
            {
              update_block (trial, thread);
+             if (trial == thread)
+               {
+                 thread = next_active_insn (thread);
+                 if (new_thread == trial)
+                   new_thread = thread;
+               }
              delete_insn (trial);
            }
          else
@@ -2922,7 +3806,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
 
       if (new_thread && GET_CODE (new_thread) == JUMP_INSN
          && (simplejump_p (new_thread)
-             || GET_CODE (PATTERN (new_thread)) == RETURN))
+             || GET_CODE (PATTERN (new_thread)) == RETURN)
+         && redirect_with_delay_list_safe_p (insn,
+                                             JUMP_LABEL (new_thread),
+                                             delay_list))
        new_thread = follow_jumps (JUMP_LABEL (new_thread));
 
       if (new_thread == 0)
@@ -2932,7 +3819,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
       else
        label = get_label_before (new_thread);
 
-      redirect_jump (insn, label);
+      reorg_redirect_jump (insn, label);
     }
 
   return delay_list;
@@ -2969,7 +3856,7 @@ fill_eager_delay_slots (first)
       if (insn == 0
          || INSN_DELETED_P (insn)
          || GET_CODE (insn) != JUMP_INSN
-         || ! condjump_p (insn))
+         || ! (condjump_p (insn) || condjump_in_parallel_p (insn)))
        continue;
 
       slots_to_fill = num_delay_slots (insn);
@@ -2983,7 +3870,7 @@ fill_eager_delay_slots (first)
       if (condition == 0)
        continue;
 
-      /* Get the next active fallthough and target insns and see if we own
+      /* Get the next active fallthrough and target insns and see if we own
         them.  Then see whether the branch is likely true.  We don't need
         to do a lot of this for unconditional branches.  */
 
@@ -3007,7 +3894,7 @@ fill_eager_delay_slots (first)
         target, then our fallthrough insns.  If it is not, expected to branch,
         try the other order.  */
 
-      if (prediction)
+      if (prediction > 0)
        {
          delay_list
            = fill_slots_from_thread (insn, condition, insn_at_target,
@@ -3082,6 +3969,7 @@ relax_delay_slots (first)
         the next insn, or jumps to a label that is not the last of a
         group of consecutive labels.  */
       if (GET_CODE (insn) == JUMP_INSN
+         && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && (target_label = JUMP_LABEL (insn)) != 0)
        {
          target_label = follow_jumps (target_label);
@@ -3090,14 +3978,15 @@ 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;
            }
 
          if (target_label != JUMP_LABEL (insn))
-           redirect_jump (insn, target_label);
+           reorg_redirect_jump (insn, target_label);
 
          /* See if this jump branches around a unconditional jump.
             If so, invert this jump and point it to the target of the
@@ -3147,13 +4036,14 @@ 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)
-         && ! mostly_true_jump (other,
-                                get_branch_condition (other,
-                                                      JUMP_LABEL (other))))
+         && 0 < mostly_true_jump (other,
+                                  get_branch_condition (other,
+                                                        JUMP_LABEL (other))))
        {
          rtx other_target = JUMP_LABEL (other);
+         target_label = JUMP_LABEL (insn);
 
          /* Increment the count of OTHER_TARGET, so it doesn't get deleted
             as we move the label.  */
@@ -3161,7 +4051,7 @@ relax_delay_slots (first)
            ++LABEL_NUSES (other_target);
 
          if (invert_jump (other, target_label))
-           redirect_jump (insn, other_target);
+           reorg_redirect_jump (insn, other_target);
 
          if (other_target)
            --LABEL_NUSES (other_target);
@@ -3178,7 +4068,7 @@ relax_delay_slots (first)
       /* See if the first insn in the delay slot is redundant with some
         previous insn.  Remove it from the delay slot if so; then set up
         to reprocess this insn.  */
-      if (redundant_insn_p (XVECEXP (pat, 0, 1), delay_insn, 0))
+      if (redundant_insn (XVECEXP (pat, 0, 1), delay_insn, 0))
        {
          delete_from_delay_slot (XVECEXP (pat, 0, 1));
          next = prev_active_insn (next);
@@ -3187,7 +4077,8 @@ relax_delay_slots (first)
 
       /* Now look only at the cases where we have a filled JUMP_INSN.  */
       if (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN
-         || ! condjump_p (XVECEXP (PATTERN (insn), 0, 0)))
+         || ! (condjump_p (XVECEXP (PATTERN (insn), 0, 0))
+               || condjump_in_parallel_p (XVECEXP (PATTERN (insn), 0, 0))))
        continue;
 
       target_label = JUMP_LABEL (delay_insn);
@@ -3197,13 +4088,19 @@ 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))
            {
-             redirect_jump (delay_insn, trial);
+             reorg_redirect_jump (delay_insn, trial);
              target_label = trial;
            }
 
@@ -3211,14 +4108,23 @@ 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);
-             redirect_jump (delay_insn, target_label);
+             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;
            }
@@ -3230,19 +4136,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 ();
-             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
@@ -3276,6 +4188,19 @@ relax_delay_slots (first)
          continue;
        }
 
+      /* See if this is an unconditional jump around a single insn which is
+        identical to the one in its delay slot.  In this case, we can just
+        delete the branch and the insn in its delay slot.  */
+      if (next && GET_CODE (next) == INSN
+         && prev_label (next_active_insn (next)) == target_label
+         && simplejump_p (insn)
+         && XVECLEN (pat, 0) == 2
+         && rtx_equal_p (PATTERN (next), PATTERN (XVECEXP (pat, 0, 1))))
+       {
+         delete_insn (insn);
+         continue;
+       }
+
       /* See if this jump (with its delay slots) branches around another
         jump (without delay slots).  If so, invert this jump and point
         it to the target of the second jump.  We cannot do this for
@@ -3293,20 +4218,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
@@ -3357,6 +4297,8 @@ make_return_insns (first)
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
+      int flags;
+
       /* Only look at filled JUMP_INSNs that go to the end of function
         label.  */
       if (GET_CODE (insn) != INSN
@@ -3368,11 +4310,16 @@ make_return_insns (first)
       pat = PATTERN (insn);
       jump_insn = XVECEXP (pat, 0, 0);
 
-      /* If we can't make the jump into a RETURN, redirect it to the best
+      /* If we can't make the jump into a RETURN, try to redirect it to the best
         RETURN and go on to the next insn.  */
-      if (! redirect_jump (jump_insn, NULL_RTX))
+      if (! reorg_redirect_jump (jump_insn, NULL_RTX))
        {
-         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;
        }
 
@@ -3380,6 +4327,7 @@ make_return_insns (first)
         It can if it has more or an equal number of slots and the contents
         of each is valid.  */
 
+      flags = get_jump_flags (jump_insn, JUMP_LABEL (jump_insn));
       slots = num_delay_slots (jump_insn);
       if (slots >= XVECLEN (pat, 0) - 1)
        {
@@ -3389,15 +4337,15 @@ make_return_insns (first)
                   (INSN_ANNULLED_BRANCH_P (jump_insn)
                    && INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)))
                   ? eligible_for_annul_false (jump_insn, i - 1,
-                                              XVECEXP (pat, 0, i)) :
+                                              XVECEXP (pat, 0, i), flags) :
 #endif
 #ifdef ANNUL_IFTRUE_SLOTS
                   (INSN_ANNULLED_BRANCH_P (jump_insn)
                    && ! INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)))
                   ? eligible_for_annul_true (jump_insn, i - 1,
-                                             XVECEXP (pat, 0, i)) :
+                                             XVECEXP (pat, 0, i), flags) :
 #endif
-                  eligible_for_delay (jump_insn, i -1, XVECEXP (pat, 0, i))))
+                  eligible_for_delay (jump_insn, i -1, XVECEXP (pat, 0, i), flags)))
              break;
        }
       else
@@ -3427,7 +4375,7 @@ make_return_insns (first)
       else
        /* It is probably more efficient to keep this with its current
           delay slot as a branch to a RETURN.  */
-       redirect_jump (jump_insn, real_return_label);
+       reorg_redirect_jump (jump_insn, real_return_label);
     }
 
   /* Now delete REAL_RETURN_LABEL if we never used it.  Then try to fill any
@@ -3447,7 +4395,7 @@ dbr_schedule (first, file)
      rtx first;
      FILE *file;
 {
-  rtx insn, next;
+  rtx insn, next, epilogue_insn = 0;
   int i;
 #if 0
   int old_flag_no_peephole = flag_no_peephole;
@@ -3461,11 +4409,21 @@ dbr_schedule (first, file)
   flag_no_peephole = old_flag_no_peephole;
 #endif
 
+  /* If the current function has no insns other than the prologue and 
+     epilogue, then do not try to fill any delay slots.  */
+  if (n_basic_blocks == 0)
+    return;
+
   /* Find the highest INSN_UID and allocate and initialize our map from
      INSN_UID's to position in code.  */
   for (max_uid = 0, insn = first; insn; insn = NEXT_INSN (insn))
-    if (INSN_UID (insn) > max_uid)
-      max_uid = INSN_UID (insn);
+    {
+      if (INSN_UID (insn) > max_uid)
+       max_uid = INSN_UID (insn);
+      if (GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
+       epilogue_insn = insn;
+    }
 
   uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int *));
   for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn))
@@ -3495,7 +4453,8 @@ dbr_schedule (first, file)
        obstack_ptr_grow (&unfilled_slots_obstack, insn);
 
       /* Ensure all jumps go to the last of a set of consecutive labels.  */
-      if (GET_CODE (insn) == JUMP_INSN && condjump_p (insn)
+      if (GET_CODE (insn) == JUMP_INSN 
+         && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && JUMP_LABEL (insn) != 0
          && ((target = prev_label (next_active_insn (JUMP_LABEL (insn))))
              != JUMP_LABEL (insn)))
@@ -3511,11 +4470,15 @@ 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)
 #endif
@@ -3527,12 +4490,38 @@ dbr_schedule (first, file)
   if (current_function_return_rtx != 0
       && GET_CODE (current_function_return_rtx) == REG)
     mark_referenced_resources (current_function_return_rtx,
-                              &end_of_function_needs, 0);
+                              &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
+     represented in the flow information as being dead just prior to
+     reaching the end of the function.  For example, the return of a value
+     might be represented by a USE of the return register immediately
+     followed by an unconditional jump to the return label where the
+     return label is the end of the RTL chain.  The end of the RTL chain
+     is then taken to mean that the return register is live.
+
+     This sequence is no longer maintained when epilogue instructions are
+     added to the RTL chain.  To reconstruct the original meaning, the
+     start of the epilogue (NOTE_INSN_EPILOGUE_BEG) is regarded as the
+     point where these registers become live (start_of_epilogue_needs).
+     If epilogue instructions are present, the registers set by those
+     instructions won't have been processed by flow.  Thus, those
+     registers are additionally required at the end of the RTL chain
+     (end_of_function_needs).  */
+
+  start_of_epilogue_needs = end_of_function_needs;
+
+  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.  */
   end_of_function_label = 0;
 
@@ -3540,14 +4529,15 @@ dbr_schedule (first, file)
   target_hash_table
     = (struct target_info **) alloca ((TARGET_HASH_PRIME
                                       * sizeof (struct target_info *)));
-  bzero (target_hash_table, TARGET_HASH_PRIME * sizeof (struct target_info *));
+  bzero ((char *) target_hash_table,
+        TARGET_HASH_PRIME * sizeof (struct target_info *));
 
   bb_ticks = (int *) alloca (n_basic_blocks * sizeof (int));
-  bzero (bb_ticks, n_basic_blocks * sizeof (int));
+  bzero ((char *) bb_ticks, n_basic_blocks * sizeof (int));
 
   /* Initialize the statistics for this function.  */
-  bzero (num_insns_needing_delays, sizeof num_insns_needing_delays);
-  bzero (num_filled_delays, sizeof num_filled_delays);
+  bzero ((char *) num_insns_needing_delays, sizeof num_insns_needing_delays);
+  bzero ((char *) num_filled_delays, sizeof num_filled_delays);
 
   /* Now do the delay slot filling.  Try everything twice in case earlier
      changes make more slots fillable.  */
@@ -3569,9 +4559,7 @@ dbr_schedule (first, file)
       next = NEXT_INSN (insn);
 
       if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE
-         && (GET_CODE (XEXP (PATTERN (insn), 0)) == INSN
-             || GET_CODE (XEXP (PATTERN (insn), 0)) == JUMP_INSN
-             || GET_CODE (XEXP (PATTERN (insn), 0)) == CALL_INSN))
+         && GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
        next = delete_insn (insn);
     }