OSDN Git Service

* config.gcc (powerpc-*-linux*spe*): Use t-dfprules.
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index c80cc6f..8b9e86b 100644 (file)
@@ -1,6 +1,6 @@
 /* Compute register class preferences for pseudo-registers.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
-   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -230,6 +230,9 @@ static move_table *may_move_in_cost[MAX_MACHINE_MODE];
 
 static move_table *may_move_out_cost[MAX_MACHINE_MODE];
 
+/* Keep track of the last mode we initialized move costs for.  */
+static int last_mode_for_init_move_cost;
+
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 
 /* These are the classes that regs which are auto-incremented or decremented
@@ -262,7 +265,7 @@ unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
    with moving single words, but probably isn't worth the trouble.  */
 
 void
-reg_set_to_hard_reg_set (HARD_REG_SET *to, bitmap from)
+reg_set_to_hard_reg_set (HARD_REG_SET *to, const_bitmap from)
 {
   unsigned i;
   bitmap_iterator bi;
@@ -306,11 +309,6 @@ init_reg_sets (void)
   memcpy (fixed_regs, initial_fixed_regs, sizeof fixed_regs);
   memcpy (call_used_regs, initial_call_used_regs, sizeof call_used_regs);
   memset (global_regs, 0, sizeof global_regs);
-
-#ifdef REG_ALLOC_ORDER
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    inv_reg_alloc_order[reg_alloc_order[i]] = i;
-#endif
 }
 
 /* Initialize may_move_cost and friends for mode M.  */
@@ -319,7 +317,6 @@ static void
 init_move_cost (enum machine_mode m)
 {
   static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
-  static int last_mode = -1;
   bool all_match = true;
   unsigned int i, j;
 
@@ -339,14 +336,14 @@ init_move_cost (enum machine_mode m)
          all_match &= (last_move_cost[i][j] == cost);
          last_move_cost[i][j] = cost;
        }
-  if (all_match && last_mode != -1)
+  if (all_match && last_mode_for_init_move_cost != -1)
     {
-      move_cost[m] = move_cost[last_mode];
-      may_move_in_cost[m] = may_move_in_cost[last_mode];
-      may_move_out_cost[m] = may_move_out_cost[last_mode];
+      move_cost[m] = move_cost[last_mode_for_init_move_cost];
+      may_move_in_cost[m] = may_move_in_cost[last_mode_for_init_move_cost];
+      may_move_out_cost[m] = may_move_out_cost[last_mode_for_init_move_cost];
       return;
     }
-  last_mode = m;
+  last_mode_for_init_move_cost = m;
   move_cost[m] = (move_table *)xmalloc (sizeof (move_table)
                                        * N_REG_CLASSES);
   may_move_in_cost[m] = (move_table *)xmalloc (sizeof (move_table)
@@ -403,6 +400,58 @@ init_move_cost (enum machine_mode m)
        }
 }
 
+/* We need to save copies of some of the register information which
+   can be munged by command-line switches so we can restore it during
+   subsequent back-end reinitialization.  */
+
+static char saved_fixed_regs[FIRST_PSEUDO_REGISTER];
+static char saved_call_used_regs[FIRST_PSEUDO_REGISTER];
+#ifdef CALL_REALLY_USED_REGISTERS
+static char saved_call_really_used_regs[FIRST_PSEUDO_REGISTER];
+#endif
+static const char *saved_reg_names[FIRST_PSEUDO_REGISTER];
+
+/* Save the register information.  */
+
+void
+save_register_info (void)
+{
+  /* Sanity check:  make sure the target macros FIXED_REGISTERS and
+     CALL_USED_REGISTERS had the right number of initializers.  */
+  gcc_assert (sizeof fixed_regs == sizeof saved_fixed_regs);
+  gcc_assert (sizeof call_used_regs == sizeof saved_call_used_regs);
+  memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs);
+  memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs);
+
+  /* Likewise for call_really_used_regs.  */
+#ifdef CALL_REALLY_USED_REGISTERS
+  gcc_assert (sizeof call_really_used_regs
+             == sizeof saved_call_really_used_regs);
+  memcpy (saved_call_really_used_regs, call_really_used_regs,
+         sizeof call_really_used_regs);
+#endif
+
+  /* And similarly for reg_names.  */
+  gcc_assert (sizeof reg_names == sizeof saved_reg_names);
+  memcpy (saved_reg_names, reg_names, sizeof reg_names);
+}
+
+/* Restore the register information.  */
+
+static void
+restore_register_info (void)
+{
+  memcpy (fixed_regs, saved_fixed_regs, sizeof fixed_regs);
+  memcpy (call_used_regs, saved_call_used_regs, sizeof call_used_regs);
+
+#ifdef CALL_REALLY_USED_REGISTERS
+  memcpy (call_really_used_regs, saved_call_really_used_regs,
+         sizeof call_really_used_regs);
+#endif
+
+  memcpy (reg_names, saved_reg_names, sizeof reg_names);
+}
+
 /* After switches have been processed, which perhaps alter
    `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
 
@@ -412,6 +461,13 @@ init_reg_sets_1 (void)
   unsigned int i, j;
   unsigned int /* enum machine_mode */ m;
 
