OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / regrename.c
index 5078585..afee0d7 100644 (file)
@@ -1,22 +1,22 @@
 /* Register renaming for the GNU compiler.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #define REG_OK_STRICT
 
@@ -57,11 +57,11 @@ struct du_chain
   rtx *loc;
   enum reg_class class;
   unsigned int need_caller_save_reg:1;
+  unsigned int earlyclobber:1;
 };
 
 enum scan_actions
 {
-  note_reference,
   terminate_all_read,
   terminate_overlapping_read,
   terminate_write,
@@ -72,7 +72,6 @@ enum scan_actions
 
 static const char * const scan_actions_name[] =
 {
-  "note_reference",
   "terminate_all_read",
   "terminate_overlapping_read",
   "terminate_write",
@@ -85,20 +84,117 @@ 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));
+                                 enum scan_actions, enum op_type, int));
 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 *));
+                             enum scan_actions, enum op_type, int));
+static struct du_chain *build_def_use PARAMS ((basic_block));
 static void dump_def_use_chain PARAMS ((struct du_chain *));
+static void note_sets PARAMS ((rtx, rtx, void *));
+static void clear_dead_regs PARAMS ((HARD_REG_SET *, enum machine_mode, rtx));
+static void merge_overlapping_regs PARAMS ((basic_block, HARD_REG_SET *,
+                                           struct du_chain *));
+
+/* Called through note_stores from update_life.  Find sets of registers, and
+   record them in *DATA (which is actually a HARD_REG_SET *).  */
+
+static void
+note_sets (x, set, data)
+     rtx x;
+     rtx set ATTRIBUTE_UNUSED;
+     void *data;
+{
+  HARD_REG_SET *pset = (HARD_REG_SET *) data;
+  unsigned int regno;
+  int nregs;
+  if (GET_CODE (x) != REG)
+    return;
+  regno = REGNO (x);
+  nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+  while (nregs-- > 0)
+    SET_HARD_REG_BIT (*pset, regno + nregs);
+}
+
+/* Clear all registers from *PSET for which a note of kind KIND can be found
+   in the list NOTES.  */
+
+static void
+clear_dead_regs (pset, kind, notes)
+     HARD_REG_SET *pset;
+     enum machine_mode kind;
+     rtx notes;
+{
+  rtx note;
+  for (note = notes; note; note = XEXP (note, 1))
+    if (REG_NOTE_KIND (note) == kind && REG_P (XEXP (note, 0)))
+      {
+       rtx reg = XEXP (note, 0);
+       unsigned int regno = REGNO (reg);
+       int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+       while (nregs-- > 0)
+         CLEAR_HARD_REG_BIT (*pset, regno + nregs);
+      }
+}
+
+/* For a def-use chain CHAIN in basic block B, find which registers overlap
+   its lifetime and set the corresponding bits in *PSET.  */
+
+static void
+merge_overlapping_regs (b, pset, chain)
+     basic_block b;
+     HARD_REG_SET *pset;
+     struct du_chain *chain;
+{
+  struct du_chain *t = chain;
+  rtx insn;
+  HARD_REG_SET live;
+
+  REG_SET_TO_HARD_REG_SET (live, b->global_live_at_start);
+  insn = b->head;
+  while (t)
+    {
+      /* Search forward until the next reference to the register to be
+        renamed.  */
+      while (insn != t->insn)
+       {
+         if (INSN_P (insn))
+           {
+             clear_dead_regs (&live, REG_DEAD, REG_NOTES (insn));
+             note_stores (PATTERN (insn), note_sets, (void *) &live);
+             /* Only record currently live regs if we are inside the
+                reg's live range.  */
+             if (t != chain)
+               IOR_HARD_REG_SET (*pset, live);
+             clear_dead_regs (&live, REG_UNUSED, REG_NOTES (insn));  
+           }
+         insn = NEXT_INSN (insn);
+       }
+
+      IOR_HARD_REG_SET (*pset, live);
+
+      /* For the last reference, also merge in all registers set in the
+        same insn.
+        @@@ We only have take earlyclobbered sets into account.  */
+      if (! t->next_use)
+       note_stores (PATTERN (insn), note_sets, (void *) pset);
+
+      t = t->next_use;
+    }
+}
+
+/* Perform register renaming on the current function.  */
 
 void
 regrename_optimize ()
 {
+  int tick[FIRST_PSEUDO_REGISTER];
+  int this_tick = 0;
   int b;
   char *first_obj;
 
+  memset (tick, 0, sizeof tick);
+
   gcc_obstack_init (&rename_obstack);
   first_obj = (char *) obstack_alloc (&rename_obstack, 0);
 
@@ -106,58 +202,63 @@ regrename_optimize ()
     {
       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;
 
-      CLEAR_HARD_REG_SET (regs_used);
       CLEAR_HARD_REG_SET (unavailable);
 
       if (rtl_dump_file)
        fprintf (rtl_dump_file, "\nBasic block %d:\n", b);
 
-      all_chains = build_def_use (bb, &regs_used);
+      all_chains = build_def_use (bb);
 
       if (rtl_dump_file)
        dump_def_use_chain (all_chains);
 
-      /* 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);
-
+      CLEAR_HARD_REG_SET (unavailable);
       /* Don't clobber traceback for noreturn functions.  */
       if (frame_pointer_needed)
        {
-         SET_HARD_REG_BIT (unavailable, FRAME_POINTER_REGNUM);
+         int i;
+         
+         for (i = HARD_REGNO_NREGS (FRAME_POINTER_REGNUM, Pmode); i--;)
+           SET_HARD_REG_BIT (unavailable, FRAME_POINTER_REGNUM + i);
+         
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-         SET_HARD_REG_BIT (unavailable, HARD_FRAME_POINTER_REGNUM);
+         for (i = HARD_REGNO_NREGS (HARD_FRAME_POINTER_REGNUM, Pmode); i--;)
+           SET_HARD_REG_BIT (unavailable, HARD_FRAME_POINTER_REGNUM + i);
 #endif
        }
 
       CLEAR_HARD_REG_SET (regs_seen);
       while (all_chains)
        {
+         int new_reg, best_new_reg = -1;
          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 reg = REGNO (*this->loc);
          int i;
 
          all_chains = this->next_chain;
-
+         
+#if 0 /* This just disables optimization opportunities.  */
          /* 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;
            }
+#endif
 
-         if (fixed_regs[reg] || global_regs[reg])
+         if (fixed_regs[reg] || global_regs[reg]
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+             || (frame_pointer_needed && reg == HARD_FRAME_POINTER_REGNUM)
+#else
+             || (frame_pointer_needed && reg == FRAME_POINTER_REGNUM)
+#endif
+             )
            continue;
 
          COPY_HARD_REG_SET (this_unavailable, unavailable);
@@ -178,21 +279,32 @@ regrename_optimize ()
          IOR_COMPL_HARD_REG_SET (this_unavailable,
                                  reg_class_contents[last->class]);
 
-         if (last->need_caller_save_reg)
+         if (this->need_caller_save_reg)
            IOR_HARD_REG_SET (this_unavailable, call_used_reg_set);
 
+         merge_overlapping_regs (bb, &this_unavailable, this);
+
          /* 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 (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++)
            {
+             int nregs = HARD_REGNO_NREGS (new_reg, GET_MODE (*this->loc));
+
              for (i = nregs - 1; i >= 0; --i)
-               if (TEST_HARD_REG_BIT (this_unavailable, treg+i)
-                   || fixed_regs[treg+i]
-                   || global_regs[treg+i]
+               if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i)
+                   || fixed_regs[new_reg + i]
+                   || global_regs[new_reg + i]
                    /* Can't use regs which aren't saved by the prologue.  */
-                   || (! regs_ever_live[treg+i] && ! call_used_regs[treg+i])
+                   || (! regs_ever_live[new_reg + i]
+                       && ! call_used_regs[new_reg + i])
+#ifdef LEAF_REGISTERS
+                   /* We can't use a non-leaf register if we're in a 
+                      leaf function.  */
+                   || (current_function_is_leaf 
+                       && !LEAF_REGISTERS[new_reg + i])
+#endif
 #ifdef HARD_REGNO_RENAME_OK
-                   || ! HARD_REGNO_RENAME_OK (reg+i, treg+i)
+                   || ! HARD_REGNO_RENAME_OK (reg + i, new_reg + i)
 #endif
                    )
                  break;
@@ -202,10 +314,14 @@ regrename_optimize ()
              /* 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)))
+               if (! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc)))
                  break;
              if (! tmp)
-               break;
+               {
+                 if (best_new_reg == -1
+                     || tick[best_new_reg] > tick[new_reg])
+                   best_new_reg = new_reg;
+               }
            }
 
          if (rtl_dump_file)
@@ -216,20 +332,18 @@ regrename_optimize ()
                fprintf (rtl_dump_file, " crosses a call");
              }
 
-         if (treg == FIRST_PSEUDO_REGISTER)
+         if (best_new_reg == -1)
            {
              if (rtl_dump_file)
                fprintf (rtl_dump_file, "; no available registers\n");
              continue;
            }
 
-         
-         for (i = nregs - 1; i >= 0; --i)
-           SET_HARD_REG_BIT (unavailable, treg+i);
-         do_replace (this, treg);
+         do_replace (this, best_new_reg);
+         tick[best_new_reg] = this_tick++;
 
          if (rtl_dump_file)
-           fprintf (rtl_dump_file, ", renamed as %s\n", reg_names[treg]);
+           fprintf (rtl_dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
        }
 
       obstack_free (&rename_obstack, first_obj);
@@ -252,23 +366,26 @@ do_replace (chain, reg)
 {
   while (chain)
     {
-      *chain->loc = gen_rtx_REG (GET_MODE (*chain->loc), reg);
+      unsigned int regno = ORIGINAL_REGNO (*chain->loc);
+      *chain->loc = gen_raw_REG (GET_MODE (*chain->loc), reg);
+      if (regno >= FIRST_PSEUDO_REGISTER)
+       ORIGINAL_REGNO (*chain->loc) = regno;
       chain = chain->next_use;
     }
 }
 
 
-static HARD_REG_SET *referenced_regs;
 static struct du_chain *open_chains;
 static struct du_chain *closed_chains;
 
 static void
-scan_rtx_reg (insn, loc, class, action, type)
+scan_rtx_reg (insn, loc, class, action, type, earlyclobber)
      rtx insn;
      rtx *loc;
      enum reg_class class;
      enum scan_actions action;
      enum op_type type;
+     int earlyclobber;
 {
   struct du_chain **p;
   rtx x = *loc;
@@ -276,13 +393,6 @@ scan_rtx_reg (insn, loc, class, action, type)
   int this_regno = REGNO (x);
   int this_nregs = HARD_REGNO_NREGS (this_regno, mode);
 
-  if (action == note_reference)
-    {
-      while (this_nregs-- > 0)
-       SET_HARD_REG_BIT (*referenced_regs, this_regno + this_nregs);
-      return;
-    }
-
   if (action == mark_write)
     {
       if (type == OP_OUT)
@@ -295,6 +405,7 @@ scan_rtx_reg (insn, loc, class, action, type)
          this->insn = insn;
          this->class = class;
          this->need_caller_save_reg = 0;
+         this->earlyclobber = earlyclobber;
          open_chains = this;
        }
       return;
@@ -307,62 +418,87 @@ scan_rtx_reg (insn, loc, class, action, type)
   for (p = &open_chains; *p;)
     {
       struct du_chain *this = *p;
-      int regno = REGNO (*this->loc);
-      int nregs = HARD_REGNO_NREGS (regno, GET_MODE (*this->loc));
-      int exact_match = (regno == this_regno && nregs == this_nregs);
 
-      if (regno + nregs <= this_regno
-         || this_regno + this_nregs <= regno)
-       p = &this->next_chain;
-      else if (action == mark_read)
-       {
-         if (! exact_match)
-           abort ();
-         if (class == NO_REGS)
-           abort ();
+      /* Check if the chain has been terminated if it has then skip to
+        the next chain.
 
-         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;
-       }
-      else if (action != terminate_overlapping_read || ! exact_match)
-       {
-         struct du_chain *next = this->next_chain;
+        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.  */
 
-         /* 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 (*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);
 
-         if ((action == terminate_dead || action == terminate_write)
-             && exact_match)
+         if (regno + nregs <= this_regno
+             || this_regno + this_nregs <= regno)
            {
-             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]);
+             p = &this->next_chain;
+             continue;
            }
-         else
+
+         if (action == mark_read)
            {
-             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]);
+             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 = 0;
+                 this->next_chain = (*p)->next_chain;
+                 this->loc = loc;
+                 this->insn = insn;
+                 this->class = class;
+                 this->need_caller_save_reg = 0;
+                 while (*p)
+                   p = &(*p)->next_use;
+                 *p = this;
+                 return;
+               }
+           }
+
+         if (action != terminate_overlapping_read || ! exact_match)
+           {
+             struct du_chain *next = this->next_chain;
+
+             /* 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 ((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;
            }
-         *p = next;
+         else
+           p = &this->next_chain;
        }
-      else
-       p = &this->next_chain;
     }
 }
 
@@ -487,7 +623,7 @@ scan_rtx_address (insn, loc, class, action, mode)
       return;
 
     case REG:
-      scan_rtx_reg (insn, loc, class, action, OP_IN);
+      scan_rtx_reg (insn, loc, class, action, OP_IN, 0);
       return;
 
     default:
@@ -506,12 +642,13 @@ scan_rtx_address (insn, loc, class, action, mode)
 }
 
 static void
-scan_rtx (insn, loc, class, action, type)
+scan_rtx (insn, loc, class, action, type, earlyclobber)
      rtx insn;
      rtx *loc;
      enum reg_class class;
      enum scan_actions action;
      enum op_type type;
+     int earlyclobber;
 {
   const char *fmt;
   rtx x = *loc;
@@ -531,7 +668,7 @@ scan_rtx (insn, loc, class, action, type)
       return;
 
     case REG:
-      scan_rtx_reg (insn, loc, class, action, type);
+      scan_rtx_reg (insn, loc, class, action, type, earlyclobber);
       return;
 
     case MEM:
@@ -540,20 +677,20 @@ scan_rtx (insn, loc, class, action, type)
       return;
 
     case SET:
-      scan_rtx (insn, &SET_SRC (x), class, action, OP_IN);
-      scan_rtx (insn, &SET_DEST (x), class, action, OP_OUT);
+      scan_rtx (insn, &SET_SRC (x), class, action, OP_IN, 0);
+      scan_rtx (insn, &SET_DEST (x), class, action, OP_OUT, 0);
       return;
 
     case STRICT_LOW_PART:
-      scan_rtx (insn, &XEXP (x, 0), class, action, OP_INOUT);
+      scan_rtx (insn, &XEXP (x, 0), class, action, OP_INOUT, earlyclobber);
       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);
+               type == OP_IN ? OP_IN : OP_INOUT, earlyclobber);
+      scan_rtx (insn, &XEXP (x, 1), class, action, OP_IN, 0);
+      scan_rtx (insn, &XEXP (x, 2), class, action, OP_IN, 0);
       return;
 
     case POST_INC:
@@ -566,13 +703,13 @@ scan_rtx (insn, loc, class, action, type)
       abort ();
 
     case CLOBBER:
-      scan_rtx (insn, &SET_DEST (x), class, action, OP_OUT);
+      scan_rtx (insn, &SET_DEST (x), class, action, OP_OUT, 1);
       return;
 
     case EXPR_LIST:
-      scan_rtx (insn, &XEXP (x, 0), class, action, type);
+      scan_rtx (insn, &XEXP (x, 0), class, action, type, 0);
       if (XEXP (x, 1))
-       scan_rtx (insn, &XEXP (x, 1), class, action, type);
+       scan_rtx (insn, &XEXP (x, 1), class, action, type, 0);
       return;
 
     default:
@@ -583,24 +720,22 @@ scan_rtx (insn, loc, class, action, type)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       scan_rtx (insn, &XEXP (x, i), class, action, type);
+       scan_rtx (insn, &XEXP (x, i), class, action, type, 0);
       else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         scan_rtx (insn, &XVECEXP (x, i, j), class, action, type);
+         scan_rtx (insn, &XVECEXP (x, i, j), class, action, type, 0);
     }
 }
 
 /* Build def/use chain */
 
 static struct du_chain *
-build_def_use (bb, regs_used)
+build_def_use (bb)
      basic_block bb;
-     HARD_REG_SET *regs_used;
 {
   rtx insn;
 
   open_chains = closed_chains = NULL;
-  referenced_regs = regs_used;
 
   for (insn = bb->head; ; insn = NEXT_INSN (insn))
     {
@@ -614,9 +749,6 @@ build_def_use (bb, regs_used)
          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:
@@ -658,7 +790,7 @@ build_def_use (bb, regs_used)
          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]);
+                     recog_data.operand_type[i], 0);
 
          /* Step 2: Close chains for which we have reads outside operands.
             We do this by munging all operands into CC0, and closing 
@@ -680,7 +812,8 @@ build_def_use (bb, regs_used)
              *recog_data.dup_loc[i] = cc0_rtx;
            }
 
-         scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_all_read, OP_IN);
+         scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_all_read,
+                   OP_IN, 0);
 
          for (i = 0; i < recog_data.n_dups; i++)
            *recog_data.dup_loc[i] = old_dups[i];
@@ -690,7 +823,7 @@ build_def_use (bb, regs_used)
          /* 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);
+                     NO_REGS, terminate_all_read, OP_IN, 0);
 
          /* Step 3: Append to chains for reads inside operands.  */
          for (i = 0; i < n_ops + recog_data.n_dups; i++)
@@ -711,13 +844,20 @@ build_def_use (bb, regs_used)
              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);
