OSDN Git Service

* except.c (expand_start_all_catch): If the machine needs to
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index 3beac27..f562472 100644 (file)
@@ -1,5 +1,5 @@
 /* Compute register class preferences for pseudo-registers.
-   Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91, 92, 93, 94, 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.  */
 
 
 /* This file contains two passes of the compiler: reg_scan and reg_class.
@@ -44,7 +45,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* If we have auto-increment or auto-decrement and we can have secondary
    reloads, we are not allowed to use classes requiring secondary
-   reloads for psuedos auto-incremented since reload can't handle it.  */
+   reloads for pseudos auto-incremented since reload can't handle it.  */
 
 #ifdef AUTO_INC_DEC
 #if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
@@ -80,6 +81,9 @@ char call_used_regs[FIRST_PSEUDO_REGISTER];
 
 HARD_REG_SET call_used_reg_set;
 
+/* HARD_REG_SET of registers we want to avoid caller saving.  */
+HARD_REG_SET losing_caller_save_reg_set;
+
 /* Data for initializing the above.  */
 
 static char initial_call_used_regs[] = CALL_USED_REGISTERS;
@@ -152,6 +156,13 @@ enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES];
 
 char *reg_names[] = REGISTER_NAMES;
 
+/* For each hard register, the widest mode object that it can contain.
+   This will be a MODE_INT mode if the register can hold integers.  Otherwise
+   it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
+   register.  */
+
+enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
+
 /* Indexed by n, gives number of times (REG n) is set or clobbered.
    This information remains valid for the rest of the compilation
    of the current function; it is used to control register allocation.
@@ -212,7 +223,7 @@ init_reg_sets ()
 
   /* Compute number of hard regs in each class.  */
 
-  bzero (reg_class_size, sizeof reg_class_size);
+  bzero ((char *) reg_class_size, sizeof reg_class_size);
   for (i = 0; i < N_REG_CLASSES; i++)
     for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
       if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
@@ -349,7 +360,7 @@ init_reg_sets ()
 /* After switches have been processed, which perhaps alter
    `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
 
-void
+static void
 init_reg_sets_1 ()
 {
   register int i;
@@ -368,19 +379,11 @@ init_reg_sets_1 ()
   CLEAR_HARD_REG_SET (call_fixed_reg_set);
 
   bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
-#ifdef STRUCT_VALUE_REGNUM
-  call_fixed_regs[STRUCT_VALUE_REGNUM] = 1;
-#endif
-#ifdef STATIC_CHAIN_REGNUM
-  call_fixed_regs[STATIC_CHAIN_REGNUM] = 1;
-#endif
 
   n_non_fixed_regs = 0;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      if (FUNCTION_VALUE_REGNO_P (i))
-       call_fixed_regs[i] = 1;
       if (fixed_regs[i])
        SET_HARD_REG_BIT (fixed_reg_set, i);
       else
@@ -390,9 +393,91 @@ init_reg_sets_1 ()
        SET_HARD_REG_BIT (call_used_reg_set, i);
       if (call_fixed_regs[i])
        SET_HARD_REG_BIT (call_fixed_reg_set, i);
+      if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
+       SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
     }
 }
 
+/* Compute the table of register modes.
+   These values are used to record death information for individual registers
+   (as opposed to a multi-register mode).  */
+
+static void
+init_reg_modes ()
+{
+  register int i;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      reg_raw_mode[i] = choose_hard_reg_mode (i, 1);
+
+      /* If we couldn't find a valid mode, fall back to `word_mode'.
+        ??? We assume `word_mode' has already been initialized.
+         ??? One situation in which we need to do this is on the mips where
+        HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2.  Ideally we'd like
+        to use DF mode for the even registers and VOIDmode for the odd
+        (for the cpu models where the odd ones are inaccessible).  */
+      if (reg_raw_mode[i] == VOIDmode)
+       reg_raw_mode[i] = word_mode;
+    }
+}
+
+/* Finish initializing the register sets and
+   initialize the register modes.  */
+
+void
+init_regs ()
+{
+  /* This finishes what was started by init_reg_sets, but couldn't be done
+     until after register usage was specified.  */
+  if (!output_bytecode)
+    init_reg_sets_1 ();
+
+  init_reg_modes ();
+}
+
+/* Return a machine mode that is legitimate for hard reg REGNO and large
+   enough to save nregs.  If we can't find one, return VOIDmode.  */
+
+enum machine_mode
+choose_hard_reg_mode (regno, nregs)
+     int regno;
+     int nregs;
+{
+  enum machine_mode found_mode = VOIDmode, mode;
+
+  /* We first look for the largest integer mode that can be validly
+     held in REGNO.  If none, we look for the largest floating-point mode.
+     If we still didn't find a valid mode, try CCmode.  */
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (HARD_REGNO_NREGS (regno, mode) == nregs
+       && HARD_REGNO_MODE_OK (regno, mode))
+      found_mode = mode;
+
+  if (found_mode != VOIDmode)
+    return found_mode;
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (HARD_REGNO_NREGS (regno, mode) == nregs
+       && HARD_REGNO_MODE_OK (regno, mode))
+      found_mode = mode;
+
+  if (found_mode != VOIDmode)
+    return found_mode;
+
+  if (HARD_REGNO_NREGS (regno, CCmode) == nregs
+      && HARD_REGNO_MODE_OK (regno, CCmode))
+    return CCmode;
+
+  /* We can't find a mode valid for this register.  */
+  return VOIDmode;
+}
+
 /* Specify the usage characteristics of the register named NAME.
    It should be a fixed register if FIXED and a
    call-used register if CALL_USED.  */
