OSDN Git Service

x
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index a96d3ef..a4f5ab1 100644 (file)
@@ -1,5 +1,5 @@
 /* Allocate registers for pseudo-registers that span basic blocks.
-   Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1991, 1994, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <stdio.h>
@@ -74,7 +75,7 @@ static int max_allocno;
 /* Indexed by (pseudo) reg number, gives the allocno, or -1
    for pseudo registers already allocated by local_allocate.  */
 
-static int *reg_allocno;
+int *reg_allocno;
 
 /* Indexed by allocno, gives the reg number.  */
 
@@ -246,24 +247,24 @@ static struct { int allocno1, allocno2;}
 static rtx *regs_set;
 static int n_regs_set;
 
-/* All register that can be eliminated.  */
+/* All registers that can be eliminated.  */
 
 static HARD_REG_SET eliminable_regset;
 
-static int allocno_compare ();
-static void mark_reg_store ();
-static void mark_reg_clobber ();
-static void mark_reg_conflicts ();
-static void mark_reg_live_nc ();
-static void mark_reg_death ();
-static void dump_conflicts ();
-void dump_global_regs ();
-static void find_reg ();
-static void global_conflicts ();
-static void expand_preferences ();
-static void prune_preferences ();
-static void record_conflicts ();
-static void set_preference ();
+static int allocno_compare     PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void global_conflicts   PROTO((void));
+static void expand_preferences PROTO((void));
+static void prune_preferences  PROTO((void));
+static void find_reg           PROTO((int, HARD_REG_SET, int, int, int));
+static void record_one_conflict PROTO((int));
+static void record_conflicts   PROTO((short *, int));
+static void mark_reg_store     PROTO((rtx, rtx));
+static void mark_reg_clobber   PROTO((rtx, rtx));
+static void mark_reg_conflicts PROTO((rtx));
+static void mark_reg_death     PROTO((rtx));
+static void mark_reg_live_nc   PROTO((int, enum machine_mode));
+static void set_preference     PROTO((rtx, rtx));
+static void dump_conflicts     PROTO((FILE *));
 \f
 /* Perform allocation of pseudo-registers not allocated by local_alloc.
    FILE is a file to output debugging information on,
@@ -279,6 +280,13 @@ global_alloc (file)
 #ifdef ELIMINABLE_REGS
   static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
 #endif
+  int need_fp
+    = (! flag_omit_frame_pointer
+#ifdef EXIT_IGNORE_STACK
+       || (current_function_calls_alloca && EXIT_IGNORE_STACK)
+#endif
+       || FRAME_POINTER_REQUIRED);
+
   register int i;
   rtx x;
 
@@ -302,16 +310,18 @@ global_alloc (file)
       SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
 
       if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
-         || (eliminables[i].from == FRAME_POINTER_REGNUM
-             && (! flag_omit_frame_pointer || FRAME_POINTER_REQUIRED)))
+         || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
        SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
     }
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+  SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
+  if (need_fp)
+    SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+#endif
+
 #else
   SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
-
-  /* If we know we will definitely not be eliminating the frame pointer,
-     don't allocate it.  */
-  if (! flag_omit_frame_pointer || FRAME_POINTER_REQUIRED)
+  if (need_fp)
     SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
 #endif
 
@@ -360,7 +370,7 @@ global_alloc (file)
   /* Initialize the shared-hard-reg mapping
      from the list of pairs that may share.  */
   reg_may_share = (int *) alloca (max_regno * sizeof (int));
