OSDN Git Service

config:
[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 6648455..4005c0a 100644 (file)
@@ -1,5 +1,6 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
@@ -55,7 +56,7 @@ Boston, MA 02111-1307, USA.  */
    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 
+   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
@@ -139,7 +140,6 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "resource.h"
 
-
 #ifdef DELAY_SLOTS
 
 #define obstack_chunk_alloc xmalloc
@@ -352,7 +352,7 @@ find_end_label ()
                 || GET_CODE (PATTERN (insn)) == CLOBBER)))
     insn = PREV_INSN (insn);
 
-  /* When a target threads its epilogue we might already have a 
+  /* 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
@@ -374,22 +374,42 @@ find_end_label ()
     end_of_function_label = insn;
   else
     {
-      /* Otherwise, make a new label and emit a RETURN and BARRIER,
-        if needed.  */
       end_of_function_label = gen_label_rtx ();
       LABEL_NUSES (end_of_function_label) = 0;
-      emit_label (end_of_function_label);
-#ifdef HAVE_return
-      if (HAVE_return)
+      /* If the basic block reorder pass moves the return insn to
+        some other place try to locate it again and put our
+        end_of_function_label there.  */
+      while (insn && ! (GET_CODE (insn) == JUMP_INSN
+                       && (GET_CODE (PATTERN (insn)) == RETURN)))
+       insn = PREV_INSN (insn);
+      if (insn)
        {
-         /* 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);
+         insn = PREV_INSN (insn);
+
+         /* Put the label before an USE insns that may proceed the
+            RETURN insn.  */
+         while (GET_CODE (insn) == USE)
+           insn = PREV_INSN (insn);
+
+         emit_label_after (end_of_function_label, insn);
        }
+      else
+       {
+         /* Otherwise, make a new label and emit a RETURN and BARRIER,
+            if needed.  */
+         emit_label (end_of_function_label);
+#ifdef HAVE_return
+         if (HAVE_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
+       }
     }
 
   /* Show one additional use for this label so it won't go away until
@@ -430,7 +450,7 @@ emit_delay_sequence (insn, list, length)
   rtx delay_insn = copy_rtx (insn);
 
   /* If INSN is followed by a BARRIER, delete the BARRIER since it will only
-     confuse further processing.  Update LAST in case it was the last insn.  
+     confuse further processing.  Update LAST in case it was the last insn.
      We will put the BARRIER back in later.  */
   if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER)
     {
@@ -499,7 +519,7 @@ emit_delay_sequence (insn, list, length)
   if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == INSN
       && GET_CODE (PATTERN (NEXT_INSN (seq_insn))) == SEQUENCE)
     PREV_INSN (XVECEXP (PATTERN (NEXT_INSN (seq_insn)), 0, 0)) = seq_insn;
-    
+
   /* If there used to be a BARRIER, put it back.  */
   if (had_barrier)
     emit_barrier_after (seq_insn);
@@ -533,7 +553,7 @@ add_to_delay_list (insn, delay_list)
   XEXP (delay_list, 1) = add_to_delay_list (insn, XEXP (delay_list, 1));
 
   return delay_list;
-}   
+}
 \f
 /* Delete INSN from the delay slot of the insn that it is in, which may
    produce an insn with no delay slots.  Return the new insn.  */
@@ -732,7 +752,7 @@ optimize_skip (insn)
     {
       if (eligible_for_annul_false (insn, 0, trial, flags))
        {
-         if (invert_jump (insn, JUMP_LABEL (insn)))
+         if (invert_jump (insn, JUMP_LABEL (insn), 1))
            INSN_FROM_TARGET_P (trial) = 1;
          else if (! eligible_for_annul_true (insn, 0, trial, flags))
            return 0;
@@ -771,7 +791,6 @@ optimize_skip (insn)
 }
 #endif
 \f
-
 /*  Encode and return branch direction and prediction information for
     INSN assuming it will jump to LABEL.
 
@@ -795,15 +814,15 @@ get_jump_flags (insn, label)
       && INSN_UID (insn) <= max_uid
       && label != 0
       && INSN_UID (label) <= max_uid)
-    flags 
+    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.  
+     determine the branch prediction.
 
      Non conditional branches are predicted as very likely taken.  */
   if (GET_CODE (insn) == JUMP_INSN
@@ -814,21 +833,21 @@ get_jump_flags (insn, label)
       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;
+       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();
+       default:
+         abort ();
        }
     }
   else
