OSDN Git Service

add sparc64-*-solaris2 support just like sparcv9-*-solaris2
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index 4e0bed3..8cc8729 100644 (file)
@@ -1,22 +1,23 @@
 /* Allocate registers for pseudo-registers that span basic blocks.
-   Copyright (C) 1987, 88, 91, 94, 96-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1991, 1994, 1996, 1997, 1998,
+   1999, 2000 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
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+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.  */
 
 
 #include "config.h"
@@ -74,7 +75,7 @@ Boston, MA 02111-1307, USA.  */
    5. Allocate the variables in that order; each if possible into
    a preferred register, else into another register.  */
 \f
-/* Number of pseudo-registers which are candidates for allocation. */
+/* Number of pseudo-registers which are candidates for allocation.  */
 
 static int max_allocno;
 
@@ -93,9 +94,12 @@ struct allocno
   /* Number of calls crossed by each allocno.  */
   int calls_crossed;
 
-  /* Number of refs (weighted) to each allocno.  */
+  /* Number of refs to each allocno.  */
   int n_refs;
 
+  /* Frequency of uses of each allocno.  */
+  int freq;
+
   /* Guess at live length of each allocno.
      This is actually the max of the live lengths of the regs.  */
   int live_length;
@@ -214,11 +218,14 @@ static HARD_REG_SET no_global_alloc_regs;
 
 static HARD_REG_SET regs_used_so_far;
 
-/* Number of refs (weighted) to each hard reg, as used by local alloc.
+/* Number of refs to each hard reg, as used by local alloc.
    It is zero for a reg that contains global pseudos or is explicitly used.  */
 
 static int local_reg_n_refs[FIRST_PSEUDO_REGISTER];
 
+/* Frequency of uses of given hard reg.  */
+static int local_reg_freq[FIRST_PSEUDO_REGISTER];
+
 /* Guess at live length of each hard reg, as used by local alloc.
    This is actually the sum of the live lengths of the specific regs.  */
 
@@ -305,7 +312,6 @@ static void dump_conflicts  PARAMS ((FILE *));
 static void reg_becomes_live   PARAMS ((rtx, rtx, void *));
 static void reg_dies           PARAMS ((int, enum machine_mode,
                                       struct insn_chain *));
-static void build_insn_chain   PARAMS ((rtx));
 \f
 /* Perform allocation of pseudo-registers not allocated by local_alloc.
    FILE is a file to output debugging information on,
@@ -342,7 +348,7 @@ global_alloc (file)
   /* Build the regset of all eliminable registers and show we can't use those
      that we already know won't be eliminated.  */
 #ifdef ELIMINABLE_REGS
-  for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
+  for (i = 0; i < ARRAY_SIZE (eliminables); i++)
     {
       SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
 
@@ -374,7 +380,7 @@ global_alloc (file)
      a leaf function.  */
   {
     char *cheap_regs;
-    static char leaf_regs[] = LEAF_REGISTERS;
+    char *leaf_regs = LEAF_REGISTERS;
 
     if (only_leaf_regs_used () && leaf_function_p ())
       cheap_regs = leaf_regs;
@@ -447,6 +453,7 @@ global_alloc (file)
        allocno[num].size = PSEUDO_REGNO_SIZE (i);
        allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
        allocno[num].n_refs += REG_N_REFS (i);
+       allocno[num].freq += REG_FREQ (i);
        if (allocno[num].live_length < REG_LIVE_LENGTH (i))
          allocno[num].live_length = REG_LIVE_LENGTH (i);
       }
@@ -454,8 +461,9 @@ 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 ((char *) local_reg_live_length, sizeof local_reg_live_length);
-  bzero ((char *) local_reg_n_refs, sizeof local_reg_n_refs);
+  memset ((char *) local_reg_live_length, 0, sizeof local_reg_live_length);
+  memset ((char *) local_reg_n_refs, 0, sizeof local_reg_n_refs);
+  memset ((char *) local_reg_freq, 0, sizeof local_reg_freq);
   for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
     if (reg_renumber[i] >= 0)
       {
@@ -466,6 +474,7 @@ global_alloc (file)
        for (j = regno; j < endregno; j++)
          {
            local_reg_n_refs[j] += REG_N_REFS (i);
+           local_reg_freq[j] += REG_FREQ (i);
            local_reg_live_length[j] += REG_LIVE_LENGTH (i);
          }
       }
@@ -473,7 +482,7 @@ global_alloc (file)
   /* We can't override local-alloc for a reg used not just by local-alloc.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (regs_ever_live[i])
-      local_reg_n_refs[i] = 0;
+      local_reg_n_refs[i] = 0, local_reg_freq[i] = 0;
        
   allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
 
@@ -578,7 +587,7 @@ global_alloc (file)
 #endif
     {
       build_insn_chain (get_insns ());
-      retval = reload (get_insns (), 1, file);
+      retval = reload (get_insns (), 1);
     }
 
   /* Clean up.  */
@@ -602,16 +611,17 @@ allocno_compare (v1p, v2p)
   int v1 = *(const int *)v1p, v2 = *(const 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.  */
+     times a register can occur in one insn (surely less than 100)
+     weighted by the frequency (maximally REG_FREQ_MAX).
+     Multiplying this by 10000/REG_FREQ_MAX can't overflow.  */
   register int pri1
-    = (((double) (floor_log2 (allocno[v1].n_refs) * allocno[v1].n_refs)
+    = (((double) (floor_log2 (allocno[v1].n_refs) * allocno[v1].freq)
        / allocno[v1].live_length)
-       * 10000 * allocno[v1].size);
+       * (10000 / REG_FREQ_MAX) * allocno[v1].size);
   register int pri2
-    = (((double) (floor_log2 (allocno[v2].n_refs) * allocno[v2].n_refs)
+    = (((double) (floor_log2 (allocno[v2].n_refs) * allocno[v2].freq)
        / allocno[v2].live_length)
-       * 10000 * allocno[v2].size);
+       * (10000 / REG_FREQ_MAX) * allocno[v2].size);
   if (pri2 - pri1)
     return pri2 - pri1;
 
@@ -637,7 +647,7 @@ global_conflicts ()
 
   for (b = 0; b < n_basic_blocks; b++)
     {
-      bzero ((char *) allocnos_live, allocno_row_words * sizeof (INT_TYPE));
+      memset ((char *) allocnos_live, 0, allocno_row_words * sizeof (INT_TYPE));
 
       /* Initialize table of registers currently live
         to the state at the beginning of this basic block.
@@ -804,10 +814,13 @@ global_conflicts ()
 
              /* Mark any registers set in INSN and then never used.  */
 
-             while (n_regs_set > 0)
-               if (find_regno_note (insn, REG_UNUSED,
-                                    REGNO (regs_set[--n_regs_set])))
-                 mark_reg_death (regs_set[n_regs_set]);
+             while (n_regs_set-- > 0)
+               {
+                 rtx note = find_regno_note (insn, REG_UNUSED,
+                                             REGNO (regs_set[n_regs_set]));
+                 if (note)
+                   mark_reg_death (XEXP (note, 0));
+               }
            }
 
          if (insn == BLOCK_END (b))
@@ -835,7 +848,7 @@ expand_preferences ()
      where this wins are reg-reg copies.  */
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+    if (INSN_P (insn)
        && (set = single_set (insn)) != 0
        && GET_CODE (SET_DEST (set)) == REG
        && reg_allocno[REGNO (SET_DEST (set))] >= 0)
@@ -999,10 +1012,10 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
 
   IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
 
-#ifdef CLASS_CANNOT_CHANGE_SIZE
-  if (REG_CHANGES_SIZE (allocno[num].reg))
+#ifdef CLASS_CANNOT_CHANGE_MODE
+  if (REG_CHANGES_MODE (allocno[num].reg))
     IOR_HARD_REG_SET (used1,
-                     reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
+                     reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
 #endif
 
   /* Try each hard reg to see if it fits.  Do this in two passes.
@@ -1189,10 +1202,10 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
              /* 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[num].reg)
+#ifdef CLASS_CANNOT_CHANGE_MODE
+             && ! (REG_CHANGES_MODE (allocno[num].reg)
                    && (TEST_HARD_REG_BIT
-                       (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                       (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
                         regno)))
 #endif
              )
@@ -1201,9 +1214,9 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
                 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]
+             double tmp1 = ((double) local_reg_freq[regno]
                            / local_reg_live_length[regno]);
-             double tmp2 = ((double) allocno[num].n_refs
+             double tmp2 = ((double) allocno[num].freq
                             / allocno[num].live_length);
 
              if (tmp1 < tmp2)
@@ -1253,6 +1266,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
          SET_HARD_REG_BIT (regs_used_so_far, j);
          /* This is no longer a reg used just by local regs.  */
          local_reg_n_refs[j] = 0;
+         local_reg_freq[j] = 0;
        }
       /* For each other pseudo-reg conflicting with this one,
         mark it as conflicting with the hard regs this one occupies.  */
@@ -1276,17 +1290,17 @@ retry_global_alloc (regno, forbidden_regs)
      int regno;
      HARD_REG_SET forbidden_regs;
 {
-  int allocno = reg_allocno[regno];
-  if (allocno >= 0)
+  int alloc_no = reg_allocno[regno];
+  if (alloc_no >= 0)
     {
       /* If we have more than one register class,
         first try allocating in the class that is cheapest
         for this pseudo-reg.  If that fails, try any reg.  */
       if (N_REG_CLASSES > 1)
-       find_reg (allocno, forbidden_regs, 0, 0, 1);
+       find_reg (alloc_no, forbidden_regs, 0, 0, 1);
       if (reg_renumber[regno] < 0
          && reg_alternate_class (regno) != NO_REGS)
-       find_reg (allocno, forbidden_regs, 1, 0, 1);
+       find_reg (alloc_no, forbidden_regs, 1, 0, 1);
 
       /* If we found a register, modify the RTL for the register to
         show the hard register, and mark that register live.  */
@@ -1419,17 +1433,8 @@ mark_reg_store (reg, setter, data)
 {
   register int regno;
 
-  /* WORD is which word of a multi-register group is being stored.
-     For the case where the store is actually into a SUBREG of REG.
-     Except we don't use it; I believe the entire REG needs to be
-     made live.  */
-  int word = 0;
-
   if (GET_CODE (reg) == SUBREG)
-    {
-      word = SUBREG_WORD (reg);
-      reg = SUBREG_REG (reg);
-    }
+    reg = SUBREG_REG (reg);
 
   if (GET_CODE (reg) != REG)
     return;
@@ -1453,7 +1458,7 @@ mark_reg_store (reg, setter, data)
     }
 
   if (reg_renumber[regno] >= 0)
-    regno = reg_renumber[regno] /* + word */;
+    regno = reg_renumber[regno];
 
   /* Handle hardware regs (and pseudos allocated to hard regs).  */
   if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno])
@@ -1585,11 +1590,11 @@ static void
 set_preference (dest, src)
      rtx dest, src;
 {
-  int src_regno, dest_regno;
+  unsigned int src_regno, dest_regno;
   /* Amount to add to the hard regno for SRC, or subtract from that for DEST,
      to compensate for subregs in SRC or DEST.  */
   int offset = 0;
-  int i;
+  unsigned int i;
   int copy = 1;
 
   if (GET_RTX_FORMAT (GET_CODE (src))[0] == 'e')
@@ -1603,7 +1608,15 @@ set_preference (dest, src)
   else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG)
     {
       src_regno = REGNO (SUBREG_REG (src));
-      offset += SUBREG_WORD (src);
+
+      if (REGNO (SUBREG_REG (src)) < FIRST_PSEUDO_REGISTER)
+       offset += subreg_regno_offset (REGNO (SUBREG_REG (src)),
+                                      GET_MODE (SUBREG_REG (src)),
+                                      SUBREG_BYTE (src),
+                                      GET_MODE (src));
+      else
+       offset += (SUBREG_BYTE (src)
+                  / REGMODE_NATURAL_SIZE (GET_MODE (src)));
     }
   else
     return;
@@ -1613,7 +1626,15 @@ set_preference (dest, src)
   else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
     {
       dest_regno = REGNO (SUBREG_REG (dest));
-      offset -= SUBREG_WORD (dest);
+
+      if (REGNO (SUBREG_REG (dest)) < FIRST_PSEUDO_REGISTER)
+       offset -= subreg_regno_offset (REGNO (SUBREG_REG (dest)),
+                                      GET_MODE (SUBREG_REG (dest)),
+                                      SUBREG_BYTE (dest),
+                                      GET_MODE (dest));
+      else
+       offset -= (SUBREG_BYTE (dest)
+                  / REGMODE_NATURAL_SIZE (GET_MODE (dest)));
     }
   else
     return;
@@ -1633,7 +1654,7 @@ set_preference (dest, src)
       && reg_allocno[src_regno] >= 0)
     {
       dest_regno -= offset;
-      if (dest_regno >= 0 && dest_regno < FIRST_PSEUDO_REGISTER)
+      if (dest_regno < FIRST_PSEUDO_REGISTER)
        {
          if (copy)
            SET_REGBIT (hard_reg_copy_preferences,
@@ -1652,7 +1673,7 @@ set_preference (dest, src)
       && reg_allocno[dest_regno] >= 0)
     {
       src_regno += offset;
-      if (src_regno >= 0 && src_regno < FIRST_PSEUDO_REGISTER)
+      if (src_regno < FIRST_PSEUDO_REGISTER)
        {
          if (copy)
            SET_REGBIT (hard_reg_copy_preferences,
@@ -1757,15 +1778,16 @@ reg_dies (regno, mode, chain)
 
 /* Walk the insns of the current function and build reload_insn_chain,
    and record register life information.  */
-static void
+void
 build_insn_chain (first)
      rtx first;
 {
   struct insn_chain **p = &reload_insn_chain;
   struct insn_chain *prev = 0;
   int b = 0;
+  regset_head live_relevant_regs_head;
 
-  live_relevant_regs = ALLOCA_REG_SET ();
+  live_relevant_regs = INITIALIZE_REG_SET (live_relevant_regs_head);
 
   for (; first; first = NEXT_INSN (first))
     {
@@ -1797,7 +1819,7 @@ build_insn_chain (first)
          c->insn = first;
          c->block = b;
 
-         if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
+         if (INSN_P (first))
            {
              rtx link;
 
@@ -1819,7 +1841,7 @@ build_insn_chain (first)
          else
            COPY_REG_SET (&c->live_throughout, live_relevant_regs);
 
-         if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
+         if (INSN_P (first))
            {
              rtx link;
 
@@ -1840,12 +1862,17 @@ build_insn_chain (first)
         no real insns are after the end of the last basic block.
 
         We may want to reorganize the loop somewhat since this test should
-        always be the right exit test.  */
+        always be the right exit test.  Allow an ADDR_VEC or ADDR_DIF_VEC if
+        the previous real insn is a JUMP_INSN.  */
       if (b == n_basic_blocks)
        {
          for (first = NEXT_INSN (first) ; first; first = NEXT_INSN (first))
-           if (GET_RTX_CLASS (GET_CODE (first)) == 'i'
-               && GET_CODE (PATTERN (first)) != USE)
+           if (INSN_P (first)
+               && GET_CODE (PATTERN (first)) != USE
+               && ! ((GET_CODE (PATTERN (first)) == ADDR_VEC
+                      || GET_CODE (PATTERN (first)) == ADDR_DIFF_VEC)
+                     && prev_real_insn (first) != 0
+                     && GET_CODE (prev_real_insn (first)) == JUMP_INSN))
              abort ();
          break;
        }