@@ -594,6 +679,10 @@ regclass (f, nregs)
                     being used in such addresses.  */
 
                  if ((0
+#ifdef SECONDARY_RELOAD_CLASS
+                      || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
+#else
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
                       || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
                           != NO_REGS)
@@ -602,6 +691,7 @@ regclass (f, nregs)
                       || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
                           != NO_REGS)
 #endif
+#endif
                       )
                      && ! auto_inc_dec_reg_p (r, m))
                    forbidden_inc_dec_class[i] = 1;
@@ -623,7 +713,7 @@ regclass (f, nregs)
     {
       /* Zero out our accumulation of the cost of each class for each reg.  */
 
-      bzero (costs, nregs * sizeof (struct costs));
+      bzero ((char *) costs, nregs * sizeof (struct costs));
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
       bzero (in_inc_dec, nregs);
@@ -744,7 +834,7 @@ regclass (f, nregs)
                              basic_block_head[b] = newinsn;
                        }
 
-                     /* This makes one more setting of new insns's dest. */
+                     /* This makes one more setting of new insns's dest.  */
                      reg_n_sets[REGNO (recog_operand[0])]++;
 
                      *recog_operand_loc[1] = recog_operand[0];
@@ -888,7 +978,7 @@ regclass (f, nregs)
          
          /* If we don't add any classes, nothing to try.  */
          if (alt == best)
-           alt = (int) NO_REGS;
+           alt = NO_REGS;
 
          /* We cast to (int) because (char) hits bugs in some compilers.  */
          prefclass[i] = (int) best;
@@ -936,6 +1026,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
   int alt;
   enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS];
   int i, j;
+  rtx set;
 
   /* By default, each operand is an input operand.  */
 
@@ -1091,12 +1182,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                break;
 
              case 'E':
+#ifndef REAL_ARITHMETIC
                /* Match any floating double constant, but only if
                   we can examine the bits of it reliably.  */
                if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
                     || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
                    && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
                  break;
+#endif
                if (GET_CODE (op) == CONST_DOUBLE)
                  win = 1;
                break;
@@ -1270,6 +1363,46 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                                     (qq->cost[class] + alt_cost) * scale);
          }
     }
+
+  /* If this insn is a single set copying operand 1 to operand 0
+     and one is a pseudo with the other a hard reg that is in its
+     own register class, set the cost of that register class to -1.  */
+
+  if ((set = single_set (insn)) != 0
+      && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set)
+      && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG)
+    for (i = 0; i <= 1; i++)
+      if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
+       {
+         int regno = REGNO (ops[!i]);
+         enum machine_mode mode = GET_MODE (ops[!i]);
+         int class;
+         int nr;
+
+         if (regno >= FIRST_PSEUDO_REGISTER && prefclass != 0
+             && (reg_class_size[prefclass[regno]]
+                 == CLASS_MAX_NREGS (prefclass[regno], mode)))
+           op_costs[i].cost[prefclass[regno]] = -1;
+         else if (regno < FIRST_PSEUDO_REGISTER)
+           for (class = 0; class < N_REG_CLASSES; class++)
+             if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+                 && reg_class_size[class] == CLASS_MAX_NREGS (class, mode))
+               {
+                 if (reg_class_size[class] == 1)
+                   op_costs[i].cost[class] = -1;
+                 else
+                   {
+                     for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++)
+                       {
+                         if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr))
+                           break;
+                       }
+
+                     if (nr == HARD_REGNO_NREGS(regno,mode))
+                       op_costs[i].cost[class] = -1;
+                   }
+               }
+       }
 }
 \f
 /* Compute the cost of loading X into (if TO_P is non-zero) or from (if
@@ -1556,7 +1689,7 @@ int *regno_last_note_uid;
 static int highest_regno_in_uid_map;
 
 /* Maximum number of parallel sets and clobbers in any insn in this fn.
-   Always at least 3, since the combiner could put that many togetherm
+   Always at least 3, since the combiner could put that many together
    and we want this to remain correct for all the remaining passes.  */
 
 int max_parallel;
@@ -1583,10 +1716,11 @@ reg_scan (f, nregs, repeat)
        = (short *) oballoc (highest_regno_in_uid_map * sizeof (short));
     }
 
-  bzero (regno_first_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (regno_last_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (regno_last_note_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (reg_n_sets, highest_regno_in_uid_map * sizeof (short));
+  bzero ((char *) regno_first_uid, highest_regno_in_uid_map * sizeof (int));
+  bzero ((char *) regno_last_uid, highest_regno_in_uid_map * sizeof (int));
+  bzero ((char *) regno_last_note_uid,
+        highest_regno_in_uid_map * sizeof (int));
+  bzero ((char *) reg_n_sets, highest_regno_in_uid_map * sizeof (short));
 
   max_parallel = 3;
 
@@ -1707,7 +1841,7 @@ reg_scan_mark_refs (x, insn, note_flag)
                      || GET_CODE (XEXP (note, 0)) == LABEL_REF))))
        REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     default:
       {