OSDN Git Service

* parse.y (check_static_final_variable_assignment_flag): Fix spelling.
[pf3gnuchains/gcc-fork.git] / gcc / regrename.c
index 816a5d2..19cc9e8 100644 (file)
    the Free Software Foundation, 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#define REG_OK_STRICT
+
 #include "config.h"
 #include "system.h"
-#include "tree.h"
 #include "rtl.h"
-#include "basic-block.h"
+#include "tm_p.h"
 #include "insn-config.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "flags.h"
+#include "basic-block.h"
+#include "reload.h"
 #include "output.h"
 #include "function.h"
 #include "recog.h"
-#include "resource.h"
+#include "flags.h"
+#include "obstack.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+#ifndef REGNO_MODE_OK_FOR_BASE_P
+#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
+#endif
+
+#ifndef REG_MODE_OK_FOR_BASE_P
+#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
+#endif
 
 static const char *const reg_class_names[] = REG_CLASS_NAMES;
 
-/* ??? Consider a more sparse data structure? */
-typedef struct def_uses
-  {
-    /* high bound of defs and uses */
-    int high_bound;
-
-    /* 1 if insn y defines a reg whose use crosses a call 
-       y is the ordinal position of the insn within the block */
-    sbitmap require_call_save_reg;
-
-    /* REGNO x INSN y  1 if insn y sets reg x */
-    sbitmap *defs;
-
-    /* REGNO x INSN y  The register class for this def */
-    enum reg_class *def_class;
-
-    /* REGNO x INSN y  1 if insn y uses reg x */
-    sbitmap *uses;
-
-    /* REGNO x INSN y  The register class for this use */
-    enum reg_class *use_class;
-  }
-def_uses;
-
-#define DU_REG_CLASS(rc,r,high_bound,i) (rc[r * high_bound + i])
-
-typedef struct ext_basic_blocks
-  {
-    /* n_basic_blocks x n_basic_blocks y  1 if bb y is in extended bb
-       having entry x */
-    sbitmap *basic_block;
-
-    /* n_basic_blocks x n_basic_blocks y  1 if bb y is an exit block */
-    sbitmap *exit;
-  }
-ext_basic_blocks;
-
-#define UID_RUID_HIGH_BOUND 64
-#define DESTINATION 1
-#define SOURCE 2
-
-static void build_def_use PARAMS ((int, ext_basic_blocks *, HARD_REG_SET *,
-                                  def_uses *, sbitmap *));
-static int replace_reg_in_block
-  PARAMS ((def_uses *, varray_type *, int, rtx, int));
-static int consider_def PARAMS ((rtx, int, def_uses *, int));
-static int consider_available PARAMS ((rtx, int, HARD_REG_SET *, int, def_uses *, int));
-static rtx rr_replace_reg PARAMS ((rtx, rtx, rtx, int, rtx, int *));
-static int consider_use PARAMS ((rtx, int, int, int));
-static int condmove_p PARAMS ((rtx));
-static void dump_def_use_chain PARAMS ((HARD_REG_SET *, def_uses *,
-                                       varray_type *));
-static void dump_ext_bb_info PARAMS ((int, ext_basic_blocks *));
-static void find_ext_basic_blocks PARAMS ((ext_basic_blocks *));
-static void find_one_ext_basic_block PARAMS ((int, basic_block, sbitmap *,
-                                             ext_basic_blocks *));
-static enum reg_class get_reg_class PARAMS ((rtx, rtx, int, enum reg_class));
-static rtx regno_first_use_in (int, rtx);
+struct du_chain
+{
+  struct du_chain *next_chain;
+  struct du_chain *next_use;
+
+  rtx insn;
+  rtx *loc;
+  enum reg_class class;
+  unsigned int need_caller_save_reg:1;
+};
+
+enum scan_actions
+{
+  note_reference,
+  terminate_all_read,
+  terminate_overlapping_read,
+  terminate_write,
+  terminate_dead,
+  mark_read,
+  mark_write
+};
+
+static const char * const scan_actions_name[] =
+{
+  "note_reference",
+  "terminate_all_read",
+  "terminate_overlapping_read",
+  "terminate_write",
+  "terminate_dead",
+  "mark_read",
+  "mark_write"
+};
+
+static struct obstack rename_obstack;
+
+static void do_replace PARAMS ((struct du_chain *, int));
+static void scan_rtx_reg PARAMS ((rtx, rtx *, enum reg_class,
+                                 enum scan_actions, enum op_type));
+static void scan_rtx_address PARAMS ((rtx, rtx *, enum reg_class,
+                                     enum scan_actions, enum machine_mode));
+static void scan_rtx PARAMS ((rtx, rtx *, enum reg_class,
+                             enum scan_actions, enum op_type));
+static struct du_chain *build_def_use PARAMS ((basic_block, HARD_REG_SET *));
+static void dump_def_use_chain PARAMS ((struct du_chain *));
 
 void
 regrename_optimize ()
 {
-  int b, eb, i, inum, r, rc, replace_ok;
-  rtx insn;
-  def_uses def_uses;
-  ext_basic_blocks ext_basic_blocks;
+  int b;
+  char *first_obj;
 
+  gcc_obstack_init (&rename_obstack);
+  first_obj = (char *) obstack_alloc (&rename_obstack, 0);
 
-  /* Registers used in a given class */
-  HARD_REG_SET class_regs;
+  for (b = 0; b < n_basic_blocks; b++)
+    {
+      basic_block bb = BASIC_BLOCK (b);
+      struct du_chain *all_chains = 0;
+      HARD_REG_SET regs_used;
+      HARD_REG_SET unavailable;
+      HARD_REG_SET regs_seen;
 
-  /* Registers available for use as renaming registers */
-  HARD_REG_SET avail_regs;
+      CLEAR_HARD_REG_SET (regs_used);
+      CLEAR_HARD_REG_SET (unavailable);
 
-  /* Registers used in the block */
-  HARD_REG_SET regs_used;
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "\nBasic block %d:\n", b);
 
-  /* Registers which have been used as renaming registers */
-  HARD_REG_SET renamed_regs;
+      all_chains = build_def_use (bb, &regs_used);
 
-  HARD_REG_SET global_live_at_end, global_live_at_start;
+      if (rtl_dump_file)
+       dump_def_use_chain (all_chains);
 
-  HARD_REG_SET null_bitmap, tmp_bitmap;
+      /* Available registers are not: used in the block, live at the start
+        live at the end, a register we've renamed to. */
+      REG_SET_TO_HARD_REG_SET (unavailable, bb->global_live_at_start);
+      REG_SET_TO_HARD_REG_SET (regs_seen, bb->global_live_at_end);
+      IOR_HARD_REG_SET (unavailable, regs_seen);
+      IOR_HARD_REG_SET (unavailable, regs_used);
 
-  /* 1 if insn y sets a register which is live at the end of the block */
-  sbitmap defs_live_exit;
+      /* Don't clobber traceback for noreturn functions.  */
+      if (frame_pointer_needed)
+       {
+         SET_HARD_REG_BIT (unavailable, FRAME_POINTER_REGNUM);
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+         SET_HARD_REG_BIT (unavailable, HARD_FRAME_POINTER_REGNUM);
+#endif
+       }
 
-  /* Mapping from insn y (ordinal position in block) to INSN_UID */
-  varray_type uid_ruid;
+      CLEAR_HARD_REG_SET (regs_seen);
+      while (all_chains)
+       {
+         int n_uses;
+         struct du_chain *this = all_chains;
+         struct du_chain *tmp, *last;
+         HARD_REG_SET this_unavailable;
+         int reg = REGNO (*this->loc), treg;
+         int nregs = HARD_REGNO_NREGS (reg, GET_MODE (*this->loc));
+         int i;
+
+         all_chains = this->next_chain;
+
+         /* Only rename once we've seen the reg more than once.  */
+         if (! TEST_HARD_REG_BIT (regs_seen, reg))
+           {
+             SET_HARD_REG_BIT (regs_seen, reg);
+             continue;
+           }
 
-  /* Mapping from insn y (ordinal position in block) to block id */
-  varray_type uid_rbid;
+         if (fixed_regs[reg] || global_regs[reg])
+           continue;
 
-  /* Ordinal position in block of defining insn */
-  int *def_idx;
+         COPY_HARD_REG_SET (this_unavailable, unavailable);
 
-  VARRAY_RTX_INIT (uid_ruid, UID_RUID_HIGH_BOUND + 1, "uid_ruid");
-  VARRAY_LONG_INIT (uid_rbid, UID_RUID_HIGH_BOUND + 1, "uid_rbid");
+         /* Find last entry on chain (which has the need_caller_save bit),
+            count number of uses, and narrow the set of registers we can
+            use for renaming.  */
+         n_uses = 0;
+         for (last = this; last->next_use; last = last->next_use)
+           {
+             n_uses++;
+             IOR_COMPL_HARD_REG_SET (this_unavailable,
+                                     reg_class_contents[last->class]);
+           }
+         if (n_uses < 1)
+           continue;
 
-  ext_basic_blocks.basic_block =
-    sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
-  sbitmap_vector_zero (ext_basic_blocks.basic_block, n_basic_blocks);
-  ext_basic_blocks.exit =
-    sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
-  sbitmap_vector_zero (ext_basic_blocks.exit, n_basic_blocks);
+         IOR_COMPL_HARD_REG_SET (this_unavailable,
+                                 reg_class_contents[last->class]);
 
-  find_ext_basic_blocks (&ext_basic_blocks);
+         if (last->need_caller_save_reg)
+           IOR_HARD_REG_SET (this_unavailable, call_used_reg_set);
 
-  def_uses.def_class = def_uses.use_class = 0;
+         /* Now potential_regs is a reasonable approximation, let's
+            have a closer look at each register still in there.  */
+         for (treg = 0; treg < FIRST_PSEUDO_REGISTER; treg++)
+           {
+             for (i = nregs - 1; i >= 0; --i)
+               if (TEST_HARD_REG_BIT (this_unavailable, treg+i)
+                   || fixed_regs[treg+i]
+                   || global_regs[treg+i]
+                   /* Can't use regs which aren't saved by the prologue.  */
+                   || (! regs_ever_live[treg+i] && ! call_used_regs[treg+i])
+#ifdef HARD_REGNO_RENAME_OK
+                   || ! HARD_REGNO_RENAME_OK (reg+i, treg+i)
+#endif
+                   )
+                 break;
+             if (i >= 0)
+               continue;
 
-  /* Build uid_ruid and uid_rbid for this extended basic block */
-  for (b = 0; b < n_basic_blocks; b++)
-    if (TEST_BIT (ext_basic_blocks.basic_block[b], b))
-      {
-       for (eb = def_uses.high_bound = 0; eb < n_basic_blocks; eb++)
-         {
-           if (TEST_BIT (ext_basic_blocks.basic_block[b], eb))
-             {
-               basic_block bb = BASIC_BLOCK (eb);
-               /* Calculate high bound for uid_ruid and allocate if necessary */
-               for (insn = bb->head;
-                    insn != NEXT_INSN (bb->end);
-                    def_uses.high_bound++, insn = NEXT_INSN (insn))
-                 {
-                   int uid_ruid_high_bound = VARRAY_SIZE (uid_ruid);
-                   if (def_uses.high_bound + 4 >= uid_ruid_high_bound)
-                     {
-                       VARRAY_GROW (uid_ruid, uid_ruid_high_bound * 2);
-                       VARRAY_GROW (uid_rbid, uid_ruid_high_bound * 2);
-                     }
-                   VARRAY_RTX (uid_ruid, def_uses.high_bound) = insn;
-                   VARRAY_LONG (uid_rbid, def_uses.high_bound) = eb;
-                 }
-             }
-         }
+             /* See whether it accepts all modes that occur in
+                definition and uses.  */
+             for (tmp = this; tmp; tmp = tmp->next_use)
+               if (! HARD_REGNO_MODE_OK (treg, GET_MODE (*tmp->loc)))
+                 break;
+             if (! tmp)
+               break;
+           }
 
-       CLEAR_HARD_REG_SET (null_bitmap);
-       CLEAR_HARD_REG_SET (class_regs);
-       CLEAR_HARD_REG_SET (regs_used);
-       CLEAR_HARD_REG_SET (avail_regs);
-       CLEAR_HARD_REG_SET (tmp_bitmap);
-       CLEAR_HARD_REG_SET (renamed_regs);
-
-       def_uses.defs =
-         sbitmap_vector_alloc (FIRST_PSEUDO_REGISTER, def_uses.high_bound + 1);
-       sbitmap_vector_zero (def_uses.defs, FIRST_PSEUDO_REGISTER);
-       def_uses.uses =
-         sbitmap_vector_alloc (FIRST_PSEUDO_REGISTER, def_uses.high_bound + 1);
-       sbitmap_vector_zero (def_uses.uses, FIRST_PSEUDO_REGISTER);
-       def_uses.require_call_save_reg = sbitmap_alloc (def_uses.high_bound + 1);
-       sbitmap_zero (def_uses.require_call_save_reg);
-       defs_live_exit = sbitmap_alloc (def_uses.high_bound + 1);
-       sbitmap_zero (defs_live_exit);
-
-       def_uses.def_class = xrealloc
-         (def_uses.def_class,
-          sizeof (enum reg_class) * FIRST_PSEUDO_REGISTER * def_uses.high_bound);
-
-       def_uses.use_class = xrealloc
-         (def_uses.use_class,
-          sizeof (enum reg_class) * FIRST_PSEUDO_REGISTER * def_uses.high_bound);
-
-       build_def_use (b, &ext_basic_blocks, &regs_used, &def_uses,
-                      &defs_live_exit);
-
-       if (rtl_dump_file)
-         {
-           dump_ext_bb_info (b, &ext_basic_blocks);
-           dump_def_use_chain (&global_live_at_end, &def_uses, &uid_ruid);
-         }
+         if (rtl_dump_file)
+           {
+             fprintf (rtl_dump_file, "Register %s in insn %d",
+                      reg_names[reg], INSN_UID (last->insn));
+             if (last->need_caller_save_reg)
+               fprintf (rtl_dump_file, " crosses a call");
+             }
 
-       /* Available registers are not: used in the block, live at the start,
-          live at the end, a register we've renamed to. */
-       /* ??? The current algorithm is pessimistic for extended basic blocks
-          as it just treats them as a big basic block. */
+         if (treg == FIRST_PSEUDO_REGISTER)
+           {
+             if (rtl_dump_file)
+               fprintf (rtl_dump_file, "; no available registers\n");
+             continue;
+           }
 
-       COPY_HARD_REG_SET (tmp_bitmap, regs_used);
-       REG_SET_TO_HARD_REG_SET (global_live_at_start, BASIC_BLOCK (b)->global_live_at_start);
-       IOR_HARD_REG_SET (tmp_bitmap, global_live_at_start);
-       for (eb = 0; eb < n_basic_blocks; eb++)
-         {
-           if (TEST_BIT (ext_basic_blocks.basic_block[b], eb))
-             {
-               basic_block bb = BASIC_BLOCK (eb);
-               REG_SET_TO_HARD_REG_SET (global_live_at_end, bb->global_live_at_end);
-               IOR_HARD_REG_SET (tmp_bitmap, global_live_at_end);
-             }
-         }
+         
+         for (i = nregs - 1; i >= 0; --i)
+           SET_HARD_REG_BIT (unavailable, treg+i);
+         do_replace (this, treg);
 
-       def_idx = xcalloc (def_uses.high_bound, sizeof (int));
+         if (rtl_dump_file)
+           fprintf (rtl_dump_file, ", renamed as %s\n", reg_names[treg]);
+       }
 
-       /* Only consider registers in this extended block and in this class
-          that are defined more than once.  Replace them if permissible. */
-       for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-         {
-           int avail_reg, ar_idx, def, def_cnt = 0, use_idx, call_idx;
+      obstack_free (&rename_obstack, first_obj);
+    }
 
-           if (!TEST_HARD_REG_BIT (regs_used, r)
-               || fixed_regs[r]
-               || r == FRAME_POINTER_REGNUM)
-             continue;
+  obstack_free (&rename_obstack, NULL);
 
-           /* Find def_idx[N] where hbound of N is the number of 
-              definitions of this register in this block. and def_idx
-              is the ordinal position of this insn in the block. */
-           for (i = 0, def_idx[def_cnt] = 0;
-                i < def_uses.high_bound;
-                i++)
-             {
-               if (TEST_BIT (def_uses.defs[r], i)
-                   && consider_def (VARRAY_RTX (uid_ruid, i), r,
-                                    &def_uses, i))
-                 {
-                   int first_use = 1;
-                   def_idx[def_cnt] = i;
-
-                   /* Only consider definitions that have a use. */
-                   for (use_idx = i + 1; use_idx < def_uses.high_bound;
-                        use_idx++)
-                     {
-                       if (TEST_BIT (def_uses.uses[r], use_idx))
-                         {
-                           if (consider_use (VARRAY_RTX (uid_ruid, use_idx), r,
-                                             VARRAY_LONG (uid_rbid, i),
-                                          VARRAY_LONG (uid_rbid, use_idx)))
-                             {
-                               if (first_use)
-                                 {
-                                   first_use = 0;
-                                   def_cnt++;
-                                 }
-                             }
-                           else
-                             {
-                               /* Don't consider def if we don't want this use */
-                               if (!first_use)
-                                 def_cnt--;
-                               break;
-                             }
-                         }
-                       if (TEST_BIT (def_uses.defs[r], use_idx))
-                         break;
-                     }
-                   /* Scan until the next def to avoid renaming
-                      parameter registers. */
-                   /* ??? consider using CALL_INSN_FUNCTION_USAGE */
-                   for (call_idx = i; call_idx <= use_idx; call_idx++)
-                     if (VARRAY_RTX (uid_ruid, call_idx)
-                         && GET_CODE (VARRAY_RTX (uid_ruid, call_idx))
-                         == CALL_INSN)
-                       {
-                         SET_BIT (def_uses.require_call_save_reg, i);
-                       }
-                 }
-             }
-           if (def_cnt < 2)
-             continue;
+  if (rtl_dump_file)
+    fputc ('\n', rtl_dump_file);
 
-           /* We have more than one def so rename until we exhaust
-              renaming registers. */
-           /* ??? Should we continue renaming round robin when we exhaust
-              renaming registers? */
-           for (def = 0; def < def_cnt - 1; def++)
-             {
-               if (!TEST_BIT (defs_live_exit, def_idx[def])
-                   && (GET_RTX_CLASS
-                       (GET_CODE (VARRAY_RTX (uid_ruid,
-                                              def_idx[def]))) == 'i'))
-                 {
-                   rtx reg_use = regno_first_use_in
-                   (r, PATTERN (VARRAY_RTX (uid_ruid, def_idx[def])));
-
-                   if (!reg_use)
-                     break;
-#ifdef STACK_REGS
-                   /* Don't bother with stacked float registers */
-                   if (GET_MODE_CLASS (GET_MODE (reg_use)) == MODE_FLOAT)
-                     break;
-#endif
-                   rc = (int) DU_REG_CLASS (def_uses.def_class,
-                                     r, def_uses.high_bound, def_idx[def]);
-                   COPY_HARD_REG_SET (avail_regs,
-                                  reg_class_contents[(enum reg_class) rc]);
-                   AND_COMPL_HARD_REG_SET (avail_regs, tmp_bitmap);
-                   AND_COMPL_HARD_REG_SET (avail_regs, renamed_regs);
-
-                   /* No available registers in this class */
-                   GO_IF_HARD_REG_EQUAL (avail_regs, null_bitmap,
-                                         no_available_regs);
-                   for (ar_idx = 0; ar_idx < FIRST_PSEUDO_REGISTER
-                        && TEST_HARD_REG_BIT (avail_regs, ar_idx); ar_idx++)
-                     ;
-                   if (ar_idx == FIRST_PSEUDO_REGISTER)
-                     goto no_available_regs;
-
-                   /* Only try register renaming if there is an available
-                      register in this class. */
-                   for (ar_idx = 0;
-                        ar_idx < FIRST_PSEUDO_REGISTER;
-                        ar_idx++)
-                     {
-                       avail_reg = reg_alloc_order[ar_idx];
-                       if (consider_available (reg_use, avail_reg, &avail_regs,
-                                               rc, &def_uses, def_idx[def]))
-                         break;
-                     }
-
-                   if (ar_idx == FIRST_PSEUDO_REGISTER)
-                     {
-                       if (rtl_dump_file)
-                         {
-                           fprintf (rtl_dump_file,
-                                    "Register %s in class %s",
-                                    reg_names[r], reg_class_names[rc]);
-                           fprintf (rtl_dump_file,
-                                    " in insn %d",
-                                    INSN_UID (VARRAY_RTX (uid_ruid,
-                                                          def_idx[def])));
-
-                           if (TEST_BIT (def_uses.require_call_save_reg,
-                                         def_idx[def]))
-                             fprintf (rtl_dump_file, " crosses a call");
-                           fprintf (rtl_dump_file, ". No available registers\n");
-                         }
-                       goto try_next_def;
-                     }
-
-                   SET_HARD_REG_BIT (renamed_regs, avail_reg);
-                   CLEAR_HARD_REG_BIT (avail_regs, avail_reg);
-
-                   /* Replace in destination.  Replace in source for
-                      remainder of block until new register is defined
-                      again */
-                   replace_ok = replace_reg_in_block
-                     (&def_uses, &uid_ruid, def_idx[def], reg_use, avail_reg);
-                   /* Replace failed, so restore previous register */
-                   if (!replace_ok)
-                     {
-                       replace_reg_in_block (&def_uses, &uid_ruid, def_idx[def],
-                                           gen_rtx_REG (GET_MODE (reg_use),
-                                                        avail_reg),
-                                             REGNO (reg_use));
-                       if (rtl_dump_file)
-                         fprintf (rtl_dump_file,
-                                  "Register %s in class %s Renaming as %s would not satisfy constraints\n",
-                                  reg_names[r], reg_class_names[rc],
-                                  reg_names[avail_reg]);
-                     }
-                   else if (rtl_dump_file)
-                     fprintf (rtl_dump_file,
-                      "Register %s in class %s Renamed as %s at insn %d\n",
-                              reg_names[r], reg_class_names[rc],
-                              reg_names[avail_reg],
-                           INSN_UID (VARRAY_RTX (uid_ruid, def_idx[def])));
-                 }
-             try_next_def:
-               continue;
-             }
-           sbitmap_zero (def_uses.defs[r]);
-         no_available_regs:
-           continue;
-         }
-       free (def_idx);
-       sbitmap_vector_free (def_uses.defs);
-       sbitmap_vector_free (def_uses.uses);
-       sbitmap_free (def_uses.require_call_save_reg);
-       sbitmap_free (defs_live_exit);
-       CLEAR_HARD_REG_SET (regs_used);
-       CLEAR_HARD_REG_SET (renamed_regs);
-
-       for (inum = 0; inum < (int) VARRAY_SIZE (uid_ruid); inum++)
-         VARRAY_RTX (uid_ruid, inum) = (rtx) 0;
-      }
+  count_or_remove_death_notes (NULL, 1);
+  update_life_info (NULL, UPDATE_LIFE_LOCAL,
+                   PROP_REG_INFO | PROP_DEATH_NOTES);
+}
 
