OSDN Git Service

Move language subdirectory Makefile processing into configure.lang.
[pf3gnuchains/gcc-fork.git] / gcc / sched.c
index aea307f..132ed54 100644 (file)
@@ -1,5 +1,5 @@
 /* Instruction scheduling pass.
-   Copyright (C) 1992, 93-95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93-96, 1997 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
    Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.com)
 
@@ -111,9 +111,11 @@ Boston, MA 02111-1307, USA.  */
    reg_n_calls_crossed, and reg_live_length.  Also, basic_block_head,
    basic_block_end.
 
-   The information in the line number notes is carefully retained by this
-   pass.  All other NOTE insns are grouped in their same relative order at
-   the beginning of basic blocks that have been scheduled.  */
+   The information in the line number notes is carefully retained by
+   this pass.  Notes that refer to the starting and ending of
+   exception regions are also carefully retained by this pass.  All
+   other NOTE insns are grouped in their same relative order at the
+   beginning of basic blocks that have been scheduled.  */
 \f
 #include <stdio.h>
 #include "config.h"
@@ -133,7 +135,6 @@ Boston, MA 02111-1307, USA.  */
 
    Values of these arrays are copied at the end of this pass into the
    arrays set up by flow analysis.  */
-static short *sched_reg_n_deaths;
 static int *sched_reg_n_calls_crossed;
 static int *sched_reg_live_length;
 
@@ -288,8 +289,9 @@ static int *insn_tick;
 
 struct sometimes
 {
-  short offset; short bit;
-  short live_length; short calls_crossed;
+  int regno;
+  int live_length;
+  int calls_crossed;
 };
 
 /* Forward declarations.  */
@@ -330,8 +332,7 @@ static void create_reg_dead_note    PROTO((rtx, rtx));
 static void attach_deaths              PROTO((rtx, rtx, int));
 static void attach_deaths_insn         PROTO((rtx));
 static rtx unlink_notes                        PROTO((rtx, rtx));
-static int new_sometimes_live          PROTO((struct sometimes *, int, int,
-                                              int));
+static int new_sometimes_live          PROTO((struct sometimes *, int, int));
 static void finish_sometimes_live      PROTO((struct sometimes *, int));
 static rtx reemit_notes                        PROTO((rtx, rtx));
 static void schedule_block             PROTO((int, FILE *));
@@ -436,7 +437,7 @@ init_alias_analysis ()
        && GET_CODE (SET_DEST (set)) == REG
        && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
        && (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
-            && reg_n_sets[REGNO (SET_DEST (set))] == 1)
+            && REG_N_SETS (REGNO (SET_DEST (set))) == 1)
            || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
        && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
       {
@@ -643,8 +644,8 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
     y = canon_rtx (y);
 
   if (rtx_equal_for_memref_p (x, y))
-    return (xsize == 0 || ysize == 0 ||
-           (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
+    return (xsize == 0 || ysize == 0
+           || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
 
   if (y == frame_pointer_rtx || y == hard_frame_pointer_rtx
       || y == stack_pointer_rtx)
@@ -807,11 +808,14 @@ memrefs_conflict_p (xsize, x, ysize, y, c)
    changed.  A volatile and non-volatile reference can be interchanged
    though. 
 
-   A MEM_IN_STRUCT reference at a non-QImode varying address can never
+   A MEM_IN_STRUCT reference at a non-QImode non-AND varying address can never
    conflict with a non-MEM_IN_STRUCT reference at a fixed address.   We must
    allow QImode aliasing because the ANSI C standard allows character
    pointers to alias anything.  We are assuming that characters are
-   always QImode here.  */
+   always QImode here.  We also must allow AND addresses, because they may
+   generate accesses outside the object being referenced.  This is used to
+   generate aligned addresses from unaligned addresses, for instance, the
+   alpha storeqi_unaligned pattern.  */
 
 /* Read dependence: X is read after read in MEM takes place.  There can
    only be a dependence here if both reads are volatile.  */
@@ -848,9 +852,11 @@ true_dependence (mem, x)
                                  SIZE_FOR_MODE (x), XEXP (x, 0), 0)
              && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
                    && GET_MODE (mem) != QImode
+                   && GET_CODE (XEXP (mem, 0)) != AND
                    && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
              && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
                    && GET_MODE (x) != QImode
+                   && GET_CODE (XEXP (x, 0)) != AND
                    && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
 }
 
@@ -874,9 +880,11 @@ anti_dependence (mem, x)
                                  SIZE_FOR_MODE (x), XEXP (x, 0), 0)
              && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
                    && GET_MODE (mem) != QImode
+                   && GET_CODE (XEXP (mem, 0)) != AND
                    && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
              && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
                    && GET_MODE (x) != QImode
+                   && GET_CODE (XEXP (x, 0)) != AND
                    && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
 }
 
@@ -894,9 +902,11 @@ output_dependence (mem, x)
                                  SIZE_FOR_MODE (x), XEXP (x, 0), 0)
              && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
                    && GET_MODE (mem) != QImode