@@ -861,7 +880,7 @@ rare_destination (insn)
        case CODE_LABEL:
          return 0;
        case BARRIER:
-         /* A BARRIER can either be after a JUMP_INSN or a CALL_INSN.  We 
+         /* 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.  */
@@ -899,30 +918,29 @@ mostly_true_jump (jump_insn, condition)
      rtx jump_insn, condition;
 {
   rtx target_label = JUMP_LABEL (jump_insn);
-  rtx insn;
+  rtx insn, note;
   int rare_dest = rare_destination (target_label);
   int rare_fallthrough = rare_destination (NEXT_INSN (jump_insn));
 
   /* If branch probabilities are available, then use that number since it
      always gives a correct answer.  */
-  if (flag_branch_probabilities)
+  note = find_reg_note (jump_insn, REG_BR_PROB, 0);
+  if (note)
     {
-      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);
-      if (note)
-       {
-         int prob = XINT (note, 0);
+      int prob = INTVAL (XEXP (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 (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;
     }
 
+  /* ??? Ought to use estimate_probability instead.  */
+
   /* 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
@@ -936,7 +954,7 @@ mostly_true_jump (jump_insn, condition)
     {
       /* 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 
+        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;
@@ -972,7 +990,7 @@ mostly_true_jump (jump_insn, condition)
       return 2;
     }
 
-  /* If we couldn't figure out what this jump was, assume it won't be 
+  /* If we couldn't figure out what this jump was, assume it won't be
      taken.  This should be rare.  */
   if (condition == 0)
     return 0;
@@ -992,7 +1010,7 @@ mostly_true_jump (jump_insn, condition)
     case LE:
     case LT:
       if (XEXP (condition, 1) == const0_rtx)
-        return 0;
+       return 0;
       break;
     case GE:
     case GT:
@@ -1025,7 +1043,7 @@ get_branch_condition (insn, target)
 {
   rtx pat = PATTERN (insn);
   rtx src;
-  
+
   if (condjump_in_parallel_p (insn))
     pat = XVECEXP (pat, 0, 0);
 
@@ -1115,7 +1133,7 @@ redirect_with_delay_slots_safe_p (jump, newlabel, seq)
           ? eligible_for_annul_true (jump, i - 1,
                                      XVECEXP (pat, 0, i), flags) :
 #endif
-          eligible_for_delay (jump, i -1, XVECEXP (pat, 0, i), flags)))
+          eligible_for_delay (jump, i - 1, XVECEXP (pat, 0, i), flags)))
       break;
 
   return (i == XVECLEN (pat, 0));
@@ -1168,18 +1186,17 @@ check_annul_list_true_false (annul_true_p, delay_list)
   if (delay_list)
     {
       for (temp = delay_list; temp; temp = XEXP (temp, 1))
-        {
-          rtx trial = XEXP (temp, 0);
-          if ((annul_true_p && INSN_FROM_TARGET_P (trial))
+       {
+         rtx trial = XEXP (temp, 0);
+
+         if ((annul_true_p && INSN_FROM_TARGET_P (trial))
              || (!annul_true_p && !INSN_FROM_TARGET_P (trial)))
            return 0;
-        }
+       }
     }
 
   return 1;
 }
-
 \f
 /* INSN branches to an insn whose pattern SEQ is a SEQUENCE.  Given that
    the condition tested by INSN is CONDITION and the resources shown in
@@ -1235,19 +1252,19 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
      moving the instructions in the delay slots.
 
      We can not steal the delay list if one of the instructions in the
-     current delay_list modifies the condition codes and the jump in the 
+     current delay_list modifies the condition codes and the jump in the
      sequence is a conditional jump. We can not do this because we can
      not change the direction of the jump because the condition codes
-     will effect the direction of the jump in the sequence. */
+     will effect the direction of the jump in the sequence.  */
 
   CLEAR_RESOURCE (&cc_set);
   for (temp = delay_list; temp; temp = XEXP (temp, 1))
     {
       rtx trial = XEXP (temp, 0);
 
-      mark_set_resources (trial, &cc_set, 0, 1);
+      mark_set_resources (trial, &cc_set, 0, MARK_SRC_DEST_CALL);
       if (insn_references_resource_p (XVECEXP (seq , 0, 0), &cc_set, 0))
-        return delay_list;
+       return delay_list;
     }
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
@@ -1327,13 +1344,13 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   return delay_list;
 }
 \f