-  sbitmap_vector_free (ext_basic_blocks.basic_block);
-  sbitmap_vector_free (ext_basic_blocks.exit);
+static void
+do_replace (chain, reg)
+     struct du_chain *chain;
+     int reg;
+{
+  while (chain)
+    {
+      *chain->loc = gen_rtx_REG (GET_MODE (*chain->loc), reg);
+      chain = chain->next_use;
+    }
 }
 
-/* Build def/use chain DU for extended basic block EBB having root B.
-   Also determine which regs are used, REGS_USED, and which insns define
-   a live at exit def, DEFS_LIVE_EXIT */
+
+static HARD_REG_SET *referenced_regs;
+static struct du_chain *open_chains;
+static struct du_chain *closed_chains;
 
 static void
-build_def_use (b, ebb, regs_used, du, defs_live_exit)
-     int b;
-     ext_basic_blocks *ebb;
-     HARD_REG_SET *regs_used;
-     def_uses *du;
-     sbitmap *defs_live_exit;
+scan_rtx_reg (insn, loc, class, action, type)
+     rtx insn;
+     rtx *loc;
+     enum reg_class class;
+     enum scan_actions action;
+     enum op_type type;
 {
-  rtx insn;
-  int eb, inum, r;
+  struct du_chain **p;
+  rtx x = *loc;
+  enum machine_mode mode = GET_MODE (x);
+  int this_regno = REGNO (x);
+  int this_nregs = HARD_REGNO_NREGS (this_regno, mode);
 
-  inum = 0;
-  for (eb = 0; eb < n_basic_blocks; eb++)
+  if (action == note_reference)
     {
-      basic_block bb = BASIC_BLOCK (eb);
-
-      if (!TEST_BIT (ebb->basic_block[b], eb))
-       continue;
+      while (this_nregs-- > 0)
+       SET_HARD_REG_BIT (*referenced_regs, this_regno + this_nregs);
+      return;
+    }
 
-      for (insn = bb->head;
-          insn != NEXT_INSN (bb->end);
-          inum++, insn = NEXT_INSN (insn))
+  if (action == mark_write)
+    {
+      if (type == OP_OUT)
        {
-         struct resources insn_res;
-         struct resources insn_sets;
+         struct du_chain *this = (struct du_chain *)
+           obstack_alloc (&rename_obstack, sizeof (struct du_chain));
+         this->next_use = 0;
+         this->next_chain = open_chains;
+         this->loc = loc;
+         this->insn = insn;
+         this->class = class;
+         this->need_caller_save_reg = 0;
+         open_chains = this;
+       }
+      return;
+    }
 
-         if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
-           continue;
+  if ((type == OP_OUT && action != terminate_write)
+      || (type != OP_OUT && action == terminate_write))
+    return;
 
-         CLEAR_RESOURCE (&insn_sets);
-         mark_set_resources (insn, &insn_sets, 0, MARK_DEST);
+  for (p = &open_chains; *p;)
+    {
+      struct du_chain *this = *p;
 
-         for (r = 0;
-              r < FIRST_PSEUDO_REGISTER;
-              r++)
-           {
-             if (!TEST_HARD_REG_BIT (insn_sets.regs, r))
-               continue;
+      /* Check if the chain has been terminated if it has then skip to
+        the next chain.
 
-             SET_HARD_REG_BIT (*regs_used, r);
-             if (REGNO_REG_SET_P (bb->global_live_at_end, r))
-               SET_BIT (*defs_live_exit, inum);
-             if (!insn_sets.memory)
-               SET_BIT (du->defs[r], inum);
-             DU_REG_CLASS (du->def_class, r, du->high_bound, inum) = get_reg_class
-               (insn, regno_first_use_in (r, PATTERN (insn)),
-                DESTINATION, NO_REGS);
-           }
+        This can happen when we've already appended the location to
+        the chain in Step 3, but are trying to hide in-out operands
+        from terminate_write in Step 5.  */
 
-         CLEAR_RESOURCE (&insn_res);
-         mark_referenced_resources (insn, &insn_res, 0);
+      if (*this->loc == cc0_rtx)
+       p = &this->next_chain;
+      else
+        {
+         int regno = REGNO (*this->loc);
+         int nregs = HARD_REGNO_NREGS (regno, GET_MODE (*this->loc));
+         int exact_match = (regno == this_regno && nregs == this_nregs);
 
-         for (r = 0;
-              r < FIRST_PSEUDO_REGISTER;
-              r++)
+         if (regno + nregs <= this_regno
+             || this_regno + this_nregs <= regno)
            {
-             if (!TEST_HARD_REG_BIT (insn_res.regs, r))
-               continue;
+             p = &this->next_chain;
+             continue;
+           }
 
-             SET_HARD_REG_BIT (*regs_used, r);
-             SET_BIT (du->uses[r], inum);
-             DU_REG_CLASS (du->use_class, r, du->high_bound, inum) = get_reg_class
-               (insn, regno_use_in (r, PATTERN (insn)),
-                SOURCE, NO_REGS);
+         if (action == mark_read)
+           {
+             if (! exact_match)
+               abort ();
+
+             /* ??? Class NO_REGS can happen if the md file makes use of 
+                EXTRA_CONSTRAINTS to match registers.  Which is arguably
+                wrong, but there we are.  Since we know not what this may
+                be replaced with, terminate the chain.  */
+             if (class != NO_REGS)
+               {
+                 this = (struct du_chain *)
+                   obstack_alloc (&rename_obstack, sizeof (struct du_chain));
+                 this->next_use = *p;
+                 this->next_chain = (*p)->next_chain;
+                 this->loc = loc;
+                 this->insn = insn;
+                 this->class = class;
+                 this->need_caller_save_reg = 0;
+                 *p = this;
+                 return;
+               }
            }
-       }
-    }
-  free_resource_info ();
-}
 
-/* Return nonzero if regno AVAIL_REG can replace REG_DEF for insns in UID_RUID
-   starting at insn DEF in def/use chain DU. */
+         if (action != terminate_overlapping_read || ! exact_match)
+           {
+             struct du_chain *next = this->next_chain;
 
-static int
-replace_reg_in_block (du, uid_ruid, def, reg_def, avail_reg)
-     def_uses *du;
-     varray_type *uid_ruid;
-     int def;
-     rtx reg_def;
-     int avail_reg;
-{
-  int du_idx, status = 1;
-  int r = REGNO (reg_def);
-  rtx death_note;
-  rtx new_reg = gen_rtx_REG (GET_MODE (reg_def), avail_reg);
-
-
-  rr_replace_reg (PATTERN (VARRAY_RTX (*uid_ruid, def)), reg_def,
-                 new_reg, DESTINATION, VARRAY_RTX (*uid_ruid, def),
-                 &status);
-  if (!status)
-    return status;
-
-  death_note = find_reg_note (VARRAY_RTX (*uid_ruid, def), REG_DEAD, reg_def);
-  if (!death_note)
-    death_note = find_reg_note (VARRAY_RTX (*uid_ruid, def), REG_UNUSED, reg_def);
-  if (death_note)
-    rr_replace_reg (death_note, reg_def, new_reg, 0,
-                   VARRAY_RTX (*uid_ruid, def), &status);
-
-  for (du_idx = def + 1; du_idx < du->high_bound; du_idx++)
-    {
-      rtx reg_use;
-      rtx new_reg;
-      if (GET_RTX_CLASS (GET_CODE (VARRAY_RTX (*uid_ruid, du_idx))) != 'i')
-       continue;
-      reg_use = regno_use_in (r, PATTERN (VARRAY_RTX (*uid_ruid, du_idx)));
+             /* Whether the terminated chain can be used for renaming
+                depends on the action and this being an exact match.
+                In either case, we remove this element from open_chains.  */
 
-      if (reg_use && TEST_BIT (du->uses[r], du_idx))
-       {
-         new_reg = gen_rtx_REG (GET_MODE (reg_use), avail_reg);
-         rr_replace_reg (PATTERN (VARRAY_RTX (*uid_ruid, du_idx)), reg_use,
-                         new_reg, SOURCE, VARRAY_RTX (*uid_ruid, du_idx),
-                         &status);
-         death_note = find_reg_note (VARRAY_RTX (*uid_ruid, du_idx),
-                                     REG_DEAD, reg_use);
-         if (!death_note)
-           death_note = find_reg_note (VARRAY_RTX (*uid_ruid, du_idx),
-                                       REG_UNUSED, reg_use);
-         if (death_note)
-           rr_replace_reg (death_note, reg_use, new_reg, 0,
-                           VARRAY_RTX (*uid_ruid, def), &status);
-         SET_BIT (du->uses[avail_reg], du_idx);
-         RESET_BIT (du->uses[r], du_idx);
-         if (!status)
-           return status;
+             if ((action == terminate_dead || action == terminate_write)
+                 && exact_match)
+               {
+                 this->next_chain = closed_chains;
+                 closed_chains = this;
+                 if (rtl_dump_file)
+                   fprintf (rtl_dump_file,
+                            "Closing chain %s at insn %d (%s)\n",
+                            reg_names[REGNO (*this->loc)], INSN_UID (insn),
+                            scan_actions_name[(int) action]);
+               }
+             else
+               {
+                 if (rtl_dump_file)
+                   fprintf (rtl_dump_file,
+                            "Discarding chain %s at insn %d (%s)\n",
+                            reg_names[REGNO (*this->loc)], INSN_UID (insn),
+                            scan_actions_name[(int) action]);
+               }
+             *p = next;
+           }
+         else
+           p = &this->next_chain;
        }
-      if (TEST_BIT (du->defs[r], du_idx))
-       break;
     }
-  return status;
 }
 
-/* Try to replace REG_USE in X with REG_SUB if INSN has a REPLACE_TYPE.
-   STATUS is zero if the resulting pattern is not valid. */
+/* Adapted from find_reloads_address_1.  CLASS is INDEX_REG_CLASS or
+   BASE_REG_CLASS depending on how the register is being considered.  */
 
-static rtx
-rr_replace_reg (x, reg_use, reg_sub, replace_type, insn, status)
-     rtx x;
-     rtx reg_use;
-     rtx reg_sub;
-     int replace_type;
+static void
+scan_rtx_address (insn, loc, class, action, mode)
      rtx insn;
-     int *status;
+     rtx *loc;
+     enum reg_class class;
+     enum scan_actions action;
+     enum machine_mode mode;
 {
-  enum rtx_code code;
-  int i;
+  rtx x = *loc;
+  RTX_CODE code = GET_CODE (x);
   const char *fmt;
-  int n;
+  int i, j;
 
-  if (x == 0)
-    return x;
+  if (action == mark_write)
+    return;
 
-  code = GET_CODE (x);
   switch (code)
     {
-    case REG:
-      if (REGNO (x) == REGNO (reg_use))
-       {
-         if (GET_MODE (x) == GET_MODE (reg_use))
-           return reg_sub;
-         else
-           return gen_rtx_REG (GET_MODE (x), REGNO (reg_use));
-       }
-      return x;
+    case PLUS:
+      {
+       rtx orig_op0 = XEXP (x, 0);
+       rtx orig_op1 = XEXP (x, 1);
+       RTX_CODE code0 = GET_CODE (orig_op0);
+       RTX_CODE code1 = GET_CODE (orig_op1);
+       rtx op0 = orig_op0;
+       rtx op1 = orig_op1;
+       rtx *locI = NULL;
+       rtx *locB = NULL;
+
+       if (GET_CODE (op0) == SUBREG)
+         {
+           op0 = SUBREG_REG (op0);
+           code0 = GET_CODE (op0);
+         }
 
-    case SET:
-      if (replace_type == DESTINATION)
-       SET_DEST (x) = rr_replace_reg (SET_DEST (x), reg_use, reg_sub,
-                                      replace_type, insn, status);
-      else if (replace_type == SOURCE)
-       {
-         int dest_subregno;
+       if (GET_CODE (op1) == SUBREG)
+         {
+           op1 = SUBREG_REG (op1);
+           code1 = GET_CODE (op1);
+         }
 
-         if (GET_CODE (SET_DEST (x)) == SUBREG)
-           dest_subregno = REGNO (XEXP (SET_DEST (x), 0));
-         else
-           dest_subregno = 0;
-
-         SET_SRC (x) = rr_replace_reg (SET_SRC (x), reg_use, reg_sub,
-                                       replace_type, insn, status);
-         /* If the replacement register is not part of the source
-            then it may be part of a source mem operand. */
-         if (GET_CODE (SET_DEST (x)) == MEM
-             || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
-             || GET_CODE (SET_DEST (x)) == SIGN_EXTRACT
-             || GET_CODE (SET_DEST (x)) == STRICT_LOW_PART)
-           SET_DEST (x) = rr_replace_reg (SET_DEST (x), reg_use, reg_sub,
-                                          replace_type, insn, status);
-         /* shared rtl sanity check */
-         if (dest_subregno
-             && dest_subregno != REGNO (XEXP (SET_DEST (x), 0)))
-           {
-             *status = 0;
-             return x;
-           }
-       }
+       if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
+           || code0 == ZERO_EXTEND || code1 == MEM)
+         {
+           locI = &XEXP (x, 0);
+           locB = &XEXP (x, 1);
+         }
+       else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
+                || code1 == ZERO_EXTEND || code0 == MEM)
+         {
+           locI = &XEXP (x, 1);
+           locB = &XEXP (x, 0);
+         }
+       else if (code0 == CONST_INT || code0 == CONST
+                || code0 == SYMBOL_REF || code0 == LABEL_REF)
+         locB = &XEXP (x, 1);
+       else if (code1 == CONST_INT || code1 == CONST
+                || code1 == SYMBOL_REF || code1 == LABEL_REF)
+         locB = &XEXP (x, 0);
+       else if (code0 == REG && code1 == REG)
+         {
+           int index_op;
+
+           if (REG_OK_FOR_INDEX_P (op0)
+               && REG_MODE_OK_FOR_BASE_P (op1, mode))
+             index_op = 0;
+           else if (REG_OK_FOR_INDEX_P (op1)
+                    && REG_MODE_OK_FOR_BASE_P (op0, mode))
+             index_op = 1;
+           else if (REG_MODE_OK_FOR_BASE_P (op1, mode))
+             index_op = 0;
+           else if (REG_MODE_OK_FOR_BASE_P (op0, mode))
+             index_op = 1;
+           else if (REG_OK_FOR_INDEX_P (op1))
+             index_op = 1;
+           else
+             index_op = 0;
+
+           locI = &XEXP (x, index_op);
+           locB = &XEXP (x, !index_op);
+         }
+       else if (code0 == REG)
+         {
+           locI = &XEXP (x, 0);
+           locB = &XEXP (x, 1);
+         }
+       else if (code1 == REG)
+         {
+           locI = &XEXP (x, 1);
+           locB = &XEXP (x, 0);
+         }
 
-      n = recog_memoized (insn);
-      if (n >= 0)
-       {
-         int id;
-         extract_insn (insn);
+       if (locI)
+         scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode);
+       if (locB)
+         scan_rtx_address (insn, locB, BASE_REG_CLASS, action, mode);
+       return;
+      }
 
-         /* Any MATCH_DUP's which are REGs must still match */
-         for (id = insn_data[n].n_dups - 1; id >= 0; id--)
-           {
-             int opno = recog_data.dup_num[id];
-             if (GET_CODE (*recog_data.dup_loc[id]) == REG
-                 && GET_CODE (*recog_data.operand_loc[opno]) == REG
-                 && (REGNO (*recog_data.dup_loc[id]) !=
-                     REGNO (*recog_data.operand_loc[opno])))
-               *status = 0;
-           }
+    case POST_INC:
+    case POST_DEC:
+    case POST_MODIFY:
+    case PRE_INC:
+    case PRE_DEC:
+    case PRE_MODIFY:
+#ifndef AUTO_INC_DEC
+      /* If the target doesn't claim to handle autoinc, this must be
+        something special, like a stack push.  Kill this chain.  */
+      action = terminate_all_read;
+#endif
+      break;
 
-         if (!constrain_operands (1))
-           {
-             *status = 0;
-             validate_replace_rtx (reg_sub, reg_use, insn);
-           }
-       }
-      else
-       *status = 0;
+    case MEM:
+      scan_rtx_address (insn, &XEXP (x, 0), BASE_REG_CLASS, action,
+                       GET_MODE (x));
+      return;
 