-  bzero (reg_may_share, max_regno * sizeof (int));
+  bzero ((char *) reg_may_share, max_regno * sizeof (int));
   for (x = regs_may_share; x; x = XEXP (XEXP (x, 1), 1))
     {
       int r1 = REGNO (XEXP (x, 0));
@@ -396,10 +406,10 @@ global_alloc (file)
   allocno_calls_crossed = (int *) alloca (max_allocno * sizeof (int));
   allocno_n_refs = (int *) alloca (max_allocno * sizeof (int));
   allocno_live_length = (int *) alloca (max_allocno * sizeof (int));
-  bzero (allocno_size, max_allocno * sizeof (int));
-  bzero (allocno_calls_crossed, max_allocno * sizeof (int));
-  bzero (allocno_n_refs, max_allocno * sizeof (int));
-  bzero (allocno_live_length, max_allocno * sizeof (int));
+  bzero ((char *) allocno_size, max_allocno * sizeof (int));
+  bzero ((char *) allocno_calls_crossed, max_allocno * sizeof (int));
+  bzero ((char *) allocno_n_refs, max_allocno * sizeof (int));
+  bzero ((char *) allocno_live_length, max_allocno * sizeof (int));
 
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (reg_allocno[i] >= 0)
@@ -416,8 +426,8 @@ global_alloc (file)
   /* Calculate amount of usage of each hard reg by pseudos
      allocated by local-alloc.  This is to see if we want to
      override it.  */
-  bzero (local_reg_live_length, sizeof local_reg_live_length);
-  bzero (local_reg_n_refs, sizeof local_reg_n_refs);
+  bzero ((char *) local_reg_live_length, sizeof local_reg_live_length);
+  bzero ((char *) local_reg_n_refs, sizeof local_reg_n_refs);
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (reg_allocno[i] < 0 && reg_renumber[i] >= 0)
       {
@@ -437,35 +447,49 @@ global_alloc (file)
     if (regs_ever_live[i])
       local_reg_n_refs[i] = 0;
 
+  /* Likewise for regs used in a SCRATCH.  */
+  for (i = 0; i < scratch_list_length; i++)
+    if (scratch_list[i])
+      {
+       int regno = REGNO (scratch_list[i]);
+       int lim = regno + HARD_REGNO_NREGS (regno, GET_MODE (scratch_list[i]));
+       int j;
+
+       for (j = regno; j < lim; j++)
+         local_reg_n_refs[j] = 0;
+      }
+       
   /* Allocate the space for the conflict and preference tables and
      initialize them.  */
 
   hard_reg_conflicts
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_conflicts, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_conflicts, max_allocno * sizeof (HARD_REG_SET));
 
   hard_reg_preferences
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_preferences, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_preferences, max_allocno * sizeof (HARD_REG_SET));
   
   hard_reg_copy_preferences
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_copy_preferences, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_copy_preferences,
+        max_allocno * sizeof (HARD_REG_SET));
   
   hard_reg_full_preferences
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_full_preferences, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_full_preferences,
+        max_allocno * sizeof (HARD_REG_SET));
   
   regs_someone_prefers
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (regs_someone_prefers, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) regs_someone_prefers, max_allocno * sizeof (HARD_REG_SET));
 
   allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
 
   conflicts = (INT_TYPE *) alloca (max_allocno * allocno_row_words
                                   * sizeof (INT_TYPE));
-  bzero (conflicts, max_allocno * allocno_row_words
-        * sizeof (INT_TYPE));
+  bzero ((char *) conflicts,
+        max_allocno * allocno_row_words * sizeof (INT_TYPE));
 
   allocnos_live = (INT_TYPE *) alloca (allocno_row_words * sizeof (INT_TYPE));
 
@@ -560,27 +584,29 @@ global_alloc (file)
    Returns -1 (1) if *v1 should be allocated before (after) *v2.  */
 
 static int
-allocno_compare (v1, v2)
-     int *v1, *v2;
+allocno_compare (v1p, v2p)
+     const GENERIC_PTR v1p;
+     const GENERIC_PTR v2p;
 {
+  int v1 = *(int *)v1p, v2 = *(int *)v2p;
   /* Note that the quotient will never be bigger than
      the value of floor_log2 times the maximum number of
      times a register can occur in one insn (surely less than 100).
      Multiplying this by 10000 can't overflow.  */
   register int pri1
-    = (((double) (floor_log2 (allocno_n_refs[*v1]) * allocno_n_refs[*v1])
-       / (allocno_live_length[*v1] * allocno_size[*v1]))
-       * 10000);
+    = (((double) (floor_log2 (allocno_n_refs[v1]) * allocno_n_refs[v1])
+       / allocno_live_length[v1])
+       * 10000 * allocno_size[v1]);
   register int pri2
-    = (((double) (floor_log2 (allocno_n_refs[*v2]) * allocno_n_refs[*v2])
-       / (allocno_live_length[*v2] * allocno_size[*v2]))
-       * 10000);
+    = (((double) (floor_log2 (allocno_n_refs[v2]) * allocno_n_refs[v2])
+       / allocno_live_length[v2])
+       * 10000 * allocno_size[v2]);
   if (pri2 - pri1)
     return pri2 - pri1;
 
   /* If regs are equally good, sort by allocno,
      so that the results of qsort leave nothing to chance.  */
-  return *v1 - *v2;
+  return v1 - v2;
 }
 \f
 /* Scan the rtl code and record all conflicts and register preferences in the
@@ -600,7 +626,7 @@ global_conflicts ()
 
   for (b = 0; b < n_basic_blocks; b++)
     {
-      bzero (allocnos_live, allocno_row_words * sizeof (INT_TYPE));
+      bzero ((char *) allocnos_live, allocno_row_words * sizeof (INT_TYPE));
 
       /* Initialize table of registers currently live
         to the state at the beginning of this basic block.
@@ -670,9 +696,9 @@ global_conflicts ()
 
          if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
            {
-             int i = 0;
 
 #if 0
+             int i = 0;
              for (link = REG_NOTES (insn);
                   link && i < NUM_NO_CONFLICT_PAIRS;
                   link = XEXP (link, 1))
@@ -845,7 +871,8 @@ prune_preferences ()
         we want to give the lower-priority allocno the first chance for
         these registers).  */
       for (j = i + 1; j < max_allocno; j++)