-/* Similar to steal_delay_list_from_target except that SEQ is on the 
+/* Similar to steal_delay_list_from_target except that SEQ is on the
    fallthrough path of INSN.  Here we only do something if the delay insn
    of SEQ is an unconditional branch.  In that case we steal its delay slot
    for INSN since unconditional branches are much easier to fill.  */
 
 static rtx
-steal_delay_list_from_fallthrough (insn, condition, seq, 
+steal_delay_list_from_fallthrough (insn, condition, seq,
                                   delay_list, sets, needed, other_needed,
                                   slots_to_fill, pslots_filled, pannul_p)
      rtx insn, condition;
@@ -1406,7 +1423,6 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
     *pannul_p = 1;
   return delay_list;
 }
-
 \f
 /* Try merging insns starting at THREAD which match exactly the insns in
    INSN's delay list.
@@ -1444,9 +1460,9 @@ try_merge_delay_insns (insn, thread)
      will essentially disable this optimization.  This method is somewhat of
      a kludge, but I don't see a better way.)  */
   if (! annul_p)
-    for (i = 1 ; i < num_slots ; i++)
+    for (i = 1 ; i < num_slots; i++)
       if (XVECEXP (PATTERN (insn), 0, i))
-        mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, 1);
+       mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, 1);
 
   for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
     {
@@ -1497,7 +1513,7 @@ try_merge_delay_insns (insn, thread)
          next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
        }
 
-      mark_set_resources (trial, &set, 0, 1);
+      mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL);
       mark_referenced_resources (trial, &needed, 1);
     }
 
@@ -1512,7 +1528,7 @@ try_merge_delay_insns (insn, thread)
       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_set_resources (filled_insn, &set, 0, MARK_SRC_DEST_CALL);
       mark_referenced_resources (filled_insn, &needed, 1);
 
       for (i = 1; i < XVECLEN (pat, 0); i++)
@@ -1551,8 +1567,8 @@ try_merge_delay_insns (insn, thread)
            {
              /* Keep track of the set/referenced resources for the delay
                 slots of any trial insns we encounter.  */
-              mark_set_resources (dtrial, &set, 0, 1);
-              mark_referenced_resources (dtrial, &needed, 1);
+             mark_set_resources (dtrial, &set, 0, MARK_SRC_DEST_CALL);
+             mark_referenced_resources (dtrial, &needed, 1);
            }
        }
     }
@@ -1631,7 +1647,7 @@ redundant_insn (insn, target, delay_list)
       if (GET_CODE (trial) == CODE_LABEL)
        return 0;
 
-      if (GET_RTX_CLASS (GET_CODE (trial)) != 'i')
+      if (! INSN_P (trial))
        continue;
 
       pat = PATTERN (trial);
@@ -1646,17 +1662,17 @@ redundant_insn (insn, target, delay_list)
            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 
+            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; 
+           return 0;
 #endif
 
 #ifdef INSN_REFERENCES_ARE_DELAYED
          if (INSN_REFERENCES_ARE_DELAYED (XVECEXP (pat, 0, 0)))
-           return 0; 
+           return 0;
 #endif
 
          /* See if any of the insns in the delay slot match, updating
@@ -1686,7 +1702,7 @@ redundant_insn (insn, target, delay_list)
 
   CLEAR_RESOURCE (&needed);
   CLEAR_RESOURCE (&set);
-  mark_set_resources (insn, &set, 0, 1);
+  mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
   mark_referenced_resources (insn, &needed, 1);
 
   /* If TARGET is a SEQUENCE, get the main insn.  */
@@ -1751,12 +1767,12 @@ redundant_insn (insn, target, delay_list)
 
 #ifdef INSN_SETS_ARE_DELAYED
          if (INSN_SETS_ARE_DELAYED (XVECEXP (pat, 0, 0)))
-           return 0; 
+           return 0;
 #endif
 
 #ifdef INSN_REFERENCES_ARE_DELAYED
          if (INSN_REFERENCES_ARE_DELAYED (XVECEXP (pat, 0, 0)))
-           return 0; 
+           return 0;
 #endif
 
          /* See if any of the insns in the delay slot match, updating
@@ -1784,8 +1800,7 @@ redundant_insn (insn, target, delay_list)
                return 0;
            }
 
-
-         /* If the insn requiring the delay slot conflicts with INSN, we 
+         /* If the insn requiring the delay slot conflicts with INSN, we
             must stop.  */
          if (insn_sets_resource_p (XVECEXP (pat, 0, 0), &needed, 1))
            return 0;
@@ -1866,7 +1881,7 @@ update_block (insn, where)
      rtx insn;
      rtx where;
 {
-  /* Ignore if this was in a delay slot and it came from the target of 
+  /* Ignore if this was in a delay slot and it came from the target of
      a branch.  */
   if (INSN_FROM_TARGET_P (insn))
     return;
@@ -1888,7 +1903,7 @@ reorg_redirect_jump (jump, nlabel)
      rtx nlabel;
 {
   incr_ticks_for_insn (jump);
-  return redirect_jump (jump, nlabel);
+  return redirect_jump (jump, nlabel, 1);
 }
 
 /* Called when INSN is being moved forward into a delay slot of DELAYED_INSN.
@@ -2026,7 +2041,7 @@ fill_simple_delay_slots (non_jumps_p)
          || (GET_CODE (insn) == JUMP_INSN && non_jumps_p)
          || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p))
        continue;
-     
+
       /* It may have been that this insn used to need delay slots, but
         now doesn't; ignore in that case.  This can happen, for example,
         on the HP PA RISC, where the number of delay slots depends on
@@ -2062,7 +2077,7 @@ fill_simple_delay_slots (non_jumps_p)
         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 
+        have insns which perform calls, but are not represented as
         CALL_INSNs.  */
 
       slots_filled = 0;
@@ -2114,7 +2129,7 @@ fill_simple_delay_slots (non_jumps_p)
         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
         are needed for those insns.
-        
+
         The delay slot insn itself sets resources unless it is a call
         (in which case the called routine, not the insn itself, is doing
         the setting).  */
@@ -2123,7 +2138,7 @@ fill_simple_delay_slots (non_jumps_p)
        {
          CLEAR_RESOURCE (&needed);
          CLEAR_RESOURCE (&set);
-         mark_set_resources (insn, &set, 0, 0);
+         mark_set_resources (insn, &set, 0, MARK_SRC_DEST);
          mark_referenced_resources (insn, &needed, 0);
 
          for (trial = prev_nonnote_insn (insn); ! stop_search_p (trial, 1);
@@ -2138,7 +2153,7 @@ fill_simple_delay_slots (non_jumps_p)
              if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
                continue;
 
-             /* Check for resource conflict first, to avoid unnecessary 
+             /* Check for resource conflict first, to avoid unnecessary
                 splitting.  */
              if (! insn_references_resource_p (trial, &set, 1)
                  && ! insn_sets_resource_p (trial, &set, 1)
@@ -2169,7 +2184,7 @@ fill_simple_delay_slots (non_jumps_p)
                    }
                }
 
-             mark_set_resources (trial, &set, 0, 1);
+             mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL);
              mark_referenced_resources (trial, &needed, 1);
            }
        }
@@ -2180,7 +2195,7 @@ fill_simple_delay_slots (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 
+         && GET_CODE (insn) == JUMP_INSN
          && (condjump_p (insn) || condjump_in_parallel_p (insn)))
        {
          delay_list = optimize_skip (insn);
@@ -2203,10 +2218,10 @@ fill_simple_delay_slots (non_jumps_p)
         fill_eager_delay_slots anyways, it was just deleted.  */
 
       if (slots_filled != slots_to_fill
-          && (GET_CODE (insn) != JUMP_INSN
+         && (GET_CODE (insn) != JUMP_INSN
              || ((condjump_p (insn) || condjump_in_parallel_p (insn))
-                  && ! simplejump_p (insn)
-                  && JUMP_LABEL (insn) != 0)))
+                 && ! simplejump_p (insn)
+                 && JUMP_LABEL (insn) != 0)))
        {
          rtx target = 0;
          int maybe_never = 0;
@@ -2217,13 +2232,13 @@ fill_simple_delay_slots (non_jumps_p)
 
          if (GET_CODE (insn) == CALL_INSN)
            {
-             mark_set_resources (insn, &set, 0, 1);
+             mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
              mark_referenced_resources (insn, &needed, 1);
              maybe_never = 1;
            }
-         else 
+         else
            {
-             mark_set_resources (insn, &set, 0, 1);
+             mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL);
              mark_referenced_resources (insn, &needed, 1);
              if (GET_CODE (insn) == JUMP_INSN)
                target = JUMP_LABEL (insn);
@@ -2263,7 +2278,7 @@ fill_simple_delay_slots (non_jumps_p)
                    break;
                  else if (JUMP_LABEL (trial_delay) != target)
                    {
-                     rtx ninsn = 
+                     rtx ninsn =
                        next_active_insn (JUMP_LABEL (trial_delay));
 
                      mark_target_live_regs (get_insns (), ninsn,
@@ -2302,7 +2317,7 @@ fill_simple_delay_slots (non_jumps_p)
                  continue;
                }
 
-             mark_set_resources (trial, &set, 0, 1);
+             mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL);
              mark_referenced_resources (trial, &needed, 1);
 
              /* Ensure we don't put insns between the setting of cc and the
@@ -2318,7 +2333,7 @@ fill_simple_delay_slots (non_jumps_p)
 
          /* 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
@@ -2347,7 +2362,7 @@ fill_simple_delay_slots (non_jumps_p)
              else
                new_label = find_end_label ();
 
-             delay_list 
+             delay_list
                = add_to_delay_list (copy_rtx (next_trial), delay_list);
              slots_filled++;
              reorg_redirect_jump (trial, new_label);
@@ -2385,7 +2400,7 @@ fill_simple_delay_slots (non_jumps_p)
 
 #ifdef DELAY_SLOTS_FOR_EPILOGUE
   /* See if the epilogue needs any delay slots.  Try to fill them if so.
-     The only thing we can do is scan backwards from the end of the 
+     The only thing we can do is scan backwards from the end of the
      function.  If we did this in a previous pass, it is incorrect to do it
      again.  */
   if (current_function_epilogue_delay_list)
@@ -2419,7 +2434,7 @@ fill_simple_delay_slots (non_jumps_p)
     SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
 
 #ifdef EPILOGUE_USES
-  for (i = 0; i <FIRST_PSEUDO_REGISTER; i++)
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       if (EPILOGUE_USES (i))
        SET_HARD_REG_BIT (needed.regs, i);
@@ -2466,7 +2481,7 @@ fill_simple_delay_slots (non_jumps_p)
            }
        }
 
-      mark_set_resources (trial, &set, 0, 1);
+      mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL);
       mark_referenced_resources (trial, &needed, 1);
     }
 
@@ -2528,7 +2543,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
   /* If our thread is the end of subroutine, we can't get any delay
      insns from that.  */
   if (thread == 0)
-      return delay_list;
+    return delay_list;
 
   /* If this is an unconditional branch, nothing is needed at the
      opposite thread.  Otherwise, compute what is needed there.  */
@@ -2718,7 +2733,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, 0, 1);
+      mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL);
       mark_referenced_resources (trial, &needed, 1);
 
       /* Ensure we don't put insns between the setting of cc and the comparison
@@ -2807,7 +2822,8 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
       dest = SET_DEST (pat), src = SET_SRC (pat);
       if ((GET_CODE (src) == PLUS || GET_CODE (src) == MINUS)
          && rtx_equal_p (XEXP (src, 0), dest)
-         && ! reg_overlap_mentioned_p (dest, XEXP (src, 1)))
+         && ! reg_overlap_mentioned_p (dest, XEXP (src, 1))
+         && ! side_effects_p (pat))
        {
          rtx other = XEXP (src, 1);
          rtx new_arith;
@@ -3086,7 +3102,7 @@ relax_delay_slots (first)
              if (label)
                ++LABEL_NUSES (label);
 
-             if (invert_jump (insn, label))
+             if (invert_jump (insn, label, 1))
                {
                  delete_insn (next);
                  next = insn;
@@ -3101,7 +3117,7 @@ relax_delay_slots (first)
              continue;
            }
        }
-         
+
       /* If this is an unconditional jump and the previous insn is a
         conditional jump, try reversing the condition of the previous
         insn and swapping our targets.  The next pass might be able to
@@ -3122,16 +3138,8 @@ relax_delay_slots (first)
          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.  */
-         if (other_target)
-           ++LABEL_NUSES (other_target);
-
-         if (invert_jump (other, target_label))
+         if (invert_jump (other, target_label, 0))
            reorg_redirect_jump (insn, other_target);
-
-         if (other_target)
-           --LABEL_NUSES (other_target);
        }
 
       /* Now look only at cases where we have filled a delay slot.  */
@@ -3208,7 +3216,7 @@ relax_delay_slots (first)
          if (trial == 0 && target_label != 0)
            trial = find_end_label ();
 
-         if (trial != target_label 
+         if (trial != target_label
              && redirect_with_delay_slots_safe_p (delay_insn, trial, insn))
            {
              reorg_redirect_jump (delay_insn, trial);
@@ -3230,10 +3238,10 @@ relax_delay_slots (first)
                tmp = find_end_label ();
 
              /* Insert the special USE insn and update dataflow info.  */
-              update_block (trial, tmp);
+             update_block (trial, tmp);
 
              /* Now emit a label before the special USE insn, and
-                redirect our jump to the new label.  */ 
+                redirect our jump to the new label.  */
              target_label = get_label_before (PREV_INSN (tmp));
              reorg_redirect_jump (delay_insn, target_label);
              next = insn;
@@ -3253,7 +3261,7 @@ relax_delay_slots (first)
              if (target_label == 0)
                target_label = find_end_label ();
 
-             if (redirect_with_delay_slots_safe_p (delay_insn, target_label, 
+             if (redirect_with_delay_slots_safe_p (delay_insn, target_label,
                                                    insn))
                {
                  reorg_redirect_jump (delay_insn, target_label);
@@ -3329,7 +3337,9 @@ relax_delay_slots (first)
          if (label == 0)
            label = find_end_label ();
 
-         if (redirect_with_delay_slots_safe_p (delay_insn, label, insn))
+         /* find_end_label can generate a new label. Check this first.  */
+         if (no_labels_between_p (insn, next)
+             && redirect_with_delay_slots_safe_p (delay_insn, label, insn))
            {
              /* Be careful how we do this to avoid deleting code or labels
                 that are momentarily dead.  See similar optimization in
@@ -3337,7 +3347,7 @@ relax_delay_slots (first)
              if (old_label)
                ++LABEL_NUSES (old_label);
 
-             if (invert_jump (delay_insn, label))
+             if (invert_jump (delay_insn, label, 1))
                {
                  int i;
 
@@ -3398,7 +3408,7 @@ make_return_insns (first)
        real_return_label = get_label_before (insn);
        break;
       }
-  
+
   /* Show an extra usage of REAL_RETURN_LABEL so it won't go away if it
      was equal to END_OF_FUNCTION_LABEL.  */
   LABEL_NUSES (real_return_label)++;
@@ -3456,7 +3466,8 @@ make_return_insns (first)
                   ? eligible_for_annul_true (jump_insn, i - 1,
                                              XVECEXP (pat, 0, i), flags) :
 #endif
-                  eligible_for_delay (jump_insn, i -1, XVECEXP (pat, 0, i), flags)))
+                  eligible_for_delay (jump_insn, i - 1,
+                                      XVECEXP (pat, 0, i), flags)))
              break;
        }
       else
@@ -3520,7 +3531,7 @@ dbr_schedule (first, file)
   flag_no_peephole = old_flag_no_peephole;
 #endif
 
-  /* If the current function has no insns other than the prologue and 
+  /* 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;
@@ -3539,7 +3550,7 @@ dbr_schedule (first, file)
   uid_to_ruid = (int *) xmalloc ((max_uid + 1) * sizeof (int));
   for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn))
     uid_to_ruid[INSN_UID (insn)] = i;
-  
+
   /* Initialize the list of insns that need filling.  */
   if (unfilled_firstobj == 0)
     {
@@ -3559,17 +3570,17 @@ dbr_schedule (first, file)
          && (GET_CODE (PATTERN (insn)) == ADDR_VEC
              || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
        continue;
-    
+
       if (num_delay_slots (insn) > 0)
        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 
+      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)))
-       redirect_jump (insn, target);
+       redirect_jump (insn, target, 1);
     }
 
   init_resource_info (epilogue_insn);
@@ -3601,7 +3612,7 @@ dbr_schedule (first, file)
       next = NEXT_INSN (insn);
 
       if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE
-         && GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
+         && INSN_P (XEXP (PATTERN (insn), 0)))
        next = delete_insn (insn);
     }
 
@@ -3675,7 +3686,7 @@ dbr_schedule (first, file)
                  else
                    total_delay_slots[j]++;
                }
-              else if (num_delay_slots (insn) > 0)
+             else if (num_delay_slots (insn) > 0)
                total_delay_slots[0]++;
            }
        }
@@ -3720,7 +3731,7 @@ dbr_schedule (first, file)
       int pred_flags;
 
       if (GET_CODE (insn) == INSN)
-        {
+       {
          rtx pat = PATTERN (insn);
 
          if (GET_CODE (pat) == SEQUENCE)