-      return x;
+    case REG:
+      scan_rtx_reg (insn, loc, class, action, OP_IN);
+      return;
 
     default:
       break;
@@ -650,401 +521,323 @@ rr_replace_reg (x, reg_use, reg_sub, replace_type, insn, status)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       XEXP (x, i) = rr_replace_reg (XEXP (x, i), reg_use, reg_sub,
-                                     replace_type, insn, status);
-      if (fmt[i] == 'E')
-       {
-         register int xv;
-         for (xv = 0; xv < XVECLEN (x, i); xv++)
-           {
-             XVECEXP (x, i, xv) = rr_replace_reg (XVECEXP (x, i, xv), reg_use,
-                                               reg_sub, replace_type, insn,
-                                                  status);
-             n = recog_memoized (insn);
-             if (n >= 0)
-               {
-                 extract_insn (insn);
-                 if (!constrain_operands (1))
-                   {
-                     *status = 0;
-                     validate_replace_rtx (reg_sub, reg_use, insn);
-                   }
-               }
-             else
-               *status = 0;
-           }
-       }
+       scan_rtx_address (insn, &XEXP (x, i), class, action, mode);
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         scan_rtx_address (insn, &XVECEXP (x, i, j), class, action, mode);
     }
-  return x;
 }
 
-/* Can REGNO in INSN be considered for renaming, given def INUM in d/u
-   chain DU? */
-
-static int
-consider_def (insn, regno, du, inum)
+static void
+scan_rtx (insn, loc, class, action, type)
      rtx insn;
-     int regno;
-     def_uses *du;
-     int inum;
+     rtx *loc;
+     enum reg_class class;
+     enum scan_actions action;
+     enum op_type type;
 {
-  /* Don't rename windowed registers across a call */
-#ifdef INCOMING_REGNO
-  if (TEST_BIT (du->require_call_save_reg, inum)
-      && INCOMING_REGNO (regno) != regno)
-    return 0;
-#endif
-
-  /* Don't consider conditional moves.  Predicate architectures may
-     use two complementary conditional moves and the regno shouldn't change */
-  if (condmove_p (insn))
-    return 0;
-
-  /* Don't rename call used registers across a call */
-  if (!(GET_CODE (insn) == CALL_INSN
-       && TEST_HARD_REG_BIT (call_used_reg_set, regno)))
-    return 1;
-  else
-    return 0;
-}
-
-/* Can the use of REGNO in INSN of block USE_BLOCK be considered for renaming
-   for a def in def_block? */
+  const char *fmt;
+  rtx x = *loc;
+  enum rtx_code code = GET_CODE (x);
+  int i, j;
 
-static int
-consider_use (insn, regno, def_block, use_block)
-     rtx insn;
-     int regno;
-     int def_block;
-     int use_block;
-{
-  rtx reg_use;
-  edge e;
-  basic_block ub = BASIC_BLOCK (use_block);
+  code = GET_CODE (x);
+  switch (code)
+    {
+    case CONST:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case LABEL_REF:
+    case CC0:
+    case PC:
+      return;
 
-  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
-    return 0;
+    case REG:
+      scan_rtx_reg (insn, loc, class, action, type);
+      return;
 
-  /* If a use's basic block is different than the def's basic block, 
-     then insure another predecessor does not also define this register */
-  if (def_block != use_block)
-    for (e = ub->pred; e; e = e->pred_next)
-      {
-       if (e->src->index != def_block
-           && e->src->index != -1
-           && REGNO_REG_SET_P (BASIC_BLOCK (e->src->index)->global_live_at_end, regno))
-         return 0;
-      }
+    case MEM:
+      scan_rtx_address (insn, &XEXP (x, 0), BASE_REG_CLASS, action,
+                       GET_MODE (x));
+      return;
 
-  /* Don't consider conditional moves.  Predicate architectures may
-     use two complementary conditional moves and the regno shouldn't change */
+    case SET:
+      scan_rtx (insn, &SET_SRC (x), class, action, OP_IN);
+      scan_rtx (insn, &SET_DEST (x), class, action, OP_OUT);
+      return;
+
+    case STRICT_LOW_PART:
+      scan_rtx (insn, &XEXP (x, 0), class, action, OP_INOUT);
+      return;
+
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT: 
+      scan_rtx (insn, &XEXP (x, 0), class, action,
+               type == OP_IN ? OP_IN : OP_INOUT);
+      scan_rtx (insn, &XEXP (x, 1), class, action, OP_IN);
+      scan_rtx (insn, &XEXP (x, 2), class, action, OP_IN);
+      return;
+
+    case POST_INC:
+    case PRE_INC:
+    case POST_DEC:
+    case PRE_DEC:
+    case POST_MODIFY:
+    case PRE_MODIFY:
+      /* Should only happen inside MEM.  */
+      abort ();
+
+    case CLOBBER:
+      scan_rtx (insn, &SET_DEST (x), class, action, OP_OUT);
+      return;
+
+    case EXPR_LIST:
+      scan_rtx (insn, &XEXP (x, 0), class, action, type);
+      if (XEXP (x, 1))
+       scan_rtx (insn, &XEXP (x, 1), class, action, type);
+      return;
 
-  if (condmove_p (insn))
-    return 0;
+    default:
+      break;
+    }
 
-  reg_use = regno_first_use_in (regno, PATTERN (insn));
-  if (reg_use)
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      /* Don't consider multi-reg values. */
-      if (HARD_REGNO_NREGS (regno, GET_MODE (reg_use)) != 1
-         && GET_MODE (reg_use) != CCmode)
-       return 0;
-
-      /* Don't consider register if the only use is in a USE */
-      if (reg_mentioned_p (gen_rtx_USE (VOIDmode, reg_use),
-                          PATTERN (insn)))
-       return 0;
-      else
-       return 1;
+      if (fmt[i] == 'e')
+       scan_rtx (insn, &XEXP (x, i), class, action, type);
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         scan_rtx (insn, &XVECEXP (x, i, j), class, action, type);
     }
-  else
-    return 0;
 }
 
-/* Can REG_USE be replaced by regno AVAIL_REG if it is in AVAIL_REGS
-   and it is in regclass RC, given insn INUM of def/use chain DU? */
-
-static int
-consider_available (reg_use, avail_reg, avail_regs, rc, du, inum)
-     rtx reg_use;
-     int avail_reg;
-     HARD_REG_SET *avail_regs;
-     int rc;
-     def_uses *du;
-     int inum;
+/* Build def/use chain */
+
+static struct du_chain *
+build_def_use (bb, regs_used)
+     basic_block bb;
+     HARD_REG_SET *regs_used;
 {
-  if (!TEST_HARD_REG_BIT (*avail_regs, avail_reg))
-    return 0;
+  rtx insn;
 
-#ifdef HARD_REGNO_RENAME_OK
-  if (!HARD_REGNO_RENAME_OK (REGNO (reg_use), avail_reg))
-    return 0;
-#endif
+  open_chains = closed_chains = NULL;
+  referenced_regs = regs_used;
 
-  /* Don't consider windowed leaf registers which will be renamed by
-     leaf_renumber_regs */
-#ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    if (LEAF_REG_REMAP (avail_reg) < 0)
-      return 0;
-#endif
+  for (insn = bb->head; ; insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+       {
+         int n_ops;
+         rtx note;
+         rtx old_operands[MAX_RECOG_OPERANDS];
+         rtx old_dups[MAX_DUP_OPERANDS];
+         int i;
+         int alt;
+         int predicated;
+
+         /* Record all mentioned registers in regs_used.  */
+         scan_rtx (insn, &PATTERN (insn), NO_REGS, note_reference, OP_IN);
+
+         /* Process the insn, determining its effect on the def-use
+            chains.  We perform the following steps with the register
+            references in the insn:
+            (1) Any read that overlaps an open chain, but doesn't exactly
+                match, causes that chain to be closed.  We can't deal
+                with overlaps yet.
+            (2) Any read outside an operand causes any chain it overlaps
+                with to be closed, since we can't replace it.
+            (3) Any read inside an operand is added if there's already
+                an open chain for it.
+            (4) For any REG_DEAD note we find, close open chains that
+                overlap it.
+            (5) For any write we find, close open chains that overlap it.
+            (6) For any write we find in an operand, make a new chain.
+            (7) For any REG_UNUSED, close any chains we just opened.  */
 
-  /* A register is considered available if it is available at the beginning of
-     the basic block.  We may want to refine this to when a register becomes
-     available within the block.  We don't consider multi-reg values. */
-  /* ??? Consider a representation that would allow multi-reg support? */
-  if (!TEST_HARD_REG_BIT (reg_class_contents[(enum reg_class) rc], avail_reg)
-      || !HARD_REGNO_MODE_OK (avail_reg, GET_MODE (reg_use))
-      || (HARD_REGNO_NREGS (avail_reg, GET_MODE (reg_use)) != 1
-         && GET_MODE (reg_use) != CCmode)
-      || (call_fixed_regs[avail_reg]
-#ifdef HARD_REGNO_RENAME_OK
-         && !HARD_REGNO_RENAME_OK (REGNO (reg_use), avail_reg)
-#endif
-      )
-      || (TEST_BIT (du->require_call_save_reg, inum)
-         && (call_used_regs[avail_reg] || call_used_regs[REGNO (reg_use)]
-         )))
-    return 0;
-
-  /* If register is a callee-saved register it must be saved in the frame. 
-     call saved registers can not be added to regs_ever_live after reload,
-     as it would invalidate most elimination offsets */
-  if (regs_ever_live[avail_reg] || call_used_regs[avail_reg]
-      || (avail_reg == PIC_OFFSET_TABLE_REGNUM
-         && flag_pic && (current_function_uses_pic_offset_table)))
-    return 1;
-
-  return 0;
-}
+         extract_insn (insn);
+         constrain_operands (1);
+         preprocess_constraints ();
+         alt = which_alternative;
+         n_ops = recog_data.n_operands;
 
-/* Return 1 if INSN is a conditional move */
+         /* Simplify the code below by rewriting things to reflect
+            matching constraints.  Also promote OP_OUT to OP_INOUT
+            in predicated instructions.  */
 
-static int
-condmove_p (insn)
-     rtx insn;
-{
-  if (GET_CODE (insn) == INSN
-      && GET_CODE (PATTERN (insn)) == SET
-      && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)
-    return 1;
-  return 0;
-}
+         predicated = GET_CODE (PATTERN (insn)) == COND_EXEC;
+         for (i = 0; i < n_ops; ++i)
+           {
+             int matches = recog_op_alt[i][alt].matches;
+             if (matches >= 0)
+               recog_op_alt[i][alt].class = recog_op_alt[matches][alt].class;
+             if (matches >= 0 || recog_op_alt[i][alt].matched >= 0
+                 || (predicated && recog_data.operand_type[i] == OP_OUT))
+               recog_data.operand_type[i] = OP_INOUT;
+           }
 
-/* Searches X for the first reference to REGNO, returning the rtx of the
-   reference found if any.  Otherwise, returns NULL_RTX.  */
+         /* Step 1: Close chains for which we have overlapping reads.  */
+         for (i = 0; i < n_ops; i++)
+           scan_rtx (insn, recog_data.operand_loc[i],
+                     NO_REGS, terminate_overlapping_read,
+                     recog_data.operand_type[i]);
 
-static rtx
-regno_first_use_in (regno, x)
-     int regno;
-     rtx x;
-{
-  register const char *fmt;
-  int i, j;
-  rtx tem;
+         /* Step 2: Close chains for which we have reads outside operands.
+            We do this by munging all operands into CC0, and closing 
+            everything remaining.  */
 
-  if (GET_CODE (x) == REG && REGNO (x) == regno)
-    return x;
+         for (i = 0; i < n_ops; i++)
+           {
+             old_operands[i] = recog_data.operand[i];
+             /* Don't squash match_operator or match_parallel here, since
+                we don't know that all of the contained registers are 
+                reachable by proper operands.  */
+             if (recog_data.constraints[i][0] == '\0')
+               continue;
+             *recog_data.operand_loc[i] = cc0_rtx;
+           }
+         for (i = 0; i < recog_data.n_dups; i++)
+           {
+             old_dups[i] = *recog_data.dup_loc[i];
+             *recog_data.dup_loc[i] = cc0_rtx;
+           }
 
-  fmt = GET_RTX_FORMAT (GET_CODE (x));
-  for (i = 0; i <= GET_RTX_LENGTH (GET_CODE (x)) - 1; i++)
-    {
-      if (fmt[i] == 'e')
-       {
-         if ((tem = regno_first_use_in (regno, XEXP (x, i))))
-           return tem;
-       }
-      else if (fmt[i] == 'E')
-       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         if ((tem = regno_first_use_in (regno, XVECEXP (x, i, j))))
-           return tem;
-    }
+         scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_all_read, OP_IN);
 
-  return NULL_RTX;
-}
+         for (i = 0; i < recog_data.n_dups; i++)
+           *recog_data.dup_loc[i] = old_dups[i];
+         for (i = 0; i < n_ops; i++)
+           *recog_data.operand_loc[i] = old_operands[i];
 
-/* Dump def/use chain DU to RTL_DUMP_FILE, given insns in UID_RUID and
-   which regs are live at end, GLOBAL_LIVE_AT_END */
+         /* Step 2B: Can't rename function call argument registers.  */
+         if (GET_CODE (insn) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (insn))
+           scan_rtx (insn, &CALL_INSN_FUNCTION_USAGE (insn),
+                     NO_REGS, terminate_all_read, OP_IN);
 
-static void
-dump_def_use_chain (global_live_at_end, du, uid_ruid)
-     HARD_REG_SET *global_live_at_end;
-     def_uses *du;
-     varray_type *uid_ruid;
-{
-  int r, inum;
+         /* Step 3: Append to chains for reads inside operands.  */
+         for (i = 0; i < n_ops + recog_data.n_dups; i++)
+           {
+             int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
+             rtx *loc = (i < n_ops
+                         ? recog_data.operand_loc[opn]
+                         : recog_data.dup_loc[i - n_ops]);
+             enum reg_class class = recog_op_alt[opn][alt].class;
+             enum op_type type = recog_data.operand_type[opn];
+
+             /* Don't scan match_operand here, since we've no reg class
+                information to pass down.  Any operands that we could
+                substitute in will be represented elsewhere.  */
+             if (recog_data.constraints[opn][0] == '\0')
+               continue;
 
-  for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-    {
-      int set = 0;
-      for (inum = 0;
-          inum <= du->high_bound;
-          inum++)
-       {
-         rtx insn = VARRAY_RTX (*uid_ruid, inum);
-#if 0
-         if (!insn
-             || GET_RTX_CLASS (GET_CODE
-                               (insn)) != 'i')
-           continue;
-         reg_use = regno_first_use_in (r, PATTERN (insn));
-         if (!reg_use)
-           continue;
-#endif
-         if (!set && (TEST_BIT (du->defs[r], inum)
-                      || TEST_BIT (du->uses[r], inum)))
+             if (recog_op_alt[opn][alt].is_address)
+               scan_rtx_address (insn, loc, class, mark_read, VOIDmode);
+             else
+               scan_rtx (insn, loc, class, mark_read, type);
+           }
+
+         /* Step 4: Close chains for registers that die here.
+            Also record updates for REG_INC notes.  */
+         for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
            {
-             fprintf (rtl_dump_file, "Register %s: ", reg_names[r]);
-             if (fixed_regs[r])
-               fprintf (rtl_dump_file, "Fixed ");
-             else if (call_fixed_regs[r])
-               fprintf (rtl_dump_file, "Call Fixed ");
-             if (TEST_HARD_REG_BIT (*global_live_at_end, r))
-               fprintf (rtl_dump_file, "Live at Exit ");
-             set = 1;
+             if (REG_NOTE_KIND (note) == REG_DEAD)
+               scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead, OP_IN);
+             else if (REG_NOTE_KIND (note) == REG_INC)
+               scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_read, OP_INOUT);
            }
-         if (TEST_BIT (du->defs[r], inum))
-           fprintf (rtl_dump_file, "=%d ", INSN_UID (insn));
-         if (TEST_BIT (du->uses[r], inum))
-           fprintf (rtl_dump_file, "%d ", INSN_UID (insn));
-       }
-      if (set)
-       fprintf (rtl_dump_file, "\n");
-    }
-}
 
-/* Dump info for extended basic block EBB having root EB */
+         /* Step 4B: If this is a call, any chain live at this point
+            requires a caller-saved reg.  */
+         if (GET_CODE (insn) == CALL_INSN)
+           {
+             struct du_chain *p;
+             for (p = open_chains; p; p = p->next_chain)
+               {
+                 struct du_chain *p2;
+                 for (p2 = p; p2->next_use; p2 = p2->next_use)
+                   /* nothing */;
+                 p2->need_caller_save_reg = 1;
+               }
+           }
 
-static void
-dump_ext_bb_info (eb, ebb)
-     int eb;
-     ext_basic_blocks *ebb;
-{
-  int b;
+         /* Step 5: Close open chains that overlap writes.  Similar to
+            step 2, we hide in-out operands, since we do not want to
+            close these chains.  */
 
-  {
-    int have_ebb = 0;
-    for (b = 0; b < n_basic_blocks; b++)
-      {
-       if (TEST_BIT (ebb->basic_block[eb], b))
-         {
-           if (!have_ebb)
-             {
-#ifndef RENAME_EXTENDED_BLOCKS
-               fprintf (rtl_dump_file, "\nBasic block %d: ", b);
-#else
-               fprintf (rtl_dump_file, "\nExtended basic block %d: ", b);
-#endif
-               have_ebb = 1;
-             }
-           fprintf (rtl_dump_file, "%d ", b);
-         }
-       if (TEST_BIT (ebb->exit[eb], b))
-         fprintf (rtl_dump_file, "(exit) ");
-      }
-    if (have_ebb)
-      fprintf (rtl_dump_file, "\n");
-  }
-}
+         for (i = 0; i < n_ops; i++)
+           {
+             old_operands[i] = recog_data.operand[i];
+             if (recog_data.operand_type[i] == OP_INOUT)
+               *recog_data.operand_loc[i] = cc0_rtx;
+           }
+         for (i = 0; i < recog_data.n_dups; i++)
+           {
+             int opn = recog_data.dup_num[i];
+             old_dups[i] = *recog_data.dup_loc[i];
+             if (recog_data.operand_type[opn] == OP_INOUT)
+               *recog_data.dup_loc[i] = cc0_rtx;
+           }
 
-/* Initialize EBB with extended basic block info if RENAME_EXTENDED_BLOCKS is
-   defined.  Otherwise just use basic blocks */
+         scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN);
 
-static void
-find_ext_basic_blocks (ebb)
-     ext_basic_blocks *ebb;
-{
-  sbitmap bb_processed;
-  int b;
+         for (i = 0; i < recog_data.n_dups; i++)
+           *recog_data.dup_loc[i] = old_dups[i];
+         for (i = 0; i < n_ops; i++)
+           *recog_data.operand_loc[i] = old_operands[i];
 
-  bb_processed = sbitmap_alloc (n_basic_blocks);
-  sbitmap_zero (bb_processed);
+         /* Step 6: Begin new chains for writes inside operands.  */
+         /* ??? Many targets have output constraints on the SET_DEST
+            of a call insn, which is stupid, since these are certainly
+            ABI defined hard registers.  Don't change calls at all.  */
+         if (GET_CODE (insn) != CALL_INSN)
+           for (i = 0; i < n_ops + recog_data.n_dups; i++)
+             {
+               int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
+               rtx *loc = (i < n_ops
+                           ? recog_data.operand_loc[opn]
+                           : recog_data.dup_loc[i - n_ops]);
+               enum reg_class class = recog_op_alt[opn][alt].class;
+
+               if (recog_data.operand_type[opn] == OP_OUT)
+                 scan_rtx (insn, loc, class, mark_write, OP_OUT);
+             }
 
-#ifndef RENAME_EXTENDED_BLOCKS
-  for (b = 0; b < n_basic_blocks; b++)
-    {
-      basic_block bb = BASIC_BLOCK (b);
-      SET_BIT (ebb->basic_block[bb->index], bb->index);
-    }
-#else
-  for (b = 0; b < n_basic_blocks; b++)
-    {
-      basic_block bb = BASIC_BLOCK (b);
-      if (!TEST_BIT (bb_processed, b))
-       {
-         find_one_ext_basic_block (bb->index, bb, &bb_processed, ebb);
+         /* Step 7: Close chains for registers that were never
+            really used here.  */
+         for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+           if (REG_NOTE_KIND (note) == REG_UNUSED)
+             scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead, OP_IN);
        }
+      if (insn == bb->end)
+       break;
     }