-       if (CONFLICTP (allocno, allocno_order[j]))
+       if (CONFLICTP (allocno, allocno_order[j])
+           || CONFLICTP (allocno_order[j], allocno))
          {
            COPY_HARD_REG_SET (temp,
                               hard_reg_full_preferences[allocno_order[j]]);
@@ -912,6 +939,12 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
 
   IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);
 
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+  if (reg_changes_size[allocno_reg[allocno]])
+    IOR_HARD_REG_SET (used1,
+                     reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
+#endif
+
   /* Try each hard reg to see if it fits.  Do this in two passes.
      In the first pass, skip registers that are preferred by some other pseudo
      to give it a better chance of getting one of those registers.  Only if
@@ -1040,7 +1073,11 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
     }
  no_prefs:
 
-  /* If we haven't succeeded yet, try with caller-saves.  */
+  /* If we haven't succeeded yet, try with caller-saves. 
+     We need not check to see if the current function has nonlocal
+     labels because we don't put any pseudos that are live over calls in
+     registers in that case.  */
+
   if (flag_caller_saves && best_reg < 0)
     {
       /* Did not find a register.  If it would be profitable to
@@ -1051,7 +1088,14 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
          && CALLER_SAVE_PROFITABLE (allocno_n_refs[allocno],
                                     allocno_calls_crossed[allocno]))
        {
-         find_reg (allocno, losers, alt_regs_p, 1, retrying);
+         HARD_REG_SET new_losers;
+         if (! losers)
+           CLEAR_HARD_REG_SET (new_losers);
+         else
+           COPY_HARD_REG_SET (new_losers, losers);
+           
+         IOR_HARD_REG_SET(new_losers, losing_caller_save_reg_set);
+         find_reg (allocno, new_losers, alt_regs_p, 1, retrying);
          if (reg_renumber[allocno_reg[allocno]] >= 0)
            {
              caller_save_needed = 1;
@@ -1071,31 +1115,55 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
     {
       /* Count from the end, to find the least-used ones first.  */
       for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
-       if (local_reg_n_refs[i] != 0
-           /* Don't use a reg no good for this pseudo.  */
-           && ! TEST_HARD_REG_BIT (used2, i)
-           && HARD_REGNO_MODE_OK (i, mode)
-           && ((double) local_reg_n_refs[i] / local_reg_live_length[i]
-               < ((double) allocno_n_refs[allocno]
-                  / allocno_live_length[allocno])))
-         {
-           /* Hard reg I was used less in total by local regs
-              than it would be used by this one allocno!  */
-           int k;
-           for (k = 0; k < max_regno; k++)
-             if (reg_renumber[k] >= 0)
+       {
+#ifdef REG_ALLOC_ORDER
+         int regno = reg_alloc_order[i];
+#else
+         int regno = i;
+#endif
+
+         if (local_reg_n_refs[regno] != 0
+             /* Don't use a reg no good for this pseudo.  */
+             && ! TEST_HARD_REG_BIT (used2, regno)
+             && HARD_REGNO_MODE_OK (regno, mode)
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+             && ! (reg_changes_size[allocno_reg[allocno]]
+                   && (TEST_HARD_REG_BIT
+                       (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                        regno)))
+#endif
+             )
+           {
+             /* We explicitly evaluate the divide results into temporary
+                variables so as to avoid excess precision problems that occur
+                on a i386-unknown-sysv4.2 (unixware) host.  */
+                
+             double tmp1 = ((double) local_reg_n_refs[regno]
+                           / local_reg_live_length[regno]);
+             double tmp2 = ((double) allocno_n_refs[allocno]
+                            / allocno_live_length[allocno]);
+
+             if (tmp1 < tmp2)
                {
-                 int regno = reg_renumber[k];
-                 int endregno
-                   = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (k));
+                 /* Hard reg REGNO was used less in total by local regs
+                    than it would be used by this one allocno!  */
+                 int k;
+                 for (k = 0; k < max_regno; k++)
+                   if (reg_renumber[k] >= 0)
+                     {
+                       int r = reg_renumber[k];
+                       int endregno
+                         = r + HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (k));
 
-                 if (i >= regno && i < endregno)
-                   reg_renumber[k] = -1;
-               }
+                       if (regno >= r && regno < endregno)
+                         reg_renumber[k] = -1;
+                     }
 
-           best_reg = i;
-           break;
-         }
+                 best_reg = regno;
+                 break;
+               }
+           }
+       }
     }
 
   /* Did we find a register?  */