+  restore_register_info ();
+
+#ifdef REG_ALLOC_ORDER
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    inv_reg_alloc_order[reg_alloc_order[i]] = i;
+#endif
+
   /* This macro allows the fixed or call-used registers
      and the register classes to depend on target flags.  */
 
@@ -431,6 +487,7 @@ init_reg_sets_1 (void)
      reg_class_subunion[I][J] gets the largest-numbered reg-class
      that is contained in the union of classes I and J.  */
 
+  memset (reg_class_subunion, 0, sizeof reg_class_subunion);
   for (i = 0; i < N_REG_CLASSES; i++)
     {
       for (j = 0; j < N_REG_CLASSES; j++)
@@ -453,6 +510,7 @@ init_reg_sets_1 (void)
      reg_class_superunion[I][J] gets the smallest-numbered reg-class
      containing the union of classes I and J.  */
 
+  memset (reg_class_superunion, 0, sizeof reg_class_superunion);
   for (i = 0; i < N_REG_CLASSES; i++)
     {
       for (j = 0; j < N_REG_CLASSES; j++)
@@ -511,6 +569,7 @@ init_reg_sets_1 (void)
   CLEAR_HARD_REG_SET (call_used_reg_set);
   CLEAR_HARD_REG_SET (call_fixed_reg_set);
   CLEAR_HARD_REG_SET (regs_invalidated_by_call);
+  CLEAR_HARD_REG_SET (losing_caller_save_reg_set);
 
   memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs);
 
@@ -564,6 +623,18 @@ init_reg_sets_1 (void)
        SET_HARD_REG_BIT (regs_invalidated_by_call, i);
     }
 
+  /* Preserve global registers if called more than once.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (global_regs[i])
+       {
+         fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
+         SET_HARD_REG_BIT (fixed_reg_set, i);
+         SET_HARD_REG_BIT (call_used_reg_set, i);
+         SET_HARD_REG_BIT (call_fixed_reg_set, i);
+       }
+    }
+
   memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode));
   memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
   for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
@@ -582,14 +653,36 @@ init_reg_sets_1 (void)
             have_regs_of_mode [m] = 1;
          }
      }
+
+  /* Reset move_cost and friends, making sure we only free shared
+     table entries once.  */
+  for (i = 0; i < MAX_MACHINE_MODE; i++)
+    if (move_cost[i])
+      {
+       for (j = 0; j < i && move_cost[i] != move_cost[j]; j++)
+         ;
+       if (i == j)
+         {
+           free (move_cost[i]);
+           free (may_move_in_cost[i]);
+           free (may_move_out_cost[i]);
+         }
+      }
+  memset (move_cost, 0, sizeof move_cost);
+  memset (may_move_in_cost, 0, sizeof may_move_in_cost);
+  memset (may_move_out_cost, 0, sizeof may_move_out_cost);
+  last_mode_for_init_move_cost = -1;
 }
 
 /* Compute the table of register modes.
    These values are used to record death information for individual registers
-   (as opposed to a multi-register mode).  */
+   (as opposed to a multi-register mode).
+   This function might be invoked more than once, if the target has support
+   for changing register usage conventions on a per-function basis.
+*/
 
 void
-init_reg_modes_once (void)
+init_reg_modes_target (void)
 {
   int i, j;
 
@@ -611,8 +704,10 @@ init_reg_modes_once (void)
     }
 }
 
-/* Finish initializing the register sets and
-   initialize the register modes.  */
+/* Finish initializing the register sets and initialize the register modes.
+   This function might be invoked more than once, if the target has support
+   for changing register usage conventions on a per-function basis.
+*/
 
 void
 init_regs (void)
