OSDN Git Service

(DUCR.M,DUC.M): Defined.
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index a125a82..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.
 
@@ -129,6 +130,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "insn-attr.h"
 
+/* Import list of registers used as spill regs from reload.  */
+extern HARD_REG_SET used_spill_regs;
+
+/* Import highest label used in function at end of reload.  */
+extern int max_label_num_after_reload;
+
+
 #ifdef DELAY_SLOTS
 
 #define obstack_chunk_alloc xmalloc
@@ -162,14 +170,15 @@ static rtx *unfilled_firstobj;
 struct resources
 {
   char memory;                 /* Insn sets or needs a memory location.  */
-  char volatil;                        /* Insn sets or needs a volatile memory loc. */
+  char unch_memory;            /* Insn sets of needs a "unchanging" MEM.  */
+  char volatil;                        /* Insn sets or needs a volatile memory loc.  */
   char cc;                     /* Insn sets or needs the condition codes.  */
   HARD_REG_SET regs;           /* Which registers are set or needed.  */
 };
 
 /* Macro to clear all resources.  */
 #define CLEAR_RESOURCE(RES)    \
- do { (RES)->memory = (RES)->volatil = (RES)->cc = 0;  \
+ do { (RES)->memory = (RES)->unch_memory = (RES)->volatil = (RES)->cc = 0; \
       CLEAR_HARD_REG_SET ((RES)->regs); } while (0)
 
 /* Indicates what resources are required at the beginning of the epilogue.  */
@@ -229,6 +238,7 @@ 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));
@@ -243,11 +253,14 @@ static rtx steal_delay_list_from_fallthrough PROTO((rtx, rtx, rtx, rtx,
                                                    struct resources *,
                                                    int, int *, int *));
 static void try_merge_delay_insns PROTO((rtx, rtx));
-static int redundant_insn_p    PROTO((rtx, rtx, rtx));
+static rtx redundant_insn      PROTO((rtx, rtx, rtx));
 static int own_thread_p                PROTO((rtx, rtx, int));
 static int find_basic_block    PROTO((rtx));
 static void update_block       PROTO((rtx, rtx));
+static int reorg_redirect_jump PROTO((rtx, rtx));
 static void update_reg_dead_notes PROTO((rtx, rtx));
+static void fix_reg_dead_note PROTO((rtx, rtx));
+static void update_reg_unused_notes PROTO((rtx, rtx));
 static void update_live_status PROTO((rtx, rtx));
 static rtx next_insn_no_annul  PROTO((rtx));
 static void mark_target_live_regs PROTO((rtx, struct resources *));
@@ -257,6 +270,8 @@ static rtx fill_slots_from_thread PROTO((rtx, rtx, rtx, rtx, int, int,
 static void fill_eager_delay_slots PROTO((rtx));
 static void relax_delay_slots  PROTO((rtx));
 static void make_return_insns  PROTO((rtx));
+static int redirect_with_delay_slots_safe_p PROTO ((rtx, rtx, rtx));
+static int redirect_with_delay_list_safe_p PROTO ((rtx, rtx, rtx));
 \f
 /* Given X, some rtl, and RES, a pointer to a `struct resource', mark
    which resources are references by the insn.  If INCLUDE_CALLED_ROUTINE
@@ -305,7 +320,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
     case MEM:
       /* If this memory shouldn't change, it really isn't referencing
         memory.  */
-      if (! RTX_UNCHANGING_P (x))
+      if (RTX_UNCHANGING_P (x))
+       res->unch_memory = 1;
+      else
        res->memory = 1;
       res->volatil = MEM_VOLATILE_P (x);
 
@@ -319,6 +336,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
 
     case UNSPEC_VOLATILE:
     case ASM_INPUT:
+    case TRAP_IF:
       /* Traditional asm's are always volatile.  */
       res->volatil = 1;
       return;
@@ -374,11 +392,13 @@ mark_referenced_resources (x, res, include_delayed_effects)
          rtx insn = PREV_INSN (x);
          rtx sequence = 0;
          int seq_size = 0;
+         rtx next = NEXT_INSN (x);
          int i;
 
-         /* If we are part of a delay slot sequence, point at the SEQUENCE. */
+         /* If we are part of a delay slot sequence, point at the SEQUENCE.  */
          if (NEXT_INSN (insn) != x)
            {
+             next = NEXT_INSN (NEXT_INSN (insn));
              sequence = PATTERN (NEXT_INSN (insn));
              seq_size = XVECLEN (sequence, 0);
              if (GET_CODE (sequence) != SEQUENCE)
@@ -388,34 +408,53 @@ mark_referenced_resources (x, res, include_delayed_effects)
          res->memory = 1;
          SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM);
          if (frame_pointer_needed)
-           SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);
+           {
+             SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+             SET_HARD_REG_BIT (res->regs, HARD_FRAME_POINTER_REGNUM);
+#endif
+           }
 
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
            if (global_regs[i])
              SET_HARD_REG_BIT (res->regs, i);
 
-         /* Skip any labels between the CALL_INSN and possible USE insns.  */
-         while (GET_CODE (insn) == CODE_LABEL)
-           insn = PREV_INSN (insn);
+         /* Check for a NOTE_INSN_SETJMP.  If it exists, then we must
+            assume that this call can need any register.
 
-         for ( ; (insn && GET_CODE (insn) == INSN
-                  && GET_CODE (PATTERN (insn)) == USE);
-              insn = PREV_INSN (insn))
-           {
-             for (i = 1; i < seq_size; i++)
+            This is done to be more conservative about how we handle setjmp.
+            We assume that they both use and set all registers.  Using all
+            registers ensures that a register will not be considered dead
+            just because it crosses a setjmp call.  A register should be
+            considered dead only if the setjmp call returns non-zero.  */
+         if (next && GET_CODE (next) == NOTE
+             && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP)
+           SET_HARD_REG_SET (res->regs);
+
+         {
+           rtx link;
+
+           for (link = CALL_INSN_FUNCTION_USAGE (x);
+                link;
+                link = XEXP (link, 1))
+             if (GET_CODE (XEXP (link, 0)) == USE)
                {
-                 rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i));
-                 if (GET_CODE (slot_pat) == SET
-                     && rtx_equal_p (SET_DEST (slot_pat),
-                                     XEXP (PATTERN (insn), 0)))
-                   break;
+                 for (i = 1; i < seq_size; i++)
+                   {
+                     rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i));
+                     if (GET_CODE (slot_pat) == SET
+                         && rtx_equal_p (SET_DEST (slot_pat),
+                                         SET_DEST (XEXP (link, 0))))
+                       break;
+                   }
+                 if (i >= seq_size)
+                   mark_referenced_resources (SET_DEST (XEXP (link, 0)),
+                                              res, 0);
                }
-             if (i >= seq_size)
-               mark_referenced_resources (XEXP (PATTERN (insn), 0), res, 0);
-           }
+         }
        }
 
-      /* ... fall through to other INSN processing ... */
+      /* ... fall through to other INSN processing ...  */
 
     case INSN:
     case JUMP_INSN:
@@ -504,20 +543,29 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
       if (include_delayed_effects)
        {
          rtx next = NEXT_INSN (x);
+         rtx prev = PREV_INSN (x);
+         rtx link;
 
          res->cc = res->memory = 1;
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
            if (call_used_regs[i] || global_regs[i])
              SET_HARD_REG_BIT (res->regs, i);
 
-         /* Skip any possible labels between the CALL_INSN and CLOBBERs.  */
-         while (GET_CODE (next) == CODE_LABEL)
-           next = NEXT_INSN (next);
-
-         for (; (next && GET_CODE (next) == INSN
-                 && GET_CODE (PATTERN (next)) == CLOBBER);
-              next = NEXT_INSN (next))
-           mark_set_resources (XEXP (PATTERN (next), 0), res, 1, 0);
+         /* If X is part of a delay slot sequence, then NEXT should be
+            the first insn after the sequence.  */
+         if (NEXT_INSN (prev) != x)
+           next = NEXT_INSN (NEXT_INSN (prev));
+
+         for (link = CALL_INSN_FUNCTION_USAGE (x);
+              link; link = XEXP (link, 1))
+           if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+             mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1, 0);
+
+         /* Check for a NOTE_INSN_SETJMP.  If it exists, then we must
+            assume that this call can clobber any register.  */
+         if (next && GET_CODE (next) == NOTE
+             && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP)
+           SET_HARD_REG_SET (res->regs);
        }
 
       /* ... and also what it's RTL says it modifies, if anything.  */
@@ -581,12 +629,29 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
       if (in_dest)
        {
          res->memory = 1;
+         res->unch_memory = RTX_UNCHANGING_P (x);
          res->volatil = MEM_VOLATILE_P (x);
        }
 
       mark_set_resources (XEXP (x, 0), res, 0, 0);
       return;
 
+    case SUBREG:
+      if (in_dest)
+       {
+         if (GET_CODE (SUBREG_REG (x)) != REG)
+           mark_set_resources (SUBREG_REG (x), res,
+                               in_dest, include_delayed_effects);
+         else
+           {
+             int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+             int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+             for (i = regno; i < last_regno; i++)
+               SET_HARD_REG_BIT (res->regs, i);
+           }
+       }
+      return;
+
     case REG:
       if (in_dest)
         for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++)
@@ -656,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;
 
@@ -736,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,
@@ -749,8 +833,8 @@ find_end_label ()
       if (HAVE_return)
        {
          /* The return we make may have delay slots too.  */
-         rtx insn = gen_return();
-         emit_jump_insn (insn);
+         rtx insn = gen_return ();
+         insn = emit_jump_insn (insn);
          emit_barrier ();
           if (num_delay_slots (insn) > 0)
            obstack_ptr_grow (&unfilled_slots_obstack, insn);
@@ -786,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
@@ -878,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.  */
@@ -1105,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;
@@ -1121,6 +1227,7 @@ optimize_skip (insn)
 
     Non conditional branches return no direction information and
     are predicted as very likely taken.  */
+
 static int
 get_jump_flags (insn, label)
      rtx insn, label;
@@ -1134,10 +1241,10 @@ get_jump_flags (insn, label)
      If LABEL is zero, then there is no way to determine the branch
      direction.  */
   if (GET_CODE (insn) == JUMP_INSN
-      && condjump_p (insn)
+      && (condjump_p (insn) || condjump_in_parallel_p (insn))
       && INSN_UID (insn) <= max_uid
-      && INSN_UID (label) <= max_uid
-      && label != 0)
+      && 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;
@@ -1150,7 +1257,7 @@ get_jump_flags (insn, label)
 
      Non conditional branches are predicted as very likely taken.  */
   if (GET_CODE (insn) == JUMP_INSN
-      && condjump_p (insn))
+      && (condjump_p (insn) || condjump_in_parallel_p (insn)))
     {
       int prediction;
 
@@ -1163,12 +1270,9 @@ get_jump_flags (insn, label)
          case 1:
            flags |= ATTR_FLAG_likely;
            break;
-
          case 0:
            flags |= ATTR_FLAG_unlikely;
            break;
-         /* mostly_true_jump does not return -1 for very unlikely jumps
-            yet, but it should in the future.  */
          case -1:
            flags |= (ATTR_FLAG_very_unlikely | ATTR_FLAG_unlikely);
            break;
@@ -1183,10 +1287,57 @@ get_jump_flags (insn, label)
   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.  */
 
@@ -1196,42 +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 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; insn = NEXT_INSN (insn))
+  /* If branch probabilities are available, then use that number since it
+     always gives a correct answer.  */
+  if (flag_branch_probabilities)
     {
-      if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
-       insn = XVECEXP (PATTERN (insn), 0, 0);
-      if (GET_CODE (insn) == JUMP_INSN)
-       break;
+      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);;
+      if (note)
+       {
+         int prob = XINT (note, 0);
+
+         if (prob >= REG_BR_PROB_BASE * 9 / 10)
+           return 2;
+         else if (prob >= REG_BR_PROB_BASE / 2)
+           return 1;
+         else if (prob >= REG_BR_PROB_BASE / 10)
+           return 0;
+         else
+           return -1;
+       }
     }
 
-  if (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 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 (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 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)
+  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.  */
@@ -1265,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)]));;
 }
@@ -1283,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;
 
@@ -1339,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
@@ -1383,12 +1642,17 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
 
   /* We can't do anything if there are more delay slots in SEQ than we
      can handle, or if we don't know that it will be a taken branch.
-
      We know that it will be a taken branch if it is either an unconditional
-     branch or a conditional branch with a stricter branch condition.  */
+     branch or a conditional branch with a stricter branch condition.
+
+     Also, exit if the branch has more than one set, since then it is computing
+     other results that can't be ignored, e.g. the HPPA mov&branch instruction.
+     ??? It may be possible to move other sets into INSN in addition to
+     moving the instructions in the delay slots.  */
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
-      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0)))
+      || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))
+      || ! single_set (XVECEXP (seq, 0, 0)))
     return delay_list;
 
   for (i = 1; i < XVECLEN (seq, 0); i++)
@@ -1412,7 +1676,7 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
 
       /* If this insn was already done (usually in a previous delay slot),
         pretend we put it in our delay slot.  */
-      if (redundant_insn_p (trial, insn, new_delay_list))
+      if (redundant_insn (trial, insn, new_delay_list))
        continue;
 
       /* We will end up re-vectoring this branch, so compute flags
@@ -1502,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;
@@ -1553,7 +1817,7 @@ try_merge_delay_insns (insn, thread)
   int i;
   int flags;
 
-  flags = get_jump_flags (insn, JUMP_LABEL (insn));
+  flags = get_jump_flags (delay_insn, JUMP_LABEL (delay_insn));
 
   CLEAR_RESOURCE (&needed);
   CLEAR_RESOURCE (&set);
@@ -1570,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);
 
@@ -1587,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, 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;
            }
@@ -1623,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++)
        {
@@ -1660,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))
        {
@@ -1702,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;
@@ -1793,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
@@ -1859,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,
@@ -1881,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))
@@ -2004,6 +2281,22 @@ update_block (insn, where)
     bb_ticks[b]++;
 }
 
+/* Similar to REDIRECT_JUMP except that we update the BB_TICKS entry for
+   the basic block containing the jump.  */
+
+static int
+reorg_redirect_jump (jump, nlabel)
+     rtx jump;
+     rtx nlabel;
+{
+  int b = find_basic_block (jump);
+
+  if (b != -1)
+    bb_ticks[b]++;
+
+  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
@@ -2040,6 +2333,65 @@ update_reg_dead_notes (insn, delayed_insn)
          }
       }
 }
+
+/* Called when an insn redundant with start_insn is deleted.  If there
+   is a REG_DEAD note for the target of start_insn between start_insn
+   and stop_insn, then the REG_DEAD note needs to be deleted since the
+   value no longer dies there.
+
+   If the REG_DEAD note isn't deleted, then mark_target_live_regs may be
+   confused into thinking the register is dead.  */
+
+static void
+fix_reg_dead_note (start_insn, stop_insn)
+     rtx start_insn, stop_insn;
+{
+  rtx p, link, next;
+
+  for (p = next_nonnote_insn (start_insn); p != stop_insn;
+       p = next_nonnote_insn (p))
+    for (link = REG_NOTES (p); link; link = next)
+      {
+       next = XEXP (link, 1);
+
+       if (REG_NOTE_KIND (link) != REG_DEAD
+           || GET_CODE (XEXP (link, 0)) != REG)
+         continue;
+
+       if (reg_set_p (XEXP (link, 0), PATTERN (start_insn)))
+         {
+           remove_note (p, link);
+           return;
+         }
+      }
+}
+
+/* Delete any REG_UNUSED notes that exist on INSN but not on REDUNDANT_INSN.
+
+   This handles the case of udivmodXi4 instructions which optimize their
+   output depending on whether any REG_UNUSED notes are present.
+   we must make sure that INSN calculates as many results as REDUNDANT_INSN
+   does.  */
+
+static void
+update_reg_unused_notes (insn, redundant_insn)
+     rtx insn, redundant_insn;
+{
+  rtx p, link, next;
+
+  for (link = REG_NOTES (insn); link; link = next)
+    {
+      next = XEXP (link, 1);
+
+      if (REG_NOTE_KIND (link) != REG_UNUSED
+         || GET_CODE (XEXP (link, 0)) != REG)
+       continue;
+
+      if (! find_regno_note (redundant_insn, REG_UNUSED,
+                            REGNO (XEXP (link, 0))))
+       remove_note (insn, link);
+    }
+}
 \f
 /* Marks registers possibly live at the current place being scanned by
    mark_target_live_regs.  Used only by next two function.    */
@@ -2109,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
@@ -2171,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.  */
@@ -2289,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
@@ -2311,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)
            {
@@ -2375,92 +2913,18 @@ mark_target_live_regs (target, res)
        in use.  This should happen only extremely rarely.  */
     SET_HARD_REG_SET (res->regs);
 
-  /* Now step forward from TARGET looking for registers that are set before
-     they are used.  These are dead.  If we pass a label, any pending dead
-     registers that weren't yet used can be made dead.  Stop when we pass a
-     conditional JUMP_INSN; follow the first few unconditional branches.  */
-
   CLEAR_RESOURCE (&set);
   CLEAR_RESOURCE (&needed);
 
-  for (insn = target; insn; insn = next)
-    {
-      rtx this_jump_insn = insn;
-
-      next = NEXT_INSN (insn);
-      switch (GET_CODE (insn))
-       {
-       case CODE_LABEL:
-         AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
-         AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
-         CLEAR_HARD_REG_SET (pending_dead_regs);
-         continue;
-
-       case BARRIER:
-       case NOTE:
-         continue;
-
-       case INSN:
-         if (GET_CODE (PATTERN (insn)) == USE)
-           {
-             /* If INSN is a USE made by update_block, we care about the
-                underlying insn.  Any registers set by the underlying insn
-                are live since the insn is being done somewhere else.  */
-             if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
-               mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
-
-             /* All other USE insns are to be ignored.  */
-             continue;
-           }
-         else if (GET_CODE (PATTERN (insn)) == CLOBBER)
-           continue;
-         else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
-           {
-             /* An unconditional jump can be used to fill the delay slot
-                of a call, so search for a JUMP_INSN in any position.  */
-             for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
-               {
-                 this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
-                 if (GET_CODE (this_jump_insn) == JUMP_INSN)
-                   break;
-               }
-           }
-       }
-
-      if (GET_CODE (this_jump_insn) == JUMP_INSN)
-       {
-         if (jump_count++ < 10
-             && (simplejump_p (this_jump_insn)
-                 || GET_CODE (PATTERN (this_jump_insn)) == RETURN))
-           {
-             next = next_active_insn (JUMP_LABEL (this_jump_insn));
-             if (jump_insn == 0)
-               {
-                 jump_insn = insn;
-                 jump_target = JUMP_LABEL (this_jump_insn);
-               }
-           }
-         else
-           break;
-       }
-
-      mark_referenced_resources (insn, &needed, 1);
-      mark_set_resources (insn, &set, 0, 1);
-
-      COPY_HARD_REG_SET (scratch, set.regs);
-      AND_COMPL_HARD_REG_SET (scratch, needed.regs);
-      AND_COMPL_HARD_REG_SET (res->regs, scratch);
-    }
+  jump_insn = find_dead_or_set_registers (target, res, &jump_target, 0,
+                                         set, needed);
 
   /* If we hit an unconditional branch, we have another way of finding out
      what is live: we can see what is live at the branch target and include
      anything used but not set before the branch.  The only things that are
-     live are those that are live using the above test and the test below.
-
-     Don't try this if we expired our jump count above, since that would
-     mean there may be an infinite loop in the function being compiled.  */
+     live are those that are live using the above test and the test below.  */
 
-  if (jump_insn && jump_count < 10)
+  if (jump_insn)
     {
       struct resources new_resources;
       rtx stop_insn = next_active_insn (jump_insn);
@@ -2510,7 +2974,7 @@ fill_simple_delay_slots (first, non_jumps_p)
   register int i, j;
   int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
   struct resources needed, set;
-  register int slots_to_fill, slots_filled;
+  int slots_to_fill, slots_filled;
   rtx delay_list;
 
   for (i = 0; i < num_unfilled_slots; i++)
@@ -2528,7 +2992,10 @@ fill_simple_delay_slots (first, non_jumps_p)
          || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p))
        continue;
      
-      flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      if (GET_CODE (insn) == JUMP_INSN)
+       flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      else
+       flags = get_jump_flags (insn, NULL_RTX);
       slots_to_fill = num_delay_slots (insn);
       if (slots_to_fill == 0)
        abort ();
@@ -2545,24 +3012,39 @@ fill_simple_delay_slots (first, non_jumps_p)
         the unconditional jump.  This is done first to avoid having the
         delay slot of the call filled in the backward scan.  Also, since
         the unconditional jump is likely to also have a delay slot, that
-        insn must exist when it is subsequently scanned.  */
+        insn must exist when it is subsequently scanned.
+
+        This is tried on each insn with delay slots as some machines
+        have insns which perform calls, but are not represented as 
+        CALL_INSNs.  */
 
       slots_filled = 0;
       delay_list = 0;
 
-      if (GET_CODE (insn) == CALL_INSN
-         && (trial = next_active_insn (insn))
+      if ((trial = next_active_insn (insn))
          && GET_CODE (trial) == JUMP_INSN
          && simplejump_p (trial)
          && eligible_for_delay (insn, slots_filled, trial, flags)
          && no_labels_between_p (insn, trial))
        {
+         rtx *tmp;
          slots_filled++;
          delay_list = add_to_delay_list (trial, delay_list);
+
+         /* TRIAL may have had its delay slot filled, then unfilled.  When
+            the delay slot is unfilled, TRIAL is placed back on the unfilled
+            slots obstack.  Unfortunately, it is placed on the end of the
+            obstack, not in its original location.  Therefore, we must search
+            from entry i + 1 to the end of the unfilled slots obstack to
+            try and find TRIAL.  */
+         tmp = &unfilled_slots_base[i + 1];
+         while (*tmp != trial && tmp != unfilled_slots_next)
+           tmp++;
+
          /* Remove the unconditional jump from consideration for delay slot
-            filling and unthread it.  */
-         if (unfilled_slots_base[i + 1] == trial)
-           unfilled_slots_base[i + 1] = 0;
+            filling and unthread it.   */
+         if (*tmp == trial)
+           *tmp = 0;
          {
            rtx next = NEXT_INSN (trial);
            rtx prev = PREV_INSN (trial);
@@ -2647,7 +3129,8 @@ fill_simple_delay_slots (first, non_jumps_p)
 #if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS)
       if (slots_filled != slots_to_fill
          && delay_list == 0
-         && GET_CODE (insn) == JUMP_INSN && condjump_p (insn))
+         && GET_CODE (insn) == JUMP_INSN 
+         && (condjump_p (insn) || condjump_in_parallel_p (insn)))
        {
          delay_list = optimize_skip (insn);
          if (delay_list)
@@ -2661,24 +3144,21 @@ fill_simple_delay_slots (first, non_jumps_p)
         is a CALL_INSN (or a CALL_INSN is passed), cannot trap (because the
         call might not return).
 
-        If this is a conditional jump, see if it merges back to us early
-        enough for us to pick up insns from the merge point.  Don't do
-        this if there is another branch to our label unless we pass all of
-        them.
-
-        Another similar merge is if we jump to the same place that a
-        later unconditional jump branches to.  In that case, we don't
-        care about the number of uses of our label.  */
+        There used to be code which continued past the target label if
+        we saw all uses of the target label.  This code did not work,
+        because it failed to account for some instructions which were
+        both annulled and marked as from the target.  This can happen as a
+        result of optimize_skip.  Since this code was redundant with
+        fill_eager_delay_slots anyways, it was just deleted.  */
 
       if (slots_filled != slots_to_fill
           && (GET_CODE (insn) != JUMP_INSN
-             || (condjump_p (insn) && ! simplejump_p (insn)
+             || ((condjump_p (insn) || condjump_in_parallel_p (insn))
+                  && ! simplejump_p (insn)
                   && JUMP_LABEL (insn) != 0)))
        {
          rtx target = 0;
          int maybe_never = 0;
-         int passed_label = 0;
-         int target_uses;
          struct resources needed_at_jump;
 
          CLEAR_RESOURCE (&needed);
@@ -2695,13 +3175,7 @@ fill_simple_delay_slots (first, non_jumps_p)
              mark_set_resources (insn, &set, 0, 1);
              mark_referenced_resources (insn, &needed, 1);
              if (GET_CODE (insn) == JUMP_INSN)
-               {
-                 /* Get our target and show how many more uses we want to
-                    see before we hit the label.  */
-                 target = JUMP_LABEL (insn);
-                 target_uses = LABEL_NUSES (target) - 1;
-               }
-               
+               target = JUMP_LABEL (insn);
            }
 
          for (trial = next_nonnote_insn (insn); trial; trial = next_trial)
@@ -2710,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.  */
@@ -2750,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);
                    }
                }
@@ -2784,8 +3243,6 @@ fill_simple_delay_slots (first, non_jumps_p)
                    link_cc0_insns (trial);
 #endif
 
-                 if (passed_label)
-                   update_block (trial, trial);
                  delete_insn (trial);
                  if (slots_to_fill == ++slots_filled)
                    break;
@@ -2801,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
@@ -2817,6 +3276,7 @@ fill_simple_delay_slots (first, non_jumps_p)
              && (next_trial = next_active_insn (JUMP_LABEL (trial))) != 0
              && ! (GET_CODE (next_trial) == INSN
                    && GET_CODE (PATTERN (next_trial)) == SEQUENCE)
+             && GET_CODE (next_trial) != JUMP_INSN
              && ! insn_references_resource_p (next_trial, &set, 1)
              && ! insn_sets_resource_p (next_trial, &set, 1)
              && ! insn_sets_resource_p (next_trial, &needed, 1)
@@ -2831,19 +3291,34 @@ fill_simple_delay_slots (first, non_jumps_p)
 
              if (new_label != 0)
                new_label = get_label_before (new_label);
+             else
+               new_label = find_end_label ();
 
              delay_list 
                = add_to_delay_list (copy_rtx (next_trial), delay_list);
              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,
@@ -2868,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))
     {
@@ -2882,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)
@@ -3005,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)
@@ -3029,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;
            }
