OSDN Git Service

* gcc-interface/trans.c (can_equal_min_or_max_val_p): Be prepared for
[pf3gnuchains/gcc-fork.git] / gcc / reginfo.c
index f17084c..6353126 100644 (file)
@@ -1,7 +1,7 @@
 /* Compute different info about registers.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
    1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009  Free Software Foundation, Inc.
+   2009, 2010, 2011  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -43,10 +43,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "recog.h"
 #include "reload.h"
-#include "toplev.h"
 #include "diagnostic-core.h"
 #include "output.h"
-#include "ggc.h"
 #include "timevar.h"
 #include "hashtab.h"
 #include "target.h"
@@ -89,10 +87,16 @@ static const char initial_call_really_used_regs[] = CALL_REALLY_USED_REGISTERS;
    and are also considered fixed.  */
 char global_regs[FIRST_PSEUDO_REGISTER];
 
+/* Declaration for the global register. */
+static tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER];
+
 /* Same information as REGS_INVALIDATED_BY_CALL but in regset form to be used
    in dataflow more conveniently.  */
 regset regs_invalidated_by_call_regset;
 
+/* Same information as FIXED_REG_SET but in regset form.  */
+regset fixed_reg_set_regset;
+
 /* The bitmap_obstack is used to hold some static variables that
    should not be reset after each function is compiled.  */
 static bitmap_obstack persistent_obstack;
@@ -121,9 +125,6 @@ const char * reg_class_names[] = REG_CLASS_NAMES;
 #define last_mode_for_init_move_cost \
   (this_target_regs->x_last_mode_for_init_move_cost)
 
-/* Sample MEM values for use by memory_move_secondary_cost.  */
-static GTY(()) rtx top_of_stack[MAX_MACHINE_MODE];
-
 /* No more global register variables may be declared; true once
    reginfo has been initialized.  */
 static int no_global_reg_vars = 0;
@@ -146,8 +147,9 @@ reg_set_to_hard_reg_set (HARD_REG_SET *to, const_bitmap from)
     }
 }
 
-/* Function called only once to initialize the above data on reg usage.
-   Once this is done, various switches may override.  */
+/* Function called only once per target_globals to initialize the
+   target_hard_regs structure.  Once this is done, various switches
+   may override.  */
 void
 init_reg_sets (void)
 {
@@ -190,7 +192,9 @@ init_reg_sets (void)
   memcpy (reg_alloc_order, initial_reg_alloc_order, sizeof reg_alloc_order);
 #endif
   memcpy (reg_names, initial_reg_names, sizeof reg_names);
-  memset (global_regs, 0, sizeof global_regs);
+
+  SET_HARD_REG_SET (accessible_reg_set);
+  SET_HARD_REG_SET (operand_reg_set);
 }
 
 /* Initialize may_move_cost and friends for mode M.  */
@@ -291,6 +295,8 @@ static char saved_call_used_regs[FIRST_PSEUDO_REGISTER];
 static char saved_call_really_used_regs[FIRST_PSEUDO_REGISTER];
 #endif
 static const char *saved_reg_names[FIRST_PSEUDO_REGISTER];
+static HARD_REG_SET saved_accessible_reg_set;
+static HARD_REG_SET saved_operand_reg_set;
 
 /* Save the register information.  */
 void
@@ -314,6 +320,8 @@ save_register_info (void)
   /* And similarly for reg_names.  */
   gcc_assert (sizeof reg_names == sizeof saved_reg_names);
   memcpy (saved_reg_names, reg_names, sizeof reg_names);
+  COPY_HARD_REG_SET (saved_accessible_reg_set, accessible_reg_set);
+  COPY_HARD_REG_SET (saved_operand_reg_set, operand_reg_set);
 }
 
 /* Restore the register information.  */
@@ -329,6 +337,8 @@ restore_register_info (void)
 #endif
 
   memcpy (reg_names, saved_reg_names, sizeof reg_names);
+  COPY_HARD_REG_SET (accessible_reg_set, saved_accessible_reg_set);
+  COPY_HARD_REG_SET (operand_reg_set, saved_operand_reg_set);
 }
 
 /* After switches have been processed, which perhaps alter
@@ -346,12 +356,9 @@ init_reg_sets_1 (void)
     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.  */
+  /* Let the target tweak things if necessary.  */
 
