]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Renamer improvements.
authorBernd Schmidt <bernds@redhat.com>
Fri, 22 Dec 2000 15:44:42 +0000 (15:44 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Fri, 22 Dec 2000 15:44:42 +0000 (15:44 +0000)
From-SVN: r38463

gcc/ChangeLog
gcc/regrename.c

index d8828ccaed72a2c00c20fa9b97990ee74d2ce37f..d1568bb84109c2f7b665bbc6808699df4f381a80 100644 (file)
@@ -1,3 +1,23 @@
+2000-12-22  Bernd Schmidt  <bernds@redhat.com>
+
+       * regrename.c (struct du_chain): New field "earlyclobber".
+       (enum scan_actions): Remove unused entry "note_reference".
+       (enum scan_actions_name): Likewise.
+       (note_sets, clear_dead_regs, merge_overlapping_regs): New static
+       functions.
+       (regrename_optimize): Use them to compute unavailable regs; get
+       rid of the more simpleminded code we used to have here.
+       Use a tick array to ensure registers are allocated in a more
+       round-robin way.  Disable code that only optimizes registers
+       that were seen more than once.
+       (referenced_regs): Remove variable.
+       (scan_rtx_reg): New arg "earlyclobber".  All callers changed.
+       Store its value in newly generated du_chain structures.
+       Add new du_chains at the end, not the start, of the list.
+       Don't handle the "note_reference" action.
+       (scan_rtx): New arg "earlyclobber".  All callers changed.
+       (build_def_use): Lose code to keep track of referenced regs.
+
 2000-12-22  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * Makefile.in (sched-deps.o, sched-rgn.o): Fix dependency typo.
index 19cc9e865cca036ee118c0f708a43d3f3a7727b2..bca986d24a40fafeada6136c2a702017397357f6 100644 (file)
@@ -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,28 +202,20 @@ 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)
        {
@@ -140,6 +228,7 @@ regrename_optimize ()
       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;
@@ -149,13 +238,15 @@ regrename_optimize ()
          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])
            continue;
@@ -178,21 +269,25 @@ 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++)
            {
+             new_reg = 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]
+               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 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 +297,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 +315,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);
@@ -258,17 +355,17 @@ do_replace (chain, reg)
 }
 
 
-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 +373,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 +385,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;
@@ -343,12 +434,14 @@ scan_rtx_reg (insn, loc, class, action, type)
                {
                  this = (struct du_chain *)
                    obstack_alloc (&rename_obstack, sizeof (struct du_chain));
-                 this->next_use = *p;
+                 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;
                }
@@ -510,7 +603,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:
@@ -529,12 +622,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;
@@ -554,7 +648,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:
@@ -563,20 +657,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:
@@ -589,13 +683,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:
@@ -606,24 +700,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))
     {
@@ -637,9 +729,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:
@@ -681,7 +770,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 
@@ -703,7 +792,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];
@@ -713,7 +803,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++)
@@ -734,7 +824,7 @@ 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.
@@ -742,9 +832,11 @@ build_def_use (bb, regs_used)
          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);
+               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);
+               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
@@ -753,12 +845,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
@@ -779,7 +866,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];
@@ -800,14 +887,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;