@@ -3052,7 +3567,12 @@ 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, flags))
                goto winner;
@@ -3066,7 +3586,12 @@ 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, flags)
@@ -3089,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
@@ -3110,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;
                    }
@@ -3141,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
@@ -3154,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);
        }
@@ -3189,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;
@@ -3235,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
@@ -3264,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)
@@ -3274,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;
@@ -3311,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);
@@ -3325,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.  */
 
@@ -3349,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,
@@ -3424,7 +3969,7 @@ relax_delay_slots (first)
         the next insn, or jumps to a label that is not the last of a
         group of consecutive labels.  */
       if (GET_CODE (insn) == JUMP_INSN
-         && condjump_p (insn)
+         && (condjump_p (insn) || condjump_in_parallel_p (insn))
          && (target_label = JUMP_LABEL (insn)) != 0)
        {
          target_label = follow_jumps (target_label);
@@ -3433,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
@@ -3490,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.  */
@@ -3504,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);
@@ -3521,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);
@@ -3530,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);
@@ -3540,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;
            }
 
@@ -3554,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;
            }
@@ -3573,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
@@ -3649,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
@@ -3726,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;
        }
 
@@ -3786,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
@@ -3820,6 +4409,11 @@ 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))
@@ -3859,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)))
@@ -3875,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
@@ -3894,7 +4493,11 @@ dbr_schedule (first, file)
                               &end_of_function_needs, 1);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (global_regs[i])
+    if (global_regs[i]
+#ifdef EPILOGUE_USES
+       || EPILOGUE_USES (i)
+#endif
+       )
       SET_HARD_REG_BIT (end_of_function_needs.regs, i);
 
   /* The registers required to be live at the end of the function are
@@ -3926,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.  */