+                   && GET_CODE (XEXP (mem, 0)) != AND
                    && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
              && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
                    && GET_MODE (x) != QImode
+                   && GET_CODE (XEXP (x, 0)) != AND
                    && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
 }
 \f
@@ -1721,8 +1731,7 @@ sched_analyze_1 (x, insn)
              if (reg_last_sets[regno + i])
                add_dependence (insn, reg_last_sets[regno + i],
                                REG_DEP_OUTPUT);
-             reg_pending_sets[(regno + i) / REGSET_ELT_BITS]
-               |= (REGSET_ELT_TYPE) 1 << ((regno + i) % REGSET_ELT_BITS);
+             SET_REGNO_REG_SET (reg_pending_sets, regno + i);
              if ((call_used_regs[i] || global_regs[i])
                  && last_function_call)
                /* Function calls clobber all call_used regs.  */
@@ -1738,8 +1747,7 @@ sched_analyze_1 (x, insn)
          reg_last_uses[regno] = 0;
          if (reg_last_sets[regno])
            add_dependence (insn, reg_last_sets[regno], REG_DEP_OUTPUT);
-         reg_pending_sets[regno / REGSET_ELT_BITS]
-           |= (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+         SET_REGNO_REG_SET (reg_pending_sets, regno);
 
          /* Pseudos that are REG_EQUIV to something may be replaced
             by that during reloading.  We need only add dependencies for
@@ -1751,7 +1759,7 @@ sched_analyze_1 (x, insn)
 
          /* Don't let it cross a call after scheduling if it doesn't
             already cross one.  */
-         if (reg_n_calls_crossed[regno] == 0 && last_function_call)
+         if (REG_N_CALLS_CROSSED (regno) == 0 && last_function_call)
            add_dependence (insn, last_function_call, REG_DEP_ANTI);
        }
     }
@@ -1909,7 +1917,7 @@ sched_analyze_2 (x, insn)
            /* If the register does not already cross any calls, then add this
               insn to the sched_before_next_call list so that it will still
               not cross calls after scheduling.  */
-           if (reg_n_calls_crossed[regno] == 0)
+           if (REG_N_CALLS_CROSSED (regno) == 0)
              add_dependence (sched_before_next_call, insn, REG_DEP_ANTI);
          }
        return;
@@ -2069,7 +2077,7 @@ sched_analyze_insn (x, insn, loop_notes)
          sched_analyze_2 (XEXP (link, 0), insn);
       }
 
-  /* If there is a LOOP_{BEG,END} note in the middle of a basic block, then
+  /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic block, then
      we must be sure that no instructions are scheduled across it.
      Otherwise, the reg_n_refs info (which depends on loop_depth) would
      become incorrect.  */
@@ -2120,18 +2128,11 @@ sched_analyze_insn (x, insn, loop_notes)
          sched_analyze_2 (XEXP (note, 0), insn);
     }
 
-  for (i = 0; i < regset_size; i++)
-    {
-      REGSET_ELT_TYPE sets = reg_pending_sets[i];
-      if (sets)
-       {
-         register int bit;
-         for (bit = 0; bit < REGSET_ELT_BITS; bit++)
-           if (sets & ((REGSET_ELT_TYPE) 1 << bit))
-             reg_last_sets[i * REGSET_ELT_BITS + bit] = insn;
-         reg_pending_sets[i] = 0;
-       }
-    }
+  EXECUTE_IF_SET_AND_RESET_IN_REG_SET (reg_pending_sets, 0, i,
+                                      {
+                                        reg_last_sets[i] = insn;
+                                      });
+
   if (reg_pending_sets_all)
     {
       for (i = 0; i < maxreg; i++)
@@ -2231,8 +2232,13 @@ sched_analyze (head, tail)
                }
              reg_pending_sets_all = 1;
 
-             /* Add a fake REG_NOTE which we will later convert
-                back into a NOTE_INSN_SETJMP note.  */
+             /* Add a pair of fake REG_NOTEs which we will later
+                convert back into a NOTE_INSN_SETJMP note.  See
+                reemit_notes for why we use a pair of of NOTEs.  */
+
+             REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
+                                         GEN_INT (0),
+                                         REG_NOTES (insn));
              REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
                                          GEN_INT (NOTE_INSN_SETJMP),
                                          REG_NOTES (insn));
@@ -2247,8 +2253,7 @@ sched_analyze (head, tail)
                    reg_last_uses[i] = 0;
                    if (reg_last_sets[i])
                      add_dependence (insn, reg_last_sets[i], REG_DEP_ANTI);
-                   reg_pending_sets[i / REGSET_ELT_BITS]
-                     |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+                   SET_REGNO_REG_SET (reg_pending_sets, i);
                  }
            }
 
@@ -2276,13 +2281,19 @@ sched_analyze (head, tail)
          last_function_call = insn;
          n_insns += 1;
        }
+
+      /* See comments on reemit_notes as to why we do this.  */
       else if (GET_CODE (insn) == NOTE
               && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
                   || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
+                  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+                  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
                   || (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
                       && GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
        {
          loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
+                               GEN_INT (NOTE_BLOCK_NUMBER (insn)), loop_notes);
+         loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
                                GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
          CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
        }
@@ -2335,10 +2346,6 @@ sched_note_set (b, x, death)
   regno = REGNO (reg);
   if (regno >= FIRST_PSEUDO_REGISTER || ! global_regs[regno])
     {
-      register int offset = regno / REGSET_ELT_BITS;
-      register REGSET_ELT_TYPE bit
-       = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-
       if (death)
        {
          /* If we only set part of the register, then this set does not
@@ -2352,17 +2359,14 @@ sched_note_set (b, x, death)
              int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
              while (--j >= 0)
                {
-                 offset = (regno + j) / REGSET_ELT_BITS;
-                 bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-                 
-                 bb_live_regs[offset] &= ~bit;
-                 bb_dead_regs[offset] |= bit;
+                 CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+                 SET_REGNO_REG_SET (bb_dead_regs, regno + j);
                }
            }
          else
            {
-             bb_live_regs[offset] &= ~bit;
-             bb_dead_regs[offset] |= bit;
+             CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+             SET_REGNO_REG_SET (bb_dead_regs, regno);
            }
        }
       else
@@ -2373,17 +2377,14 @@ sched_note_set (b, x, death)
              int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
              while (--j >= 0)
                {
-                 offset = (regno + j) / REGSET_ELT_BITS;
-                 bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-                 
-                 bb_live_regs[offset] |= bit;
-                 bb_dead_regs[offset] &= ~bit;
+                 SET_REGNO_REG_SET (bb_live_regs, regno + j);
+                 CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
                }
            }
          else
            {
-             bb_live_regs[offset] |= bit;
-             bb_dead_regs[offset] &= ~bit;
+             SET_REGNO_REG_SET (bb_live_regs, regno);
+             CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
            }
        }
     }
@@ -2501,15 +2502,13 @@ birthing_insn_p (pat)
     {
       rtx dest = SET_DEST (pat);
       int i = REGNO (dest);
-      int offset = i / REGSET_ELT_BITS;
-      REGSET_ELT_TYPE bit = (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
 
       /* It would be more accurate to use refers_to_regno_p or
         reg_mentioned_p to determine when the dest is not live before this
         insn.  */
 
-      if (bb_live_regs[offset] & bit)
-       return (reg_n_sets[i] == 1);
+      if (REGNO_REG_SET_P (bb_live_regs, i))
+       return (REG_N_SETS (i) == 1);
 
       return 0;
     }
@@ -2836,16 +2835,15 @@ attach_deaths (x, insn, set_p)
        /* This code is very similar to mark_used_1 (if set_p is false)
           and mark_set_1 (if set_p is true) in flow.c.  */
 
-       register int regno = REGNO (x);
-       register int offset = regno / REGSET_ELT_BITS;
-       register REGSET_ELT_TYPE bit
-         = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-       REGSET_ELT_TYPE all_needed = (old_live_regs[offset] & bit);
-       REGSET_ELT_TYPE some_needed = (old_live_regs[offset] & bit);
+       register int regno;
+       int some_needed;
+       int all_needed;
 
        if (set_p)
          return;
 
+       regno = REGNO (x);
+       all_needed = some_needed = REGNO_REG_SET_P (old_live_regs, regno);
        if (regno < FIRST_PSEUDO_REGISTER)
          {
            int n;
@@ -2853,12 +2851,9 @@ attach_deaths (x, insn, set_p)
            n = HARD_REGNO_NREGS (regno, GET_MODE (x));
            while (--n > 0)
              {
-               some_needed |= (old_live_regs[(regno + n) / REGSET_ELT_BITS]
-                               & ((REGSET_ELT_TYPE) 1
-                                  << ((regno + n) % REGSET_ELT_BITS)));
-               all_needed &= (old_live_regs[(regno + n) / REGSET_ELT_BITS]
-                              & ((REGSET_ELT_TYPE) 1
-                                 << ((regno + n) % REGSET_ELT_BITS)));
+               int needed = (REGNO_REG_SET_P (old_live_regs, regno + n));
+               some_needed |= needed;
+               all_needed &= needed;
              }
          }
 
@@ -2920,9 +2915,7 @@ attach_deaths (x, insn, set_p)
                           register that is set in the insn.  */
                        for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
                             i >= 0; i--)
-                         if ((old_live_regs[(regno + i) / REGSET_ELT_BITS]
-                              & ((REGSET_ELT_TYPE) 1
-                                 << ((regno +i) % REGSET_ELT_BITS))) == 0
+                         if (! REGNO_REG_SET_P (old_live_regs, regno + i)
                              && ! dead_or_set_regno_p (insn, regno + i))
                            create_reg_dead_note (gen_rtx (REG,
                                                           reg_raw_mode[regno + i],
@@ -2937,18 +2930,14 @@ attach_deaths (x, insn, set_p)
                int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
                while (--j >= 0)
                  {
-                   offset = (regno + j) / REGSET_ELT_BITS;
-                   bit
-                     = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
-                   bb_dead_regs[offset] &= ~bit;
-                   bb_live_regs[offset] |= bit;
+                   CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
+                   SET_REGNO_REG_SET (bb_live_regs, regno + j);
                  }
              }
            else
              {
-               bb_dead_regs[offset] &= ~bit;
-               bb_live_regs[offset] |= bit;
+               CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
+               SET_REGNO_REG_SET (bb_live_regs, regno);
              }
          }
        return;
@@ -3068,10 +3057,12 @@ unlink_notes (insn, tail)
       /* Don't save away NOTE_INSN_SETJMPs, because they must remain
         immediately after the call they follow.  We use a fake
         (REG_DEAD (const_int -1)) note to remember them.
-        Likewise with NOTE_INSN_LOOP_BEG and NOTE_INSN_LOOP_END.  */
+        Likewise with NOTE_INSN_{LOOP,EHREGION}_{BEG, END}.  */
       else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
               && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
-              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END)
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
+              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
        {
          /* Insert the note at the end of the notes list.  */
          PREV_INSN (insn) = note_list;
@@ -3088,13 +3079,12 @@ unlink_notes (insn, tail)
 /* Constructor for `sometimes' data structure.  */
 
 static int
-new_sometimes_live (regs_sometimes_live, offset, bit, sometimes_max)
+new_sometimes_live (regs_sometimes_live, regno, sometimes_max)
      struct sometimes *regs_sometimes_live;
-     int offset, bit;
+     int regno;
      int sometimes_max;
 {
   register struct sometimes *p;
-  register int regno = offset * REGSET_ELT_BITS + bit;
 
   /* There should never be a register greater than max_regno here.  If there
      is, it means that a define_split has created a new pseudo reg.  This
@@ -3104,8 +3094,7 @@ new_sometimes_live (regs_sometimes_live, offset, bit, sometimes_max)
     abort ();
 
   p = &regs_sometimes_live[sometimes_max];
-  p->offset = offset;
-  p->bit = bit;
+  p->regno = regno;
   p->live_length = 0;
   p->calls_crossed = 0;
   sometimes_max++;
@@ -3125,19 +3114,19 @@ finish_sometimes_live (regs_sometimes_live, sometimes_max)
   for (i = 0; i < sometimes_max; i++)
     {
       register struct sometimes *p = &regs_sometimes_live[i];
-      int regno;
-
-      regno = p->offset * REGSET_ELT_BITS + p->bit;
+      int regno = p->regno;
 
       sched_reg_live_length[regno] += p->live_length;
       sched_reg_n_calls_crossed[regno] += p->calls_crossed;
     }
 }
 
-/* Search INSN for fake REG_DEAD notes for NOTE_INSN_SETJMP,
-   NOTE_INSN_LOOP_BEG, and NOTE_INSN_LOOP_END; and convert them back
-   into NOTEs.  LAST is the last instruction output by the instruction
-   scheduler.  Return the new value of LAST.  */
+/* Search INSN for fake REG_DEAD note pairs for NOTE_INSN_SETJMP,
+   NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
+   NOTEs.  The REG_DEAD note following first one is contains the saved
+   value for NOTE_BLOCK_NUMBER which is useful for
+   NOTE_INSN_EH_REGION_{BEG,END} NOTEs.  LAST is the last instruction
+   output by the instruction scheduler.  Return the new value of LAST.  */
 
 static rtx
 reemit_notes (insn, last)
@@ -3152,10 +3141,19 @@ reemit_notes (insn, last)
          && GET_CODE (XEXP (note, 0)) == CONST_INT)
        {
          if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
-           CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
-             = CONST_CALL_P (note);
+           {
+             CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
+               = CONST_CALL_P (note);
+             remove_note (insn, note);
+             note = XEXP (note, 1);
+           }
          else
-           last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+           {
+             last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+             remove_note (insn, note);
+             note = XEXP (note, 1);
+             NOTE_BLOCK_NUMBER (last) = INTVAL (XEXP (note, 0));
+           }
          remove_note (insn, note);
        }
     }
@@ -3204,8 +3202,8 @@ schedule_block (b, file)
   bzero ((char *) reg_last_uses, i * sizeof (rtx));
   reg_last_sets = (rtx *) alloca (i * sizeof (rtx));
   bzero ((char *) reg_last_sets, i * sizeof (rtx));
-  reg_pending_sets = (regset) alloca (regset_bytes);
-  bzero ((char *) reg_pending_sets, regset_bytes);
+  reg_pending_sets = ALLOCA_REG_SET ();
+  CLEAR_REG_SET (reg_pending_sets);
   reg_pending_sets_all = 0;
   clear_units ();
 
@@ -3479,6 +3477,22 @@ schedule_block (b, file)
                        sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 0);
                  }
 
+               /* Each call clobbers (makes live) all call-clobbered regs
+                  that are not global or fixed.  Note that the function-value
+                  reg is a call_clobbered reg.  */
+
+               if (GET_CODE (insn) == CALL_INSN)
+                 {
+                   int j;
+                   for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+                     if (call_used_regs[j] && ! global_regs[j]
+                         && ! fixed_regs[j])
+                       {
+                         SET_REGNO_REG_SET (bb_live_regs, j);
+                         CLEAR_REGNO_REG_SET (bb_dead_regs, j);
+                       }
+                 }
+
                for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
                  {
                    if ((REG_NOTE_KIND (link) == REG_DEAD
@@ -3487,9 +3501,6 @@ schedule_block (b, file)
                        && GET_CODE (XEXP (link, 0)) == REG)
                      {
                        register int regno = REGNO (XEXP (link, 0));
-                       register int offset = regno / REGSET_ELT_BITS;
-                       register REGSET_ELT_TYPE bit
-                         = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
 
                        if (regno < FIRST_PSEUDO_REGISTER)
                          {
@@ -3497,18 +3508,14 @@ schedule_block (b, file)
                                                      GET_MODE (XEXP (link, 0)));
                            while (--j >= 0)
                              {
-                               offset = (regno + j) / REGSET_ELT_BITS;
-                               bit = ((REGSET_ELT_TYPE) 1
-                                      << ((regno + j) % REGSET_ELT_BITS));
-
-                               bb_live_regs[offset] &= ~bit;
-                               bb_dead_regs[offset] |= bit;
+                               CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+                               SET_REGNO_REG_SET (bb_dead_regs, regno + j);
                              }
                          }
                        else
                          {
-                           bb_live_regs[offset] &= ~bit;
-                           bb_dead_regs[offset] |= bit;
+                           CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+                           SET_REGNO_REG_SET (bb_dead_regs, regno);
                          }
                      }
                  }
@@ -3580,6 +3587,22 @@ schedule_block (b, file)
                  sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 0);
            }
 
+         /* Each call clobbers (makes live) all call-clobbered regs that are
+            not global or fixed.  Note that the function-value reg is a
+            call_clobbered reg.  */
+
+         if (GET_CODE (insn) == CALL_INSN)
+           {
+             int j;
+             for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+               if (call_used_regs[j] && ! global_regs[j]
+                   && ! fixed_regs[j])
+                 {
+                   SET_REGNO_REG_SET (bb_live_regs, j);
+                   CLEAR_REGNO_REG_SET (bb_dead_regs, j);
+                 }
+           }
+
          /* Need to know what registers this insn kills.  */
          for (prev = 0, link = REG_NOTES (insn); link; link = next)
            {
@@ -3590,9 +3613,6 @@ schedule_block (b, file)
                  && GET_CODE (XEXP (link, 0)) == REG)
                {
                  register int regno = REGNO (XEXP (link, 0));
-                 register int offset = regno / REGSET_ELT_BITS;
-                 register REGSET_ELT_TYPE bit
-                   = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
 
                  /* Only unlink REG_DEAD notes; leave REG_UNUSED notes
                     alone.  */
@@ -3614,18 +3634,14 @@ schedule_block (b, file)
                                                GET_MODE (XEXP (link, 0)));
                      while (--j >= 0)
                        {
-                         offset = (regno + j) / REGSET_ELT_BITS;
-                         bit = ((REGSET_ELT_TYPE) 1
-                                << ((regno + j) % REGSET_ELT_BITS));
-
-                         bb_live_regs[offset] &= ~bit;
-                         bb_dead_regs[offset] |= bit;
+                         CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+                         SET_REGNO_REG_SET (bb_dead_regs, regno + j);
                        }
                    }
                  else
                    {
-                     bb_live_regs[offset] &= ~bit;
-                     bb_dead_regs[offset] |= bit;
+                     CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+                     SET_REGNO_REG_SET (bb_dead_regs, regno);
                    }
                }
              else
@@ -3637,25 +3653,19 @@ schedule_block (b, file)
   if (reload_completed == 0)
     {
       /* Keep track of register lives.  */
-      old_live_regs = (regset) alloca (regset_bytes);
+      old_live_regs = ALLOCA_REG_SET ();
       regs_sometimes_live
        = (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
       sometimes_max = 0;
 
       /* Start with registers live at end.  */
-      for (j = 0; j < regset_size; j++)
-       {
-         REGSET_ELT_TYPE live = bb_live_regs[j];
-         old_live_regs[j] = live;
-         if (live)
-           {
-             register int bit;
-             for (bit = 0; bit < REGSET_ELT_BITS; bit++)
-               if (live & ((REGSET_ELT_TYPE) 1 << bit))
-                 sometimes_max = new_sometimes_live (regs_sometimes_live, j,
-                                                     bit, sometimes_max);
-           }
-       }
+      COPY_REG_SET (old_live_regs, bb_live_regs);
+      EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, 0, j,
+                                {
+                                  sometimes_max
+                                    = new_sometimes_live (regs_sometimes_live,
+                                                          j, sometimes_max);
+                                });
     }
 
   SCHED_SORT (ready, n_ready, 1);
@@ -3819,19 +3829,15 @@ schedule_block (b, file)
                {
                  register struct sometimes *p;
 
-                 /* A call kills all call used and global registers, except
-                    for those mentioned in the call pattern which will be
-                    made live again later.  */
+                 /* A call kills all call used registers that are not
+                    global or fixed, except for those mentioned in the call
+                    pattern which will be made live again later.  */
                  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-                   if ((call_used_regs[i] && ! fixed_regs[i])
-                       || global_regs[i])
+                   if (call_used_regs[i] && ! global_regs[i]
+                       && ! fixed_regs[i])
                      {
-                       register int offset = i / REGSET_ELT_BITS;
-                       register REGSET_ELT_TYPE bit
-                         = (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
-
-                       bb_live_regs[offset] &= ~bit;
-                       bb_dead_regs[offset] |= bit;
+                       CLEAR_REGNO_REG_SET (bb_live_regs, i);
+                       SET_REGNO_REG_SET (bb_dead_regs, i);
                      }
 
                  /* Regs live at the time of a call instruction must not
@@ -3842,8 +3848,7 @@ schedule_block (b, file)
                     (below).  */
                  p = regs_sometimes_live;
                  for (i = 0; i < sometimes_max; i++, p++)
-                   if (bb_live_regs[p->offset]
-                       & ((REGSET_ELT_TYPE) 1 << p->bit))
+                   if (REGNO_REG_SET_P (bb_live_regs, p->regno))
                      p->calls_crossed += 1;
                }
 
@@ -3852,20 +3857,13 @@ schedule_block (b, file)
              attach_deaths_insn (insn);
 
              /* Find registers now made live by that instruction.  */
-             for (i = 0; i < regset_size; i++)
-               {
-                 REGSET_ELT_TYPE diff = bb_live_regs[i] & ~old_live_regs[i];
-                 if (diff)
-                   {
-                     register int bit;
-                     old_live_regs[i] |= diff;
-                     for (bit = 0; bit < REGSET_ELT_BITS; bit++)
-                       if (diff & ((REGSET_ELT_TYPE) 1 << bit))
-                         sometimes_max
-                           = new_sometimes_live (regs_sometimes_live, i, bit,
-                                                 sometimes_max);
-                   }
-               }
+             EXECUTE_IF_AND_COMPL_IN_REG_SET (bb_live_regs, old_live_regs, 0, i,
+                                              {
+                                                sometimes_max
+                                                  = new_sometimes_live (regs_sometimes_live,
+                                                                        i, sometimes_max);
+                                              });
+             IOR_REG_SET (old_live_regs, bb_live_regs);
 
              /* Count lengths of all regs we are worrying about now,
                 and handle registers no longer live.  */
@@ -3873,20 +3871,18 @@ schedule_block (b, file)
              for (i = 0; i < sometimes_max; i++)
                {
                  register struct sometimes *p = &regs_sometimes_live[i];
-                 int regno = p->offset*REGSET_ELT_BITS + p->bit;
+                 int regno = p->regno;
 
                  p->live_length += 1;
 
-                 if ((bb_live_regs[p->offset]
-                      & ((REGSET_ELT_TYPE) 1 << p->bit)) == 0)
+                 if (!REGNO_REG_SET_P (bb_live_regs, p->regno))
                    {
                      /* This is the end of one of this register's lifetime
                         segments.  Save the lifetime info collected so far,
                         and clear its bit in the old_live_regs entry.  */
                      sched_reg_live_length[regno] += p->live_length;
                      sched_reg_n_calls_crossed[regno] += p->calls_crossed;
-                     old_live_regs[p->offset]
-                       &= ~((REGSET_ELT_TYPE) 1 << p->bit);
+                     CLEAR_REGNO_REG_SET (old_live_regs, p->regno);
 
                      /* Delete the reg_sometimes_live entry for this reg by
                         copying the last entry over top of it.  */
@@ -3952,8 +3948,8 @@ schedule_block (b, file)
            }
        }
 
-      /* Put back NOTE_INSN_SETJMP, NOTE_INSN_LOOP_BEGIN, and
-        NOTE_INSN_LOOP_END notes.  */
+      /* Put back NOTE_INSN_SETJMP,
+         NOTE_INSN_{LOOP,EHREGION}_{BEGIN,END} notes.  */
 
       /* To prime the loop.  We need to handle INSN and all the insns in the
          sched group.  */
@@ -4298,10 +4294,10 @@ update_n_sets (x, inc)
          int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
          
          for (i = regno; i < endregno; i++)
-           reg_n_sets[i] += inc;
+           REG_N_SETS (i) += inc;
        }
       else
-       reg_n_sets[regno] += inc;
+       REG_N_SETS (regno) += inc;
     }
 }
 
@@ -4377,6 +4373,15 @@ update_flow_info (notes, first, last, orig_insn)
                 pattern, so we can safely ignore it.  */
              if (insn == first)
                {
+                 /* After reload, REG_DEAD notes come sometimes an
+                    instruction after the register actually dies.  */
+                 if (reload_completed && REG_NOTE_KIND (note) == REG_DEAD)
+                   {
+                     XEXP (note, 1) = REG_NOTES (insn);
+                     REG_NOTES (insn) = note;
+                     break;
+                   }
+                       
                  if (REG_NOTE_KIND (note) != REG_UNUSED)
                    abort ();
 
@@ -4405,6 +4410,15 @@ update_flow_info (notes, first, last, orig_insn)
                     uses it.  */
                  break;
                }
+             /* If this note refers to a multiple word hard
+                register, it may have been split into several smaller
+                hard register references.  We could split the notes,
+                but simply dropping them is good enough.  */
+             if (GET_CODE (orig_dest) == REG
+                 && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+                 && HARD_REGNO_NREGS (REGNO (orig_dest),
+                                      GET_MODE (orig_dest)) > 1)
+                   break;
              /* It must be set somewhere, fail if we couldn't find where it
                 was set.  */
              if (insn == last)
@@ -4441,7 +4455,22 @@ update_flow_info (notes, first, last, orig_insn)
              /* The original dest must still be set someplace.  Abort if we
                 couldn't find it.  */
              if (insn == first)
-               abort ();
+               {
+                 /* However, if this note refers to a multiple word hard
+                    register, it may have been split into several smaller
+                    hard register references.  We could split the notes,
+                    but simply dropping them is good enough.  */
+                 if (GET_CODE (orig_dest) == REG
+                     && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+                     && HARD_REGNO_NREGS (REGNO (orig_dest),
+                                          GET_MODE (orig_dest)) > 1)
+                   break;
+                 /* Likewise for multi-word memory references.  */
+                 if (GET_CODE (orig_dest) == MEM
+                     && SIZE_FOR_MODE (orig_dest) > MOVE_MAX)
+                   break;
+                 abort ();
+               }
            }
          break;
 
@@ -4457,6 +4486,12 @@ update_flow_info (notes, first, last, orig_insn)
            XEXP (note, 0) = first;
          break;
 
+       case REG_EXEC_COUNT:
+         /* Move a REG_EXEC_COUNT note to the first insn created.  */
+         XEXP (note, 1) = REG_NOTES (first);
+         REG_NOTES (first) = note;
+         break;
+
        case REG_RETVAL:
          /* Move a REG_RETVAL note to the last insn created, and update
             the corresponding REG_LIBCALL note.  */
@@ -4470,6 +4505,7 @@ update_flow_info (notes, first, last, orig_insn)
          break;
 
        case REG_NONNEG:
+       case REG_BR_PROB:
          /* This should be moved to whichever instruction is a JUMP_INSN.  */
 
          for (insn = last; ; insn = PREV_INSN (insn))
@@ -4488,6 +4524,9 @@ update_flow_info (notes, first, last, orig_insn)
          break;
 
        case REG_INC:
+         /* reload sometimes leaves obsolete REG_INC notes around.  */
+         if (reload_completed)
+           break;
          /* This should be moved to whichever instruction now has the
             increment operation.  */
          abort ();
@@ -4538,10 +4577,7 @@ update_flow_info (notes, first, last, orig_insn)
   /* If any insn, except the last, uses the register set by the last insn,
      then we need a new REG_DEAD note on that insn.  In this case, there
      would not have been a REG_DEAD note for this register in the original
-     insn because it was used and set within one insn.
-
-     There is no new REG_DEAD note needed if the last insn uses the register
-     that it is setting.  */
+     insn because it was used and set within one insn.  */
 
   set = single_set (last);
   if (set)
@@ -4554,9 +4590,34 @@ update_flow_info (notes, first, last, orig_insn)
        dest = XEXP (dest, 0);
 
       if (GET_CODE (dest) == REG
-         && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
+         /* Global registers are always live, so the code below does not
+            apply to them.  */
+         && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
+             || ! global_regs[REGNO (dest)]))
        {
-         for (insn = PREV_INSN (last); ; insn = PREV_INSN (insn))
+         rtx stop_insn = PREV_INSN (first);
+
+         /* If the last insn uses the register that it is setting, then
+            we don't want to put a REG_DEAD note there.  Search backwards
+            to find the first insn that sets but does not use DEST.  */
+
+         insn = last;
+         if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
+           {
+             for (insn = PREV_INSN (insn); insn != first;
+                  insn = PREV_INSN (insn))
+               {
+                 if ((set = single_set (insn))
+                     && reg_mentioned_p (dest, SET_DEST (set))
+                     && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
+                   break;
+               }
+           }
+
+         /* Now find the first insn that uses but does not set DEST.  */
+
+         for (insn = PREV_INSN (insn); insn != stop_insn;
+              insn = PREV_INSN (insn))
            {
              if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
                  && reg_mentioned_p (dest, PATTERN (insn))
@@ -4582,8 +4643,6 @@ update_flow_info (notes, first, last, orig_insn)
                      break;
                    }
                }
-             if (insn == first)
-               break;
            }
        }
     }
@@ -4710,6 +4769,7 @@ schedule_insns (dump_file)
 {
   int max_uid = MAX_INSNS_PER_SPLIT * (get_max_uid () + 1);
   int b;
+  int i;
   rtx insn;
 
   /* Taking care of this degenerate case makes the rest of
@@ -4749,20 +4809,16 @@ schedule_insns (dump_file)
 
   if (reload_completed == 0)
     {
-      sched_reg_n_deaths = (short *) alloca (max_regno * sizeof (short));
       sched_reg_n_calls_crossed = (int *) alloca (max_regno * sizeof (int));
       sched_reg_live_length = (int *) alloca (max_regno * sizeof (int));
-      bb_dead_regs = (regset) alloca (regset_bytes);
-      bb_live_regs = (regset) alloca (regset_bytes);
+      bb_dead_regs = ALLOCA_REG_SET ();
+      bb_live_regs = ALLOCA_REG_SET ();
       bzero ((char *) sched_reg_n_calls_crossed, max_regno * sizeof (int));
       bzero ((char *) sched_reg_live_length, max_regno * sizeof (int));
-      bcopy ((char *) reg_n_deaths, (char *) sched_reg_n_deaths,
-            max_regno * sizeof (short));
       init_alias_analysis ();
     }
   else
     {
-      sched_reg_n_deaths = 0;
       sched_reg_n_calls_crossed = 0;
       sched_reg_live_length = 0;
       bb_dead_regs = 0;
@@ -4866,7 +4922,10 @@ schedule_insns (dump_file)
 
          /* Split insns here to get max fine-grain parallelism.  */
          prev = PREV_INSN (insn);
-         if (reload_completed == 0)
+         /* It is probably not worthwhile to try to split again in the
+            second pass.  However, if flag_schedule_insns is not set,
+            the first and only (if any) scheduling pass is after reload.  */
+         if (reload_completed == 0 || ! flag_schedule_insns)
            {
              rtx last, first = PREV_INSN (insn);
              rtx notes = REG_NOTES (insn);
@@ -4960,35 +5019,35 @@ schedule_insns (dump_file)
          {
            if (dump_file)
              {
-               if (reg_live_length[regno] > sched_reg_live_length[regno])
+               if (REG_LIVE_LENGTH (regno) > sched_reg_live_length[regno])
                  fprintf (dump_file,
                           ";; register %d life shortened from %d to %d\n",
-                          regno, reg_live_length[regno],
+                          regno, REG_LIVE_LENGTH (regno),
                           sched_reg_live_length[regno]);
                /* Negative values are special; don't overwrite the current
                   reg_live_length value if it is negative.  */
-               else if (reg_live_length[regno] < sched_reg_live_length[regno]
-                        && reg_live_length[regno] >= 0)
+               else if (REG_LIVE_LENGTH (regno) < sched_reg_live_length[regno]
+                        && REG_LIVE_LENGTH (regno) >= 0)
                  fprintf (dump_file,
                           ";; register %d life extended from %d to %d\n",
-                          regno, reg_live_length[regno],
+                          regno, REG_LIVE_LENGTH (regno),
                           sched_reg_live_length[regno]);
 
-               if (! reg_n_calls_crossed[regno]
+               if (! REG_N_CALLS_CROSSED (regno)
                    && sched_reg_n_calls_crossed[regno])
                  fprintf (dump_file,
                           ";; register %d now crosses calls\n", regno);
-               else if (reg_n_calls_crossed[regno]
+               else if (REG_N_CALLS_CROSSED (regno)
                         && ! sched_reg_n_calls_crossed[regno]
-                        && reg_basic_block[regno] != REG_BLOCK_GLOBAL)
+                        && REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
                  fprintf (dump_file,
                           ";; register %d no longer crosses calls\n", regno);
 
              }
            /* Negative values are special; don't overwrite the current
               reg_live_length value if it is negative.  */
-           if (reg_live_length[regno] >= 0)
-             reg_live_length[regno] = sched_reg_live_length[regno];
+           if (REG_LIVE_LENGTH (regno) >= 0)
+             REG_LIVE_LENGTH (regno) = sched_reg_live_length[regno];
 
            /* We can't change the value of reg_n_calls_crossed to zero for
               pseudos which are live in more than one block.
@@ -5004,8 +5063,8 @@ schedule_insns (dump_file)
               Alternatively, we could try to correctly update basic block live
               at start here in sched, but that seems complicated.  */
            if (sched_reg_n_calls_crossed[regno]
-               || reg_basic_block[regno] != REG_BLOCK_GLOBAL)
-             reg_n_calls_crossed[regno] = sched_reg_n_calls_crossed[regno];
+               || REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
+             REG_N_CALLS_CROSSED (regno) = sched_reg_n_calls_crossed[regno];
          }
     }
 }