-#endif
-  sbitmap_free (bb_processed);
+
+  /* Since we close every chain when we find a REG_DEAD note, anything that
+     is still open lives past the basic block, so it can't be renamed.  */
+  return closed_chains;
 }
 
-/* Find one extended basic block EBB having root ENTRY containing block
-   BB */
+/* Dump all def/use chains in CHAINS to RTL_DUMP_FILE.  They are
+   printed in reverse order as that's how we build them.  */
 
 static void
-find_one_ext_basic_block (entry, bb, bb_processed, ebb)
-     int entry;
-     basic_block bb;
-     sbitmap *bb_processed;
-     ext_basic_blocks *ebb;
+dump_def_use_chain (chains)
+     struct du_chain *chains;
 {
-  edge e;
-
-  if (!TEST_BIT (*bb_processed, bb->index))
+  while (chains)
     {
-      SET_BIT (ebb->basic_block[entry], bb->index);
-      SET_BIT (*bb_processed, bb->index);
+      struct du_chain *this = chains;
+      int r = REGNO (*this->loc);
+      int nregs = HARD_REGNO_NREGS (r, GET_MODE (*this->loc));
+      fprintf (rtl_dump_file, "Register %s (%d):", reg_names[r], nregs);
+      while (this)
+       {
+         fprintf (rtl_dump_file, " %d [%s]", INSN_UID (this->insn),
+                  reg_class_names[this->class]);
+         this = this->next_use;
+       }
+      fprintf (rtl_dump_file, "\n");
+      chains = chains->next_chain;
     }
-
-  for (e = bb->succ; e; e = e->succ_next)
-    if (!TEST_BIT (*bb_processed, e->dest->index))
-      {
-       if (!e->dest->pred->pred_next
-           && (!TEST_BIT (*bb_processed, e->dest->index)))
-         {
-           find_one_ext_basic_block (entry, e->dest, bb_processed, ebb);
-         }
-       else
-         {
-           SET_BIT (ebb->exit[entry], bb->index);
-         }
-      }
-}
-
-/* Find the register class for register REG_USE having TYPE (DESTINATION or
-   SOURCE) in INSN.  Use DEFAULT_CLASS if we cannot determine a class. */
-
-static enum reg_class
-get_reg_class (insn, reg_use, type, default_class)
-     rtx insn;
-     rtx reg_use;
-     int type;
-     enum reg_class default_class;
-{
-  int alt, id = 0;
-
-  extract_insn (insn);
-  constrain_operands (1);
-  alt = which_alternative;
-
-  preprocess_constraints ();
-
-  if (type == DESTINATION)
-    for (id = 0; id < recog_data.n_operands; id++)
-      {
-       if (rtx_equal_p (recog_data.operand[id], reg_use))
-         break;
-      }
-  else if (type == SOURCE)
-    for (id = recog_data.n_operands - 1; id >= 0; id--)
-      {
-       if (rtx_equal_p (recog_data.operand[id], reg_use))
-         break;
-      }
-
-  if (id == -1 || id == recog_data.n_operands)
-    return default_class;
-
-  return recog_op_alt[id][alt].class;
 }