-#ifdef CONDITIONAL_REGISTER_USAGE
-  CONDITIONAL_REGISTER_USAGE;
-#endif
+  targetm.conditional_register_usage ();
 
   /* Compute number of hard regs in each class.  */
 
@@ -456,9 +463,32 @@ init_reg_sets_1 (void)
     }
   else
     CLEAR_REG_SET (regs_invalidated_by_call_regset);
+  if (!fixed_reg_set_regset)
+    fixed_reg_set_regset = ALLOC_REG_SET (&persistent_obstack);
+  else
+    CLEAR_REG_SET (fixed_reg_set_regset);
 
+  AND_HARD_REG_SET (operand_reg_set, accessible_reg_set);
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
+      /* As a special exception, registers whose class is NO_REGS are
+        not accepted by `register_operand'.  The reason for this change
+        is to allow the representation of special architecture artifacts
+        (such as a condition code register) without extending the rtl
+        definitions.  Since registers of class NO_REGS cannot be used
+        as registers in any case where register classes are examined,
+        it is better to apply this exception in a target-independent way.  */
+      if (REGNO_REG_CLASS (i) == NO_REGS)
+       CLEAR_HARD_REG_BIT (operand_reg_set, i);
+
+      /* If a register is too limited to be treated as a register operand,
+        then it should never be allocated to a pseudo.  */
+      if (!TEST_HARD_REG_BIT (operand_reg_set, i))
+       {
+         fixed_regs[i] = 1;
+         call_used_regs[i] = 1;
+       }
+
       /* call_used_regs must include fixed_regs.  */
       gcc_assert (!fixed_regs[i] || call_used_regs[i]);
 #ifdef CALL_REALLY_USED_REGISTERS
@@ -467,7 +497,10 @@ init_reg_sets_1 (void)
 #endif
 
       if (fixed_regs[i])
-       SET_HARD_REG_BIT (fixed_reg_set, i);
+       {
+         SET_HARD_REG_BIT (fixed_reg_set, i);
+         SET_REGNO_REG_SET (fixed_reg_set_regset, i);
+       }
 
       if (call_used_regs[i])
        SET_HARD_REG_BIT (call_used_reg_set, i);
@@ -491,7 +524,7 @@ init_reg_sets_1 (void)
        }
       else if (i == FRAME_POINTER_REGNUM)
        ;
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
       else if (i == HARD_FRAME_POINTER_REGNUM)
        ;
 #endif
@@ -499,10 +532,9 @@ init_reg_sets_1 (void)
       else if (i == ARG_POINTER_REGNUM && fixed_regs[i])
        ;
 #endif
-#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
-      else if (i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
+      else if (!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+              && i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
        ;
-#endif
       else if (CALL_REALLY_USED_REGNO_P (i))
         {
          SET_HARD_REG_BIT (regs_invalidated_by_call, i);
@@ -535,8 +567,7 @@ init_reg_sets_1 (void)
          SET_HARD_REG_BIT (ok_regs, j);
 
       for (i = 0; i < N_REG_CLASSES; i++)
-       if (((unsigned) CLASS_MAX_NREGS ((enum reg_class) i,
-                                        (enum machine_mode) m)
+       if ((targetm.class_max_nregs ((reg_class_t) i, (enum machine_mode) m)
             <= reg_class_size[i])
            && hard_reg_set_intersect_p (ok_regs, reg_class_contents[i]))
          {
@@ -584,13 +615,15 @@ init_reg_modes_target (void)
     {
       reg_raw_mode[i] = choose_hard_reg_mode (i, 1, false);
 
-      /* If we couldn't find a valid mode, just use the previous mode.
-         ??? 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 we couldn't find a valid mode, just use the previous mode
+        if it is suitable, otherwise fall back on word_mode.  */
       if (reg_raw_mode[i] == VOIDmode)
-       reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1];
+       {
+         if (i > 0 && hard_regno_nregs[i][reg_raw_mode[i - 1]] == 1)
+           reg_raw_mode[i] = reg_raw_mode[i - 1];
+         else
+           reg_raw_mode[i] = word_mode;
+       }
     }
 }
 
@@ -632,15 +665,15 @@ init_fake_stack_mems (void)
    TO, using MODE.  */
 
 int
-register_move_cost (enum machine_mode mode, enum reg_class from,
-                    enum reg_class to)
+register_move_cost (enum machine_mode mode, reg_class_t from, reg_class_t to)
 {
   return targetm.register_move_cost (mode, from, to);
 }
 
 /* Compute cost of moving registers to/from memory.  */
+
 int
-memory_move_cost (enum machine_mode mode, enum reg_class rclass, bool in)
+memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in)
 {
   return targetm.memory_move_cost (mode, rclass, in);
 }
@@ -648,10 +681,10 @@ memory_move_cost (enum machine_mode mode, enum reg_class rclass, bool in)
 /* Compute extra cost of moving registers to/from memory due to reloads.
    Only needed if secondary reloads are required for memory moves.  */
 int
-memory_move_secondary_cost (enum machine_mode mode, enum reg_class rclass,
+memory_move_secondary_cost (enum machine_mode mode, reg_class_t rclass,
                            bool in)
 {
-  enum reg_class altclass;
+  reg_class_t altclass;
   int partial_cost = 0;
   /* We need a memory reference to feed to SECONDARY... macros.  */
   /* mem may be unused even if the SECONDARY_ macros are defined.  */
@@ -761,36 +794,69 @@ void
 fix_register (const char *name, int fixed, int call_used)
 {
   int i;
+  int reg, nregs;
 
   /* Decode the name and update the primary form of
      the register info.  */
 
-  if ((i = decode_reg_name (name)) >= 0)
+  if ((reg = decode_reg_name_and_count (name, &nregs)) >= 0)
     {
-      if ((i == STACK_POINTER_REGNUM
+      gcc_assert (nregs >= 1);
+      for (i = reg; i < reg + nregs; i++)
+       {
+         if ((i == STACK_POINTER_REGNUM
 #ifdef HARD_FRAME_POINTER_REGNUM
-          || i == HARD_FRAME_POINTER_REGNUM
+              || i == HARD_FRAME_POINTER_REGNUM
 #else
-          || i == FRAME_POINTER_REGNUM
+              || i == FRAME_POINTER_REGNUM
 #endif
-          )
-         && (fixed == 0 || call_used == 0))
-       {
-         static const char * const what_option[2][2] = {
-           { "call-saved", "call-used" },
-           { "no-such-option", "fixed" }};
-
-         error ("can't use '%s' as a %s register", name,
-                what_option[fixed][call_used]);
-       }
-      else
-       {
-         fixed_regs[i] = fixed;
-         call_used_regs[i] = call_used;
+              )
+             && (fixed == 0 || call_used == 0))
+           {
+             switch (fixed)
+               {
+               case 0:
+                 switch (call_used)
+                   {
+                   case 0:
+                     error ("can%'t use %qs as a call-saved register", name);
+                     break;
+
+                   case 1:
+                     error ("can%'t use %qs as a call-used register", name);
+                     break;
+
+                   default:
+                     gcc_unreachable ();
+                   }
+                 break;
+
+               case 1:
+                 switch (call_used)
+                   {
+                   case 1:
+                     error ("can%'t use %qs as a fixed register", name);
+                     break;
+
+                   case 0:
+                   default:
+                     gcc_unreachable ();
+                   }
+                 break;
+
+               default:
+                 gcc_unreachable ();
+               }
+           }
+         else
+           {
+             fixed_regs[i] = fixed;
+             call_used_regs[i] = call_used;
 #ifdef CALL_REALLY_USED_REGISTERS
-         if (fixed == 0)
-           call_really_used_regs[i] = call_used;
+             if (fixed == 0)
+               call_really_used_regs[i] = call_used;
 #endif
+           }
        }
     }
   else
@@ -801,21 +867,36 @@ fix_register (const char *name, int fixed, int call_used)
 
 /* Mark register number I as global.  */
 void
-globalize_reg (int i)
+globalize_reg (tree decl, int i)
 {
+  location_t loc = DECL_SOURCE_LOCATION (decl);
+
+#ifdef STACK_REGS
+  if (IN_RANGE (i, FIRST_STACK_REG, LAST_STACK_REG))
+    {
+      error ("stack register used for global register variable");
+      return;
+    }
+#endif
+
   if (fixed_regs[i] == 0 && no_global_reg_vars)
-    error ("global register variable follows a function definition");
+    error_at (loc, "global register variable follows a function definition");
 
   if (global_regs[i])
     {
-      warning (0, "register used for two global register variables");
+      warning_at (loc, 0, 
+                 "register of %qD used for multiple global register variables",
+                 decl);
+      inform (DECL_SOURCE_LOCATION (global_regs_decl[i]),
+             "conflicts with %qD", global_regs_decl[i]); 
       return;
     }
 
   if (call_used_regs[i] && ! fixed_regs[i])
-    warning (0, "call-clobbered register used for global register variable");
+    warning_at (loc, 0, "call-clobbered register used for global register variable");
 
   global_regs[i] = 1;
+  global_regs_decl[i] = decl;
 
   /* If we're globalizing the frame pointer, we need to set the
      appropriate regs_invalidated_by_call bit, even if it's already
@@ -859,9 +940,9 @@ struct reg_pref
      union of most major pair of classes, that generality is not required.  */
   char altclass;
 
-  /* coverclass is a register class that IRA uses for allocating
+  /* allocnoclass is a register class that IRA uses for allocating
      the pseudo.  */
-  char coverclass;
+  char allocnoclass;
 };
 
 /* Record preferences of each pseudo.  This is available after RA is
@@ -894,12 +975,12 @@ reg_alternate_class (int regno)
 
 /* Return the reg_class which is used by IRA for its allocation.  */
 enum reg_class
-reg_cover_class (int regno)
+reg_allocno_class (int regno)
 {
   if (reg_pref == 0)
     return NO_REGS;
 
-  return (enum reg_class) reg_pref[regno].coverclass;
+  return (enum reg_class) reg_pref[regno].allocnoclass;
 }
 
 \f
@@ -984,7 +1065,7 @@ struct rtl_opt_pass pass_reginfo_init =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  TV_NONE,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -996,18 +1077,18 @@ struct rtl_opt_pass pass_reginfo_init =
 \f
 
 /* Set up preferred, alternate, and cover classes for REGNO as
-   PREFCLASS, ALTCLASS, and COVERCLASS.  */
+   PREFCLASS, ALTCLASS, and ALLOCNOCLASS.  */
 void
 setup_reg_classes (int regno,
                   enum reg_class prefclass, enum reg_class altclass,
-                  enum reg_class coverclass)
+                  enum reg_class allocnoclass)
 {
   if (reg_pref == NULL)
     return;
   gcc_assert (reg_info_size == max_reg_num ());
   reg_pref[regno].prefclass = prefclass;
   reg_pref[regno].altclass = altclass;
-  reg_pref[regno].coverclass = coverclass;
+  reg_pref[regno].allocnoclass = allocnoclass;
 }
 
 \f
@@ -1178,7 +1259,7 @@ reg_scan_mark_refs (rtx x, rtx insn)
 /* Return nonzero if C1 is a subset of C2, i.e., if every register in C1
    is also in C2.  */
 int
-reg_class_subset_p (enum reg_class c1, enum reg_class c2)
+reg_class_subset_p (reg_class_t c1, reg_class_t c2)
 {
   return (c1 == c2
          || c2 == ALL_REGS
@@ -1204,39 +1285,13 @@ reg_classes_intersect_p (reg_class_t c1, reg_class_t c2)
 
 #ifdef CANNOT_CHANGE_MODE_CLASS
 
-struct subregs_of_mode_node
-{
-  unsigned int block;
-  unsigned char modes[MAX_MACHINE_MODE];
-};
-
-static htab_t subregs_of_mode;
-
-static hashval_t
-som_hash (const void *x)
-{
-  const struct subregs_of_mode_node *const a =
-    (const struct subregs_of_mode_node *) x;
-  return a->block;
-}
-
-static int
-som_eq (const void *x, const void *y)
-{
-  const struct subregs_of_mode_node *const a =
-    (const struct subregs_of_mode_node *) x;
-  const struct subregs_of_mode_node *const b =
-    (const struct subregs_of_mode_node *) y;
-  return a->block == b->block;
-}
+static bitmap invalid_mode_changes;
 
 static void
-record_subregs_of_mode (rtx subreg)
+record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode)
 {
-  struct subregs_of_mode_node dummy, *node;
   enum machine_mode mode;
   unsigned int regno;
-  void **slot;
 
   if (!REG_P (SUBREG_REG (subreg)))
     return;
@@ -1247,41 +1302,41 @@ record_subregs_of_mode (rtx subreg)
   if (regno < FIRST_PSEUDO_REGISTER)
     return;
 
-  dummy.block = regno & -8;
-  slot = htab_find_slot_with_hash (subregs_of_mode, &dummy,
-                                  dummy.block, INSERT);
-  node = (struct subregs_of_mode_node *) *slot;
-  if (node == NULL)
+  if (bitmap_set_bit (subregs_of_mode,
+                     regno * NUM_MACHINE_MODES + (unsigned int) mode))
     {
-      node = XCNEW (struct subregs_of_mode_node);
-      node->block = regno & -8;
-      *slot = node;
+      unsigned int rclass;
+      for (rclass = 0; rclass < N_REG_CLASSES; rclass++)
+       if (!bitmap_bit_p (invalid_mode_changes,
+                          regno * N_REG_CLASSES + rclass)
+           && CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno),
+                                        mode, (enum reg_class) rclass))
+         bitmap_set_bit (invalid_mode_changes,
+                         regno * N_REG_CLASSES + rclass);
     }
-
-  node->modes[mode] |= 1 << (regno & 7);
 }
 
 /* Call record_subregs_of_mode for all the subregs in X.  */
 static void
-find_subregs_of_mode (rtx x)
+find_subregs_of_mode (rtx x, bitmap subregs_of_mode)
 {
   enum rtx_code code = GET_CODE (x);
   const char * const fmt = GET_RTX_FORMAT (code);
   int i;
 
   if (code == SUBREG)
-    record_subregs_of_mode (x);
+    record_subregs_of_mode (x, subregs_of_mode);
 
   /* Time for some deep diving.  */
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       find_subregs_of_mode (XEXP (x, i));
+       find_subregs_of_mode (XEXP (x, i), subregs_of_mode);
       else if (fmt[i] == 'E')
        {
          int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_subregs_of_mode (XVECEXP (x, i, j));
+           find_subregs_of_mode (XVECEXP (x, i, j), subregs_of_mode);
        }
     }
 }
@@ -1291,50 +1346,37 @@ init_subregs_of_mode (void)
 {
   basic_block bb;
   rtx insn;
+  bitmap_obstack srom_obstack;
+  bitmap subregs_of_mode;
 
-  if (subregs_of_mode)
-    htab_empty (subregs_of_mode);
-  else
-    subregs_of_mode = htab_create (100, som_hash, som_eq, free);
+  gcc_assert (invalid_mode_changes == NULL);
+  invalid_mode_changes = BITMAP_ALLOC (NULL);
+  bitmap_obstack_initialize (&srom_obstack);
+  subregs_of_mode = BITMAP_ALLOC (&srom_obstack);
 
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
-    if (INSN_P (insn))
-      find_subregs_of_mode (PATTERN (insn));
+      if (NONDEBUG_INSN_P (insn))
+        find_subregs_of_mode (PATTERN (insn), subregs_of_mode);
+
+  BITMAP_FREE (subregs_of_mode);
+  bitmap_obstack_release (&srom_obstack);
 }
 
 /* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
    mode.  */
 bool
 invalid_mode_change_p (unsigned int regno,
-                      enum reg_class rclass ATTRIBUTE_UNUSED,
-                      enum machine_mode from)
+                      enum reg_class rclass)
 {
-  struct subregs_of_mode_node dummy, *node;
-  unsigned int to;
-  unsigned char mask;
-
-  gcc_assert (subregs_of_mode);
-  dummy.block = regno & -8;
-  node = (struct subregs_of_mode_node *)
-    htab_find_with_hash (subregs_of_mode, &dummy, dummy.block);
-  if (node == NULL)
-    return false;
-
-  mask = 1 << (regno & 7);
-  for (to = VOIDmode; to < NUM_MACHINE_MODES; to++)
-    if (node->modes[to] & mask)
-      if (CANNOT_CHANGE_MODE_CLASS (from, (enum machine_mode) to, rclass))
-       return true;
-
-  return false;
+  return bitmap_bit_p (invalid_mode_changes,
+                      regno * N_REG_CLASSES + (unsigned) rclass);
 }
 
 void
 finish_subregs_of_mode (void)
 {
-  htab_delete (subregs_of_mode);
-  subregs_of_mode = 0;
+  BITMAP_FREE (invalid_mode_changes);
 }
 #else
 void
@@ -1347,5 +1389,3 @@ finish_subregs_of_mode (void)
 }
 
 #endif /* CANNOT_CHANGE_MODE_CLASS */
-
-#include "gt-reginfo.h"