@@ -964,8 +1059,10 @@ regclass_init (void)
   return 1;
 }
 
-struct tree_opt_pass pass_regclass_init =
+struct rtl_opt_pass pass_regclass_init =
 {
+ {
+  RTL_PASS,
   "regclass",                           /* name */
   NULL,                                 /* gate */
   regclass_init,                        /* execute */
@@ -977,8 +1074,8 @@ struct tree_opt_pass pass_regclass_init =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  'k'                                   /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
 
 
@@ -1046,8 +1143,9 @@ record_operand_costs (rtx insn, struct costs *op_costs,
        record_address_regs (GET_MODE (recog_data.operand[i]),
                             XEXP (recog_data.operand[i], 0),
                             0, MEM, SCRATCH, frequency * 2);
-      else if (constraints[i][0] == 'p'
-              || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
+      else if (recog_data.alternative_enabled_p[0]
+              && (constraints[i][0] == 'p'
+                  || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i])))
        record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS,
                             SCRATCH, frequency * 2);
     }
@@ -1157,6 +1255,7 @@ init_reg_autoinc (void)
 #ifdef FORBIDDEN_INC_DEC_CLASSES
   int i;
 
+  memset (forbidden_inc_dec_class, 0, sizeof forbidden_inc_dec_class);
   for (i = 0; i < N_REG_CLASSES; i++)
     {
       rtx r = gen_rtx_raw_REG (VOIDmode, 0);
@@ -1186,7 +1285,7 @@ init_reg_autoinc (void)
                     requires secondary reloads, disallow its class from
                     being used in such addresses.  */
 
-                 if ((secondary_reload_class (1, base_class, m, r)
+                 if ((secondary_reload_class (0, base_class, m, r)
                       || secondary_reload_class (1, base_class, m, r))
                      && ! auto_inc_dec_reg_p (r, m))
                    forbidden_inc_dec_class[i] = 1;
@@ -1603,7 +1702,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
                    [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
                  break;
 
-               case 'm':  case 'o':  case 'V':
+               case TARGET_MEM_CONSTRAINT:  case 'o':  case 'V':
                  /* It doesn't seem worth distinguishing between offsettable
                     and non-offsettable addresses here.  */
                  allows_mem[i] = 1;
@@ -1834,6 +1933,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
       if (alt_fail)
        continue;
 
+      if (!recog_data.alternative_enabled_p[alt])
+       continue;
+
       /* Finally, update the costs with the information we've calculated
         about this alternative.  */
 
@@ -2227,8 +2329,6 @@ reg_scan (rtx f, unsigned int nregs ATTRIBUTE_UNUSED)
    We should only record information for REGs with numbers
    greater than or equal to MIN_REGNO.  */
 
-extern struct tree_opt_pass *current_pass;
-
 static void
 reg_scan_mark_refs (rtx x, rtx insn)
 {
@@ -2244,6 +2344,7 @@ reg_scan_mark_refs (rtx x, rtx insn)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case CC0:
     case PC:
@@ -2338,10 +2439,7 @@ reg_scan_mark_refs (rtx x, rtx insn)
                 || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)))
            src = XEXP (src, 0);
 
-         if (REG_P (src))
-           REG_ATTRS (dest) = REG_ATTRS (src);
-         if (MEM_P (src))
-           set_reg_attrs_from_mem (dest, src);
+         set_reg_attrs_from_value (dest, src);
        }
 
       /* ... fall through ...  */
@@ -2578,8 +2676,10 @@ gate_subregs_of_mode_init (void)
 #endif
 }
 
-struct tree_opt_pass pass_subregs_of_mode_init =
+struct rtl_opt_pass pass_subregs_of_mode_init =
 {
+ {
+  RTL_PASS,
   "subregs_of_mode_init",               /* name */
   gate_subregs_of_mode_init,            /* gate */
   init_subregs_of_mode,                 /* execute */
@@ -2591,12 +2691,14 @@ struct tree_opt_pass pass_subregs_of_mode_init =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
 
-struct tree_opt_pass pass_subregs_of_mode_finish =
+struct rtl_opt_pass pass_subregs_of_mode_finish =
 {
+ {
+  RTL_PASS,
   "subregs_of_mode_finish",               /* name */
   gate_subregs_of_mode_init,            /* gate */
   finish_subregs_of_mode,               /* execute */
@@ -2608,8 +2710,8 @@ struct tree_opt_pass pass_subregs_of_mode_finish =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };