OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / reorg.c
index 8cd4473..375d4f8 100644 (file)
@@ -1,5 +1,5 @@
 /* Perform instruction reorganizations for delay slot filling.
-   Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
    Hacked by Michael Tiemann (tiemann@cygnus.com).
 
@@ -61,6 +61,10 @@ Boston, MA 02111-1307, USA.  */
    we can hoist insns from the fall-through path for forward branches or
    steal insns from the target of backward branches.
 
+   The TMS320C3x and C4x have three branch delay slots.  When the three
+   slots are filled, the branch penalty is zero.  Most insns can fill the
+   delay slots except jump insns.
+
    Three techniques for filling delay slots have been implemented so far:
 
    (1) `fill_simple_delay_slots' is the simplest, most efficient way
@@ -115,9 +119,10 @@ Boston, MA 02111-1307, USA.  */
    The HP-PA can conditionally nullify insns, providing a similar
    effect to the ARM, differing mostly in which insn is "in charge".   */
 
-#include <stdio.h>
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
+#include "expr.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "hard-reg-set.h"
@@ -130,12 +135,6 @@ Boston, MA 02111-1307, 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
 
@@ -229,11 +228,11 @@ static int stop_search_p  PROTO((rtx, int));
 static int resource_conflicts_p        PROTO((struct resources *,
                                       struct resources *));
 static int insn_references_resource_p PROTO((rtx, struct resources *, int));
-static int insn_sets_resources_p PROTO((rtx, struct resources *, int));
+static int insn_sets_resource_p PROTO((rtx, struct resources *, int));
 static rtx find_end_label      PROTO((void));
-static rtx emit_delay_sequence PROTO((rtx, rtx, int, int));
+static rtx emit_delay_sequence PROTO((rtx, rtx, int));
 static rtx add_to_delay_list   PROTO((rtx, rtx));
-static void delete_from_delay_slot PROTO((rtx));
+static rtx delete_from_delay_slot PROTO((rtx));
 static void delete_scheduled_jump PROTO((rtx));
 static void note_delay_statistics PROTO((int, int));
 static rtx optimize_skip       PROTO((rtx));
@@ -263,18 +262,21 @@ static void fix_reg_dead_note PROTO((rtx, rtx));
 static void update_reg_unused_notes PROTO((rtx, rtx));
 static void update_live_status PROTO((rtx, rtx));
 static rtx next_insn_no_annul  PROTO((rtx));
+static rtx find_dead_or_set_registers PROTO ((rtx, struct resources *, rtx *,
+                                             int, struct resources,
+                                             struct resources));
 static void mark_target_live_regs PROTO((rtx, struct resources *));
-static void fill_simple_delay_slots PROTO((rtx, int));
+static void fill_simple_delay_slots PROTO((int));
 static rtx fill_slots_from_thread PROTO((rtx, rtx, rtx, rtx, int, int,
-                                        int, int, int, int *));
-static void fill_eager_delay_slots PROTO((rtx));
+                                        int, int, int *, rtx));
+static void fill_eager_delay_slots PROTO((void));
 static void relax_delay_slots  PROTO((rtx));
 static void make_return_insns  PROTO((rtx));
 static int redirect_with_delay_slots_safe_p PROTO ((rtx, rtx, rtx));
 static int redirect_with_delay_list_safe_p PROTO ((rtx, rtx, rtx));
 \f
 /* Given X, some rtl, and RES, a pointer to a `struct resource', mark
-   which resources are references by the insn.  If INCLUDE_CALLED_ROUTINE
+   which resources are references by the insn.  If INCLUDE_DELAYED_EFFECTS
    is TRUE, resources used by the called routine will be included for
    CALL_INSNs.  */
 
@@ -336,11 +338,14 @@ 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;
 
+    case TRAP_IF:
+      res->volatil = 1;
+      break;
+
     case ASM_OPERANDS:
       res->volatil = MEM_VOLATILE_P (x);
 
@@ -468,6 +473,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
       /* No special processing, just speed up.  */
       mark_referenced_resources (PATTERN (x), res, include_delayed_effects);
       return;
+
+    default:
+      break;
     }
 
   /* Process each sub-expression and flag what it needs.  */
@@ -487,9 +495,10 @@ mark_referenced_resources (x, res, include_delayed_effects)
       }
 }
 \f
-/* Given X, a part of an insn, and a pointer to a `struct resource', RES,
-   indicate which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE
-   is nonzero, also mark resources potentially set by the called routine.
+/* Given X, a part of an insn, and a pointer to a `struct resource',
+   RES, indicate which resources are modified by the insn. If
+   INCLUDE_DELAYED_EFFECTS is nonzero, also mark resources potentially
+   set by the called routine.
 
    If IN_DEST is nonzero, it means we are inside a SET.  Otherwise,
    objects are being referenced instead of set.
@@ -568,7 +577,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
            SET_HARD_REG_SET (res->regs);
        }
 
-      /* ... and also what it's RTL says it modifies, if anything.  */
+      /* ... and also what its RTL says it modifies, if anything.  */
 
     case JUMP_INSN:
     case INSN:
@@ -657,6 +666,9 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
         for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++)
          SET_HARD_REG_BIT (res->regs, REGNO (x) + i);
       return;
+
+    default:
+      break;
     }
 
   /* Process each sub-expression and flag what it needs.  */
@@ -740,7 +752,7 @@ resource_conflicts_p (res1, res2)
 }
 
 /* Return TRUE if any resource marked in RES, a `struct resources', is
-   referenced by INSN.  If INCLUDE_CALLED_ROUTINE is set, return if the called
+   referenced by INSN.  If INCLUDE_DELAYED_EFFECTS is set, return if the called
    routine is using those resources.
 
    We compute this by computing all the resources referenced by INSN and
@@ -762,7 +774,7 @@ insn_references_resource_p (insn, res, include_delayed_effects)
 }
 
 /* Return TRUE if INSN modifies resources that are marked in RES.
-   INCLUDE_CALLED_ROUTINE is set if the actions of that routine should be
+   INCLUDE_DELAYED_EFFECTS is set if the actions of that routine should be
    included.   CC0 is only modified if it is explicitly set; see comments
    in front of mark_set_resources for details.  */
 
@@ -860,19 +872,18 @@ find_end_label ()
    Returns the SEQUENCE that replaces INSN.  */
 
 static rtx
-emit_delay_sequence (insn, list, length, avail)
+emit_delay_sequence (insn, list, length)
      rtx insn;
      rtx list;
      int length;
-     int avail;
 {
   register int i = 1;
   register rtx li;
   int had_barrier = 0;
 
-  /* Allocate the the rtvec to hold the insns and the SEQUENCE.  */
+  /* Allocate the rtvec to hold the insns and the SEQUENCE.  */
   rtvec seqv = rtvec_alloc (length + 1);
-  rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);
+  rtx seq = gen_rtx_SEQUENCE (VOIDmode, seqv);
   rtx seq_insn = make_insn_raw (seq);
   rtx first = get_insns ();
   rtx last = get_last_insn ();
@@ -894,15 +905,22 @@ emit_delay_sequence (insn, list, length, avail)
   NEXT_INSN (seq_insn) = NEXT_INSN (insn);
   PREV_INSN (seq_insn) = PREV_INSN (insn);
 
+  if (insn != last)
+    PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;
+
+  if (insn != first)
+    NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;
+
+  /* Note the calls to set_new_first_and_last_insn must occur after
+     SEQ_INSN has been completely spliced into the insn stream.
+
+     Otherwise CUR_INSN_UID will get set to an incorrect value because
+     set_new_first_and_last_insn will not find SEQ_INSN in the chain.  */
   if (insn == last)
     set_new_first_and_last_insn (first, seq_insn);
-  else
-    PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;
 
   if (insn == first)
     set_new_first_and_last_insn (seq_insn, last);
-  else
-    NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;
 
   /* Build our SEQUENCE and rebuild the insn chain.  */
   XVECEXP (seq, 0, 0) = delay_insn;
@@ -963,7 +981,7 @@ add_to_delay_list (insn, delay_list)
      rtx delay_list;
 {
   /* If we have an empty list, just make a new list element.  If
-     INSN has it's block number recorded, clear it since we may
+     INSN has its block number recorded, clear it since we may
      be moving the insn to a new block.  */
 
   if (delay_list == 0)
@@ -978,7 +996,7 @@ add_to_delay_list (insn, delay_list)
       if (tinfo)
        tinfo->block = -1;
 
-      return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+      return gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
     }
 
   /* Otherwise this must be an INSN_LIST.  Add INSN to the end of the
@@ -988,10 +1006,10 @@ add_to_delay_list (insn, delay_list)
   return delay_list;
 }   
 \f
-/* Delete INSN from the the delay slot of the insn that it is in.  This may
+/* Delete INSN from the delay slot of the insn that it is in.  This may
    produce an insn without anything in its delay slots.  */
 
-static void
+static rtx
 delete_from_delay_slot (insn)
      rtx insn;
 {
@@ -1032,7 +1050,7 @@ delete_from_delay_slot (insn)
   /* If there are any delay insns, remit them.  Otherwise clear the
      annul flag.  */
   if (delay_list)
-    trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2, 0);
+    trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2);
   else
     INSN_ANNULLED_BRANCH_P (trial) = 0;
 
@@ -1040,6 +1058,8 @@ delete_from_delay_slot (insn)
 
   /* Show we need to fill this insn again.  */
   obstack_ptr_grow (&unfilled_slots_obstack, trial);
+
+  return trial;
 }
 \f
 /* Delete INSN, a JUMP_INSN.  If it is a conditional jump, we must track down
@@ -1324,6 +1344,9 @@ rare_destination (insn)
            next = JUMP_LABEL (insn);
          else
            return 0;
+
+       default:
+         break;
        }
     }
 
@@ -1354,7 +1377,7 @@ mostly_true_jump (jump_insn, condition)
      always gives a correct answer.  */
   if (flag_branch_probabilities)
     {
-      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);;
+      rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);
       if (note)
        {
          int prob = XINT (note, 0);
@@ -1446,6 +1469,9 @@ mostly_true_jump (jump_insn, condition)
       if (XEXP (condition, 1) == const0_rtx)
        return 1;
       break;
+
+    default:
+      break;
     }
 
   /* Predict backward branches usually take, forward branches usually not.  If
@@ -1495,9 +1521,9 @@ get_branch_condition (insn, target)
               || (GET_CODE (XEXP (src, 2)) == LABEL_REF
                   && XEXP (XEXP (src, 2), 0) == target))
           && XEXP (src, 1) == pc_rtx)
-    return gen_rtx (reverse_condition (GET_CODE (XEXP (src, 0))),
-                   GET_MODE (XEXP (src, 0)),
-                   XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
+    return gen_rtx_fmt_ee (reverse_condition (GET_CODE (XEXP (src, 0))),
+                          GET_MODE (XEXP (src, 0)),
+                          XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
 
   return 0;
 }
@@ -1537,7 +1563,7 @@ static int
 redirect_with_delay_slots_safe_p (jump, newlabel, seq)
      rtx jump, newlabel, seq;
 {
-  int flags, slots, i;
+  int flags, i;
   rtx pat = PATTERN (seq);
 
   /* Make sure all the delay slots of this jump would still
@@ -1598,6 +1624,31 @@ redirect_with_delay_list_safe_p (jump, newlabel, delay_list)
   return (li == NULL);
 }
 
+/* DELAY_LIST is a list of insns that have already been placed into delay
+   slots.  See if all of them have the same annulling status as ANNUL_TRUE_P.
+   If not, return 0; otherwise return 1.  */
+
+static int
+check_annul_list_true_false (annul_true_p, delay_list)
+     int annul_true_p;
+     rtx delay_list;
+{
+  rtx temp;
+
+  if (delay_list)
+    {
+      for (temp = delay_list; temp; temp = XEXP (temp, 1))
+        {
+          rtx trial = XEXP (temp, 0);
+          if ((annul_true_p && INSN_FROM_TARGET_P (trial))
+             || (!annul_true_p && !INSN_FROM_TARGET_P (trial)))
+           return 0;
+        }
+    }
+  return 1;
+}
+
 \f
 /* INSN branches to an insn whose pattern SEQ is a SEQUENCE.  Given that
    the condition tested by INSN is CONDITION and the resources shown in
@@ -1639,6 +1690,8 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   rtx new_delay_list = 0;
   int must_annul = *pannul_p;
   int i;
+  int used_annul = 0;
+  struct resources cc_set;
 
   /* We can't do anything if there are more delay slots in SEQ than we
      can handle, or if we don't know that it will be a taken branch.
@@ -1648,7 +1701,23 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
      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.  */
+     moving the instructions in the delay slots.
+
+     We can not steal the delay list if one of the instructions in the
+     current delay_list modifies the condition codes and the jump in the 
+     sequence is a conditional jump. We can not do this because we can
+     not change the direction of the jump because the condition codes
+     will effect the direction of the jump in the sequence. */
+
+  CLEAR_RESOURCE (&cc_set);
+  for (temp = delay_list; temp; temp = XEXP (temp, 1))
+    {
+      rtx trial = XEXP (temp, 0);
+
+      mark_set_resources (trial, &cc_set, 0, 1);
+      if (insn_references_resource_p (XVECEXP (seq , 0, 0), &cc_set, 0))
+        return delay_list;
+    }
 
   if (XVECLEN (seq, 0) - 1 > slots_remaining
       || ! condition_dominates_p (condition, XVECEXP (seq, 0, 0))
@@ -1688,9 +1757,15 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
          ? eligible_for_delay (insn, total_slots_filled, trial, flags)
-         : (must_annul = 1,
-            eligible_for_annul_false (insn, total_slots_filled, trial, flags)))
+         : (must_annul || (delay_list == NULL && new_delay_list == NULL))
+            && (must_annul = 1,
+                check_annul_list_true_false (0, delay_list)
+                && check_annul_list_true_false (0, new_delay_list)
+                && eligible_for_annul_false (insn, total_slots_filled,
+                                             trial, flags)))
        {
+         if (must_annul)
+           used_annul = 1;
          temp = copy_rtx (trial);
          INSN_FROM_TARGET_P (temp) = 1;
          new_delay_list = add_to_delay_list (temp, new_delay_list);
@@ -1709,7 +1784,8 @@ steal_delay_list_from_target (insn, condition, seq, delay_list,
   /* Add any new insns to the delay list and update the count of the
      number of slots filled.  */
   *pslots_filled = total_slots_filled;
-  *pannul_p = must_annul;
+  if (used_annul)
+    *pannul_p = 1;
 
   if (delay_list == 0)
     return new_delay_list;
@@ -1739,6 +1815,8 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
 {
   int i;
   int flags;
+  int must_annul = *pannul_p;
+  int used_annul = 0;
 
   flags = get_jump_flags (insn, JUMP_LABEL (insn));
 
@@ -1772,14 +1850,17 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
          continue;
        }
 
-      if (! *pannul_p
+      if (! must_annul
          && ((condition == const_true_rtx
               || (! insn_sets_resource_p (trial, other_needed, 0)
                   && ! may_trap_p (PATTERN (trial)))))
          ? eligible_for_delay (insn, *pslots_filled, trial, flags)
-         : (*pannul_p = 1,
-            eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
+         : (must_annul || delay_list == NULL) && (must_annul = 1,
+            check_annul_list_true_false (1, delay_list)
+            && eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
        {
+         if (must_annul)
+           used_annul = 1;
          delete_from_delay_slot (trial);
          delay_list = add_to_delay_list (trial, delay_list);
 
@@ -1790,8 +1871,11 @@ steal_delay_list_from_fallthrough (insn, condition, seq,
        break;
     }
 
+  if (used_annul)
+    *pannul_p = 1;
   return delay_list;
 }
+
 \f
 /* Try merging insns starting at THREAD which match exactly the insns in
    INSN's delay list.
@@ -1823,13 +1907,15 @@ try_merge_delay_insns (insn, thread)
   CLEAR_RESOURCE (&set);
 
   /* If this is not an annulling branch, take into account anything needed in
-     NEXT_TO_MATCH.  This prevents two increments from being incorrectly
+     INSN's delay slot.  This prevents two increments from being incorrectly
      folded into one.  If we are annulling, this would be the correct
      thing to do.  (The alternative, looking at things set in NEXT_TO_MATCH
      will essentially disable this optimization.  This method is somewhat of
      a kludge, but I don't see a better way.)  */
   if (! annul_p)
-    mark_referenced_resources (next_to_match, &needed, 1);
+    for (i = 1 ; i < num_slots ; i++)
+      if (XVECEXP (PATTERN (insn), 0, i))
+        mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, 1);
 
   for (trial = thread; !stop_search_p (trial, 1); trial = next_trial)
     {
@@ -1872,14 +1958,12 @@ try_merge_delay_insns (insn, thread)
              INSN_FROM_TARGET_P (next_to_match) = 0;
            }
          else
-           merged_insns = gen_rtx (INSN_LIST, VOIDmode, trial, merged_insns);
+           merged_insns = gen_rtx_INSN_LIST (VOIDmode, trial, merged_insns);
 
          if (++slot_number == num_slots)
            break;
 
          next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
-         if (! annul_p)
-           mark_referenced_resources (next_to_match, &needed, 1);
        }
 
       mark_set_resources (trial, &set, 0, 1);
@@ -1915,25 +1999,36 @@ try_merge_delay_insns (insn, thread)
            {
              if (! annul_p)
                {
+                 rtx new;
+
                  update_block (dtrial, thread);
-                 delete_from_delay_slot (dtrial);
+                 new = delete_from_delay_slot (dtrial);
+                 if (INSN_DELETED_P (thread))
+                   thread = new;
                  INSN_FROM_TARGET_P (next_to_match) = 0;
                }
              else
-               merged_insns = gen_rtx (INSN_LIST, SImode, dtrial,
-                                       merged_insns);
+               merged_insns = gen_rtx_INSN_LIST (SImode, dtrial,
+                                                 merged_insns);
 
              if (++slot_number == num_slots)
                break;
 
              next_to_match = XVECEXP (PATTERN (insn), 0, slot_number);
            }
+         else
+           {
+             /* Keep track of the set/referenced resources for the delay
+                slots of any trial insns we encounter.  */
+              mark_set_resources (dtrial, &set, 0, 1);
+              mark_referenced_resources (dtrial, &needed, 1);
+           }
        }
     }
 
   /* If all insns in the delay slot have been matched and we were previously
      annulling the branch, we need not any more.  In that case delete all the
-     merged insns.  Also clear the INSN_FROM_TARGET_P bit of each insn the
+     merged insns.  Also clear the INSN_FROM_TARGET_P bit of each insn in
      the delay list so that we know that it isn't only being used at the
      target.  */
   if (slot_number == num_slots && annul_p)
@@ -1942,8 +2037,12 @@ try_merge_delay_insns (insn, thread)
        {
          if (GET_MODE (merged_insns) == SImode)
            {
+             rtx new;
+
              update_block (XEXP (merged_insns, 0), thread);
-             delete_from_delay_slot (XEXP (merged_insns, 0));
+             new = delete_from_delay_slot (XEXP (merged_insns, 0));
+             if (INSN_DELETED_P (thread))
+               thread = new;
            }
          else
            {
@@ -1990,6 +2089,11 @@ redundant_insn (insn, target, delay_list)
   struct resources needed, set;
   int i;
 
+  /* If INSN has any REG_UNUSED notes, it can't match anything since we
+     are allowed to not actually assign to such a register.  */
+  if (find_reg_note (insn, REG_UNUSED, NULL_RTX) != 0)
+    return 0;
+
   /* Scan backwards looking for a match.  */
   for (trial = PREV_INSN (target); trial; trial = PREV_INSN (trial))
     {
@@ -2028,7 +2132,8 @@ redundant_insn (insn, target, delay_list)
             resource requirements as we go.  */
          for (i = XVECLEN (pat, 0) - 1; i > 0; i--)
            if (GET_CODE (XVECEXP (pat, 0, i)) == GET_CODE (insn)
-               && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat))
+               && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat)
+               && ! find_reg_note (XVECEXP (pat, 0, i), REG_UNUSED, NULL_RTX))
              break;
 
          /* If found a match, exit this loop early.  */
@@ -2036,7 +2141,8 @@ redundant_insn (insn, target, delay_list)
            break;
        }
 
-      else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat))
+      else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat)
+              && ! find_reg_note (trial, REG_UNUSED, NULL_RTX))
        break;
     }
 
@@ -2109,7 +2215,7 @@ redundant_insn (insn, target, delay_list)
          if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN)
            return 0;
 
-         /* If this this is an INSN or JUMP_INSN with delayed effects, it
+         /* If this is an INSN or JUMP_INSN with delayed effects, it
             is hard to track the resource needs properly, so give up.  */
 
 #ifdef INSN_SETS_ARE_DELAYED
@@ -2271,7 +2377,7 @@ update_block (insn, where)
   if (INSN_FROM_TARGET_P (insn))
     return;
 
-  emit_insn_before (gen_rtx (USE, VOIDmode, insn), where);
+  emit_insn_before (gen_rtx_USE (VOIDmode, insn), where);
 
   /* INSN might be making a value live in a block where it didn't use to
      be.  So recompute liveness information for this block.  */
@@ -2377,7 +2483,7 @@ static void
 update_reg_unused_notes (insn, redundant_insn)
      rtx insn, redundant_insn;
 {
-  rtx p, link, next;
+  rtx link, next;
 
   for (link = REG_NOTES (insn); link; link = next)
     {
@@ -2493,14 +2599,6 @@ find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
          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:
@@ -2532,6 +2630,9 @@ find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
                    break;
                }
            }
+
+       default:
+         break;
        }
 
       if (GET_CODE (this_jump_insn) == JUMP_INSN)
@@ -2689,12 +2790,11 @@ mark_target_live_regs (target, res)
   int b = -1;
   int i;
   struct target_info *tinfo;
-  rtx insn, next;
+  rtx insn;
   rtx jump_insn = 0;
   rtx jump_target;
   HARD_REG_SET scratch;
   struct resources set, needed;
-  int jump_count = 0;
 
   /* Handle end of function.  */
   if (target == 0)
@@ -2753,8 +2853,7 @@ mark_target_live_regs (target, res)
   if (b != -1)
     {
       regset regs_live = basic_block_live_at_start[b];
-      int offset, j;
-      REGSET_ELT_TYPE bit;
+      int j;
       int regno;
       rtx start_insn, stop_insn;
 
@@ -2762,26 +2861,18 @@ mark_target_live_regs (target, res)
         marked live, plus live pseudo regs that have been renumbered to
         hard regs.  */
 
-#ifdef HARD_REG_SET
-      current_live_regs = *regs_live;
-#else
-      COPY_HARD_REG_SET (current_live_regs, regs_live);
-#endif
+      REG_SET_TO_HARD_REG_SET (current_live_regs, regs_live);
 
-      for (offset = 0, i = 0; offset < regset_size; offset++)
-       {
-         if (regs_live[offset] == 0)
-           i += REGSET_ELT_BITS;
-         else
-           for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
-             if ((regs_live[offset] & bit)
-                 && (regno = reg_renumber[i]) >= 0)
-               for (j = regno;
-                    j < regno + HARD_REGNO_NREGS (regno,
-                                                  PSEUDO_REGNO_MODE (i));
-                    j++)
-                 SET_HARD_REG_BIT (current_live_regs, j);
-       }
+      EXECUTE_IF_SET_IN_REG_SET
+       (regs_live, FIRST_PSEUDO_REGISTER, i,
+        {
+          if ((regno = reg_renumber[i]) >= 0)
+            for (j = regno;
+                 j < regno + HARD_REGNO_NREGS (regno,
+                                               PSEUDO_REGNO_MODE (i));
+                 j++)
+              SET_HARD_REG_BIT (current_live_regs, j);
+        });
 
       /* Get starting and ending insn, handling the case where each might
         be a SEQUENCE.  */
@@ -2966,12 +3057,11 @@ mark_target_live_regs (target, res)
    through FINAL_SEQUENCE.  */
 
 static void
-fill_simple_delay_slots (first, non_jumps_p)
-     rtx first;
+fill_simple_delay_slots (non_jumps_p)
      int non_jumps_p;
 {
   register rtx insn, pat, trial, next_trial;
-  register int i, j;
+  register int i;
   int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
   struct resources needed, set;
   int slots_to_fill, slots_filled;
@@ -2997,8 +3087,20 @@ fill_simple_delay_slots (first, non_jumps_p)
       else
        flags = get_jump_flags (insn, NULL_RTX);
       slots_to_fill = num_delay_slots (insn);
+
+      /* Some machine description have defined instructions to have
+        delay slots only in certain circumstances which may depend on
+        nearby insns (which change due to reorg's actions).
+
+        For example, the PA port normally has delay slots for unconditional
+        jumps.
+
+        However, the PA port claims such jumps do not have a delay slot
+        if they are immediate successors of certain CALL_INSNs.  This
+        allows the port to favor filling the delay slot of the call with
+        the unconditional jump.  */
       if (slots_to_fill == 0)
-       abort ();
+       continue;
 
       /* This insn needs, or can use, some delay slots.  SLOTS_TO_FILL
         says how many.  After initialization, first try optimizing
@@ -3094,7 +3196,7 @@ fill_simple_delay_slots (first, non_jumps_p)
 #ifdef HAVE_cc0
                  /* Can't separate set of cc0 from its use.  */
                  && ! (reg_mentioned_p (cc0_rtx, pat)
-                       && ! sets_cc0_p (cc0_rtx, pat))
+                       && ! sets_cc0_p (pat))
 #endif
                  )
                {
@@ -3108,8 +3210,8 @@ fill_simple_delay_slots (first, non_jumps_p)
                         tail, of the list.  */
 
                      update_reg_dead_notes (trial, insn);
-                     delay_list = gen_rtx (INSN_LIST, VOIDmode,
-                                           trial, delay_list);
+                     delay_list = gen_rtx_INSN_LIST (VOIDmode,
+                                                     trial, delay_list);
                      update_block (trial, trial);
                      delete_insn (trial);
                      if (slots_to_fill == ++slots_filled)
@@ -3317,12 +3419,12 @@ fill_simple_delay_slots (first, non_jumps_p)
                                    NULL, 1, 1,
                                    own_thread_p (JUMP_LABEL (insn),
                                                  JUMP_LABEL (insn), 0),
-                                   0, slots_to_fill, &slots_filled);
+                                   slots_to_fill, &slots_filled,
+                                   delay_list);
 
       if (delay_list)
        unfilled_slots_base[i]
-         = emit_delay_sequence (insn, delay_list,
-                                slots_filled, slots_to_fill);
+         = emit_delay_sequence (insn, delay_list, slots_filled);
 
       if (slots_to_fill == slots_filled)
        unfilled_slots_base[i] = 0;
@@ -3357,7 +3459,8 @@ fill_simple_delay_slots (first, non_jumps_p)
       SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
 #endif
 #ifdef EXIT_IGNORE_STACK
-      if (! EXIT_IGNORE_STACK)
+      if (! EXIT_IGNORE_STACK
+         || current_function_sp_is_unchanging)
 #endif
        SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
     }
@@ -3397,8 +3500,8 @@ fill_simple_delay_slots (first, non_jumps_p)
                 insns we find on the head of the list.  */
 
              current_function_epilogue_delay_list
-               = gen_rtx (INSN_LIST, VOIDmode, trial,
-                          current_function_epilogue_delay_list);
+               = gen_rtx_INSN_LIST (VOIDmode, trial,
+                                    current_function_epilogue_delay_list);
              mark_referenced_resources (trial, &end_of_function_needs, 1);
              update_block (trial, trial);
              delete_insn (trial);
@@ -3446,18 +3549,18 @@ fill_simple_delay_slots (first, non_jumps_p)
 
 static rtx
 fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
-                       thread_if_true, own_thread, own_opposite_thread,
-                       slots_to_fill, pslots_filled)
+                       thread_if_true, own_thread,
+                       slots_to_fill, pslots_filled, delay_list)
      rtx insn;
      rtx condition;
      rtx thread, opposite_thread;
      int likely;
      int thread_if_true;
-     int own_thread, own_opposite_thread;
+     int own_thread;
      int slots_to_fill, *pslots_filled;
+     rtx delay_list;
 {
   rtx new_thread;
-  rtx delay_list = 0;
   struct resources opposite_needed, set, needed;
   rtx trial;
   int lose = 0;
@@ -3474,7 +3577,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
   /* If our thread is the end of subroutine, we can't get any delay
      insns from that.  */
   if (thread == 0)
-    return 0;
+      return delay_list;
 
   /* If this is an unconditional branch, nothing is needed at the
      opposite thread.  Otherwise, compute what is needed there.  */
@@ -3536,7 +3639,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          /* 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 (prior_insn = redundant_insn (trial, insn, delay_list))
+         if ((prior_insn = redundant_insn (trial, insn, delay_list)))
            {
              fix_reg_dead_note (prior_insn, insn);
              if (own_thread)
@@ -3563,9 +3666,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
          /* There are two ways we can win:  If TRIAL doesn't set anything
             needed at the opposite thread and can't trap, or if it can
             go into an annulled delay slot.  */
-         if (condition == const_true_rtx
-             || (! insn_sets_resource_p (trial, &opposite_needed, 1)
-                 && ! may_trap_p (pat)))
+         if (!must_annul
+             && (condition == const_true_rtx
+                 || (! insn_sets_resource_p (trial, &opposite_needed, 1)
+                     && ! may_trap_p (pat))))
            {
              old_trial = trial;
              trial = try_split (pat, trial, 0);
@@ -3593,9 +3697,11 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
              if (thread == old_trial)
                thread = trial;
              pat = PATTERN (trial);
-             if ((thread_if_true
-                  ? eligible_for_annul_false (insn, *pslots_filled, trial, flags)
-                  : eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
+             if ((must_annul || delay_list == NULL) && (thread_if_true
+                  ? check_annul_list_true_false (0, delay_list)
+                    && eligible_for_annul_false (insn, *pslots_filled, trial, flags)
+                  : check_annul_list_true_false (1, delay_list)
+                    && eligible_for_annul_true (insn, *pslots_filled, trial, flags)))
                {
                  rtx temp;
 
@@ -3641,8 +3747,16 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
                             && ! insn_sets_resource_p (new_thread, &needed, 1)
                             && ! insn_references_resource_p (new_thread,
                                                              &set, 1)
-                            && redundant_insn (new_thread, insn, delay_list))
-                       new_thread = next_active_insn (new_thread);
+                            && (prior_insn
+                                = redundant_insn (new_thread, insn,
+                                                  delay_list)))
+                       {
+                         /* We know we do not own the thread, so no need
+                            to call update_block and delete_insn.  */
+                         fix_reg_dead_note (prior_insn, insn);
+                         update_reg_unused_notes (prior_insn, new_thread);
+                         new_thread = next_active_insn (new_thread);
+                       }
                      break;
                    }
 
@@ -3751,18 +3865,17 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
             the negated constant.  Otherwise, reverse the sense of the
             arithmetic.  */
          if (GET_CODE (other) == CONST_INT)
-           new_arith = gen_rtx (GET_CODE (src), GET_MODE (src), dest,
-                                negate_rtx (GET_MODE (src), other));
+           new_arith = gen_rtx_fmt_ee (GET_CODE (src), GET_MODE (src), dest,
+                                       negate_rtx (GET_MODE (src), other));
          else
-           new_arith = gen_rtx (GET_CODE (src) == PLUS ? MINUS : PLUS,
-                                GET_MODE (src), dest, other);
+           new_arith = gen_rtx_fmt_ee (GET_CODE (src) == PLUS ? MINUS : PLUS,
+                                       GET_MODE (src), dest, other);
 
-         ninsn = emit_insn_after (gen_rtx (SET, VOIDmode, dest, new_arith),
+         ninsn = emit_insn_after (gen_rtx_SET (VOIDmode, dest, new_arith),
                                   insn);
 
          if (recog_memoized (ninsn) < 0
-             || (insn_extract (ninsn),
-                 ! constrain_operands (INSN_CODE (ninsn), 1)))
+             || (extract_insn (ninsn), ! constrain_operands (1)))
            {
              delete_insn (ninsn);
              return 0;
@@ -3836,8 +3949,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
    if safe.  */
 
 static void
-fill_eager_delay_slots (first)
-     rtx first;
+fill_eager_delay_slots ()
 {
   register rtx insn;
   register int i;
@@ -3860,8 +3972,19 @@ fill_eager_delay_slots (first)
        continue;
 
       slots_to_fill = num_delay_slots (insn);
+      /* Some machine description have defined instructions to have
+        delay slots only in certain circumstances which may depend on
+        nearby insns (which change due to reorg's actions).
+
+        For example, the PA port normally has delay slots for unconditional
+        jumps.
+
+        However, the PA port claims such jumps do not have a delay slot
+        if they are immediate successors of certain CALL_INSNs.  This
+        allows the port to favor filling the delay slot of the call with
+        the unconditional jump.  */
       if (slots_to_fill == 0)
-       abort ();
+        continue;
 
       slots_filled = 0;
       target_label = JUMP_LABEL (insn);
@@ -3899,8 +4022,8 @@ fill_eager_delay_slots (first)
          delay_list
            = fill_slots_from_thread (insn, condition, insn_at_target,
                                      fallthrough_insn, prediction == 2, 1,
-                                     own_target, own_fallthrough,
-                                     slots_to_fill, &slots_filled);
+                                     own_target,
+                                     slots_to_fill, &slots_filled, delay_list);
 
          if (delay_list == 0 && own_fallthrough)
            {
@@ -3914,8 +4037,9 @@ fill_eager_delay_slots (first)
              delay_list
                = fill_slots_from_thread (insn, condition, fallthrough_insn,
                                          insn_at_target, 0, 0,
-                                         own_fallthrough, own_target,
-                                         slots_to_fill, &slots_filled);
+                                         own_fallthrough,
+                                         slots_to_fill, &slots_filled,
+                                         delay_list);
            }
        }
       else
@@ -3924,21 +4048,22 @@ fill_eager_delay_slots (first)
            delay_list
              = fill_slots_from_thread (insn, condition, fallthrough_insn,
                                        insn_at_target, 0, 0,
-                                       own_fallthrough, own_target,
-                                       slots_to_fill, &slots_filled);
+                                       own_fallthrough,
+                                       slots_to_fill, &slots_filled,
+                                       delay_list);
 
          if (delay_list == 0)
            delay_list
              = fill_slots_from_thread (insn, condition, insn_at_target,
                                        next_active_insn (insn), 0, 1,
-                                       own_target, own_fallthrough,
-                                       slots_to_fill, &slots_filled);
+                                       own_target,
+                                       slots_to_fill, &slots_filled,
+                                       delay_list);
        }
 
       if (delay_list)
        unfilled_slots_base[i]
-         = emit_delay_sequence (insn, delay_list,
-                                slots_filled, slots_to_fill);
+         = emit_delay_sequence (insn, delay_list, slots_filled);
 
       if (slots_to_fill == slots_filled)
        unfilled_slots_base[i] = 0;
@@ -4038,7 +4163,7 @@ relax_delay_slots (first)
          && (other = prev_active_insn (insn)) != 0
          && (condjump_p (other) || condjump_in_parallel_p (other))
          && no_labels_between_p (other, insn)
-         && 0 < mostly_true_jump (other,
+         && 0 > mostly_true_jump (other,
                                   get_branch_condition (other,
                                                         JUMP_LABEL (other))))
        {
@@ -4075,6 +4200,40 @@ relax_delay_slots (first)
          continue;
        }
 
+      /* See if we have a RETURN insn with a filled delay slot followed
+        by a RETURN insn with an unfilled a delay slot.  If so, we can delete
+        the first RETURN (but not it's delay insn).  This gives the same
+        effect in fewer instructions.
+
+        Only do so if optimizing for size since this results in slower, but
+        smaller code.  */
+      if (optimize_size
+         && GET_CODE (PATTERN (delay_insn)) == RETURN
+         && next
+         && GET_CODE (next) == JUMP_INSN
+         && GET_CODE (PATTERN (next)) == RETURN)
+       {
+         int i;
+
+         /* Delete the RETURN and just execute the delay list insns.
+
+            We do this by deleting the INSN containing the SEQUENCE, then
+            re-emitting the insns separately, and then deleting the RETURN.
+            This allows the count of the jump target to be properly
+            decremented.  */
+
+         /* Clear the from target bit, since these insns are no longer
+            in delay slots.  */
+         for (i = 0; i < XVECLEN (pat, 0); i++)
+           INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
+
+         trial = PREV_INSN (insn);
+         delete_insn (insn);
+         emit_insn_after (pat, trial);
+         delete_scheduled_jump (delay_insn);
+         continue;
+       }
+
       /* Now look only at the cases where we have a filled JUMP_INSN.  */
       if (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN
          || ! (condjump_p (XVECEXP (PATTERN (insn), 0, 0))
@@ -4383,8 +4542,8 @@ make_return_insns (first)
   if (--LABEL_NUSES (real_return_label) == 0)
     delete_insn (real_return_label);
 
-  fill_simple_delay_slots (first, 1);
-  fill_simple_delay_slots (first, 0);
+  fill_simple_delay_slots (1);
+  fill_simple_delay_slots (0);
 }
 #endif
 \f
@@ -4425,7 +4584,7 @@ dbr_schedule (first, file)
        epilogue_insn = insn;
     }
 
-  uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int *));
+  uid_to_ruid = (int *) alloca ((max_uid + 1) * sizeof (int));
   for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn))
     uid_to_ruid[INSN_UID (insn)] = i;
   
@@ -4480,15 +4639,15 @@ dbr_schedule (first, file)
       SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
 #endif
 #ifdef EXIT_IGNORE_STACK
-      if (! EXIT_IGNORE_STACK)
+      if (! EXIT_IGNORE_STACK
+         || current_function_sp_is_unchanging)
 #endif
        SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
     }
   else
     SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
 
-  if (current_function_return_rtx != 0
-      && GET_CODE (current_function_return_rtx) == REG)
+  if (current_function_return_rtx != 0)
     mark_referenced_resources (current_function_return_rtx,
                               &end_of_function_needs, 1);
 
@@ -4519,7 +4678,7 @@ dbr_schedule (first, file)
 
   start_of_epilogue_needs = end_of_function_needs;
 
-  while (epilogue_insn = next_nonnote_insn (epilogue_insn))
+  while ((epilogue_insn = next_nonnote_insn (epilogue_insn)))
     mark_set_resources (epilogue_insn, &end_of_function_needs, 0, 1);
 
   /* Show we haven't computed an end-of-function label yet.  */
@@ -4546,9 +4705,9 @@ dbr_schedule (first, file)
        reorg_pass_number < MAX_REORG_PASSES;
        reorg_pass_number++)
     {
-      fill_simple_delay_slots (first, 1);
-      fill_simple_delay_slots (first, 0);
-      fill_eager_delay_slots (first);
+      fill_simple_delay_slots (1);
+      fill_simple_delay_slots (0);
+      fill_eager_delay_slots ();
       relax_delay_slots (first);
     }
 
@@ -4613,5 +4772,30 @@ dbr_schedule (first, file)
            }
        }
     }
+
+  /* For all JUMP insns, fill in branch prediction notes, so that during
+     assembler output a target can set branch prediction bits in the code.
+     We have to do this now, as up until this point the destinations of
+     JUMPS can be moved around and changed, but past right here that cannot
+     happen.  */
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    {
+      int pred_flags;
+
+      if (GET_CODE (insn) == INSN)
+        {
+         rtx pat = PATTERN (insn);
+
+         if (GET_CODE (pat) == SEQUENCE)
+           insn = XVECEXP (pat, 0, 0);
+       }
+      if (GET_CODE (insn) != JUMP_INSN)
+       continue;
+
+      pred_flags = get_jump_flags (insn, JUMP_LABEL (insn));
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_BR_PRED,
+                                           GEN_INT (pred_flags),
+                                           REG_NOTES (insn));
+    }
 }
 #endif /* DELAY_SLOTS */