+               scan_rtx (insn, loc, class, mark_read, type, 0);
            }
 
-         /* Step 4: Close chains for registers that die here.  */
+         /* 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))
-           if (REG_NOTE_KIND (note) == REG_DEAD)
-             scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead, OP_IN);
+           {
+             if (REG_NOTE_KIND (note) == REG_DEAD)
+               scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
+                         OP_IN, 0);
+             else if (REG_NOTE_KIND (note) == REG_INC)
+               scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_read,
+                         OP_INOUT, 0);
+           }
 
          /* Step 4B: If this is a call, any chain live at this point
             requires a caller-saved reg.  */
@@ -725,12 +865,7 @@ build_def_use (bb, regs_used)
            {
              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;
-               }
+               p->need_caller_save_reg = 1;
            }
 
          /* Step 5: Close open chains that overlap writes.  Similar to
@@ -751,7 +886,7 @@ build_def_use (bb, regs_used)
                *recog_data.dup_loc[i] = cc0_rtx;
            }
 
-         scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN);
+         scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN, 0);
 
          for (i = 0; i < recog_data.n_dups; i++)
            *recog_data.dup_loc[i] = old_dups[i];
@@ -772,14 +907,16 @@ build_def_use (bb, regs_used)
                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);
+                 scan_rtx (insn, loc, class, mark_write, OP_OUT,
+                           recog_op_alt[opn][alt].earlyclobber);
              }
 
          /* 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);
+             scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
+                       OP_IN, 0);
        }
       if (insn == bb->end)
        break;