hard-reg-set.h: Include hash-table.h.
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 22 Sep 2014 07:38:12 +0000 (07:38 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 22 Sep 2014 07:38:12 +0000 (07:38 +0000)
gcc/
* hard-reg-set.h: Include hash-table.h.
(target_hard_regs): Add a finalize method and a x_simplifiable_subregs
field.
* target-globals.c (target_globals::~target_globals): Call
hard_regs->finalize.
* rtl.h (subreg_shape): New structure.
(shape_of_subreg): New function.
(simplifiable_subregs): Declare.
* reginfo.c (simplifiable_subreg): New structure.
(simplifiable_subregs_hasher): Likewise.
(simplifiable_subregs): New function.
(invalid_mode_changes): Delete.
(alid_mode_changes, valid_mode_changes_obstack): New variables.
(record_subregs_of_mode): Remove subregs_of_mode parameter.
Record valid mode changes in valid_mode_changes.
(find_subregs_of_mode): Remove subregs_of_mode parameter.
Update calls to record_subregs_of_mode.
(init_subregs_of_mode): Remove invalid_mode_changes and bitmap
handling.  Initialize new variables.  Update call to
find_subregs_of_mode.
(invalid_mode_change_p): Check new variables instead of
invalid_mode_changes.
(finish_subregs_of_mode): Finalize new variables instead of
invalid_mode_changes.
(target_hard_regs::finalize): New function.
* ira-costs.c (print_allocno_costs): Call invalid_mode_change_p
even when CLASS_CANNOT_CHANGE_MODE is undefined.

From-SVN: r215449

gcc/ChangeLog
gcc/hard-reg-set.h
gcc/ira-costs.c
gcc/reginfo.c
gcc/rtl.h
gcc/target-globals.c

index 830b2efad7497584489ca5b6e2caa754e05847ea..5f6d4a3545053b4d965bbd8f64a136c3be14ecd8 100644 (file)
@@ -1,3 +1,33 @@
+2014-09-22  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * hard-reg-set.h: Include hash-table.h.
+       (target_hard_regs): Add a finalize method and a x_simplifiable_subregs
+       field.
+       * target-globals.c (target_globals::~target_globals): Call
+       hard_regs->finalize.
+       * rtl.h (subreg_shape): New structure.
+       (shape_of_subreg): New function.
+       (simplifiable_subregs): Declare.
+       * reginfo.c (simplifiable_subreg): New structure.
+       (simplifiable_subregs_hasher): Likewise.
+       (simplifiable_subregs): New function.
+       (invalid_mode_changes): Delete.
+       (alid_mode_changes, valid_mode_changes_obstack): New variables.
+       (record_subregs_of_mode): Remove subregs_of_mode parameter.
+       Record valid mode changes in valid_mode_changes.
+       (find_subregs_of_mode): Remove subregs_of_mode parameter.
+       Update calls to record_subregs_of_mode.
+       (init_subregs_of_mode): Remove invalid_mode_changes and bitmap
+       handling.  Initialize new variables.  Update call to
+       find_subregs_of_mode.
+       (invalid_mode_change_p): Check new variables instead of
+       invalid_mode_changes.
+       (finish_subregs_of_mode): Finalize new variables instead of
+       invalid_mode_changes.
+       (target_hard_regs::finalize): New function.
+       * ira-costs.c (print_allocno_costs): Call invalid_mode_change_p
+       even when CLASS_CANNOT_CHANGE_MODE is undefined.
+
 2014-09-22  Richard Sandiford  <richard.sandiford@arm.com>
 
        * combine.c (subst): Use simplify_subreg_regno rather than
index 401fea1bab8a057917340572d79997b5a28512c2..c32516c6913c7fcc9c2e7e20e0b303fe8ddaa788 100644 (file)
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_HARD_REG_SET_H
 #define GCC_HARD_REG_SET_H
 
+#include "hash-table.h"
+
 /* Define the type of a set of hard registers.  */
 
 /* HARD_REG_ELT_TYPE is a typedef of the unsigned integral type which
@@ -613,7 +615,11 @@ hard_reg_set_iter_next (hard_reg_set_iterator *iter, unsigned *regno)
 
 extern char global_regs[FIRST_PSEUDO_REGISTER];
 
+struct simplifiable_subregs_hasher;
+
 struct target_hard_regs {
+  void finalize ();
+
   /* The set of registers that actually exist on the current target.  */
   HARD_REG_SET x_accessible_reg_set;
 
@@ -688,6 +694,10 @@ struct target_hard_regs {
 
   /* Vector indexed by hardware reg giving its name.  */
   const char *x_reg_names[FIRST_PSEUDO_REGISTER];
+
+  /* Records which registers can form a particular subreg, with the subreg
+     being identified by its outer mode, inner mode and offset.  */
+  hash_table <simplifiable_subregs_hasher> *x_simplifiable_subregs;
 };
 
 extern struct target_hard_regs default_target_hard_regs;
index 34da9a73ba3ea0cdbdb264358c898d1c7be2a347..38d0e0edeee82e788a924dd806163c5968a1b8e6 100644 (file)
@@ -1438,10 +1438,7 @@ print_allocno_costs (FILE *f)
        {
          rclass = cost_classes[k];
          if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
-#ifdef CANNOT_CHANGE_MODE_CLASS
-             && ! invalid_mode_change_p (regno, (enum reg_class) rclass)
-#endif
-             )
+             && ! invalid_mode_change_p (regno, (enum reg_class) rclass))
            {
              fprintf (f, " %s:%d", reg_class_names[rclass],
                       COSTS (costs, i)->cost[k]);
@@ -1480,10 +1477,7 @@ print_pseudo_costs (FILE *f)
        {
          rclass = cost_classes[k];
          if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
-#ifdef CANNOT_CHANGE_MODE_CLASS
-             && ! invalid_mode_change_p (regno, (enum reg_class) rclass)
-#endif
-             )
+             && ! invalid_mode_change_p (regno, (enum reg_class) rclass))
            fprintf (f, " %s:%d", reg_class_names[rclass],
                     COSTS (costs, regno)->cost[k]);
        }
@@ -1725,10 +1719,7 @@ find_costs_and_classes (FILE *dump_file)
              /* Ignore classes that are too small or invalid for this
                 operand.  */
              if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
-#ifdef CANNOT_CHANGE_MODE_CLASS
-                 || invalid_mode_change_p (i, (enum reg_class) rclass)
-#endif
-                 )
+                 || invalid_mode_change_p (i, (enum reg_class) rclass))
                continue;
              if (i_costs[k] < best_cost)
                {
@@ -1822,10 +1813,7 @@ find_costs_and_classes (FILE *dump_file)
                      /* Ignore classes that are too small or invalid
                         for this operand.  */
                      if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
-#ifdef CANNOT_CHANGE_MODE_CLASS
-                         || invalid_mode_change_p (i, (enum reg_class) rclass)
-#endif
-                         )
+                         || invalid_mode_change_p (i, (enum reg_class) rclass))
                        ;
                      else if (total_a_costs[k] < best_cost)
                        {
index 8fd5a68660cb466e0f45a9d3dcc368f3c7fe11e0..226152278b4a03a03883830476d3bc1ab3f5bad5 100644 (file)
@@ -54,6 +54,24 @@ along with GCC; see the file COPYING3.  If not see
 
 int max_regno;
 
+/* Used to cache the results of simplifiable_subregs.  SHAPE is the input
+   parameter and SIMPLIFIABLE_REGS is the result.  */
+struct simplifiable_subreg
+{
+  simplifiable_subreg (const subreg_shape &);
+
+  subreg_shape shape;
+  HARD_REG_SET simplifiable_regs;
+};
+
+struct simplifiable_subregs_hasher : typed_noop_remove <simplifiable_subreg>
+{
+  typedef simplifiable_subreg value_type;
+  typedef subreg_shape compare_type;
+
+  static inline hashval_t hash (const value_type *);
+  static inline bool equal (const value_type *, const compare_type *);
+};
 \f
 struct target_hard_regs default_target_hard_regs;
 struct target_regs default_target_regs;
@@ -1193,64 +1211,102 @@ reg_classes_intersect_p (reg_class_t c1, reg_class_t c2)
 }
 
 \f
+inline hashval_t
+simplifiable_subregs_hasher::hash (const value_type *value)
+{
+  return value->shape.unique_id ();
+}
+
+inline bool
+simplifiable_subregs_hasher::equal (const value_type *value,
+                                   const compare_type *compare)
+{
+  return value->shape == *compare;
+}
+
+inline simplifiable_subreg::simplifiable_subreg (const subreg_shape &shape_in)
+  : shape (shape_in)
+{
+  CLEAR_HARD_REG_SET (simplifiable_regs);
+}
+
+/* Return the set of hard registers that are able to form the subreg
+   described by SHAPE.  */
+
+const HARD_REG_SET &
+simplifiable_subregs (const subreg_shape &shape)
+{
+  if (!this_target_hard_regs->x_simplifiable_subregs)
+    this_target_hard_regs->x_simplifiable_subregs
+      = new hash_table <simplifiable_subregs_hasher> (30);
+  simplifiable_subreg **slot
+    = (this_target_hard_regs->x_simplifiable_subregs
+       ->find_slot_with_hash (&shape, shape.unique_id (), INSERT));
+
+  if (!*slot)
+    {
+      simplifiable_subreg *info = new simplifiable_subreg (shape);
+      for (unsigned int i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+       if (HARD_REGNO_MODE_OK (i, shape.inner_mode)
+           && simplify_subreg_regno (i, shape.inner_mode, shape.offset,
+                                     shape.outer_mode) >= 0)
+         SET_HARD_REG_BIT (info->simplifiable_regs, i);
+      *slot = info;
+    }
+  return (*slot)->simplifiable_regs;
+}
 
 /* Passes for keeping and updating info about modes of registers
    inside subregisters.  */
 
-#ifdef CANNOT_CHANGE_MODE_CLASS
-
-static bitmap invalid_mode_changes;
+static HARD_REG_SET **valid_mode_changes;
+static obstack valid_mode_changes_obstack;
 
 static void
-record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode)
+record_subregs_of_mode (rtx subreg)
 {
-  enum machine_mode mode;
   unsigned int regno;
 
   if (!REG_P (SUBREG_REG (subreg)))
     return;
 
   regno = REGNO (SUBREG_REG (subreg));
-  mode = GET_MODE (subreg);
-
   if (regno < FIRST_PSEUDO_REGISTER)
     return;
 
-  if (bitmap_set_bit (subregs_of_mode,
-                     regno * NUM_MACHINE_MODES + (unsigned int) mode))
+  if (valid_mode_changes[regno])
+    AND_HARD_REG_SET (*valid_mode_changes[regno],
+                     simplifiable_subregs (shape_of_subreg (subreg)));
+  else
     {
-      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);
+      valid_mode_changes[regno]
+       = XOBNEW (&valid_mode_changes_obstack, HARD_REG_SET);
+      COPY_HARD_REG_SET (*valid_mode_changes[regno],
+                        simplifiable_subregs (shape_of_subreg (subreg)));
     }
 }
 
 /* Call record_subregs_of_mode for all the subregs in X.  */
 static void
-find_subregs_of_mode (rtx x, bitmap subregs_of_mode)
+find_subregs_of_mode (rtx x)
 {
   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, subregs_of_mode);
+    record_subregs_of_mode (x);
 
   /* 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), subregs_of_mode);
+       find_subregs_of_mode (XEXP (x, i));
       else if (fmt[i] == 'E')
        {
          int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           find_subregs_of_mode (XVECEXP (x, i, j), subregs_of_mode);
+           find_subregs_of_mode (XVECEXP (x, i, j));
        }
     }
 }
@@ -1260,46 +1316,38 @@ init_subregs_of_mode (void)
 {
   basic_block bb;
   rtx_insn *insn;
-  bitmap_obstack srom_obstack;
-  bitmap subregs_of_mode;
 
-  gcc_assert (invalid_mode_changes == NULL);
-  invalid_mode_changes = BITMAP_ALLOC (NULL);
-  bitmap_obstack_initialize (&srom_obstack);
-  subregs_of_mode = BITMAP_ALLOC (&srom_obstack);
+  gcc_obstack_init (&valid_mode_changes_obstack);
+  valid_mode_changes = XCNEWVEC (HARD_REG_SET *, max_reg_num ());
 
   FOR_EACH_BB_FN (bb, cfun)
     FOR_BB_INSNS (bb, 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);
+        find_subregs_of_mode (PATTERN (insn));
 }
 
 /* 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)
+invalid_mode_change_p (unsigned int regno, enum reg_class rclass)
 {
-  return bitmap_bit_p (invalid_mode_changes,
-                      regno * N_REG_CLASSES + (unsigned) rclass);
+  return (valid_mode_changes[regno]
+         && !hard_reg_set_intersect_p (reg_class_contents[rclass],
+                                       *valid_mode_changes[regno]));
 }
 
 void
 finish_subregs_of_mode (void)
 {
-  BITMAP_FREE (invalid_mode_changes);
-}
-#else
-void
-init_subregs_of_mode (void)
-{
+  XDELETEVEC (valid_mode_changes);
+  obstack_finish (&valid_mode_changes_obstack);
 }
+
+/* Free all data attached to the structure.  This isn't a destructor because
+   we don't want to run on exit.  */
+
 void
-finish_subregs_of_mode (void)
+target_hard_regs::finalize ()
 {
+  delete x_simplifiable_subregs;
 }
-
-#endif /* CANNOT_CHANGE_MODE_CLASS */
index 93df69152c21d74cba79751ae5fa50f11362650f..e73f73154386fdd67eaa2671ee37f87f2ff339b6 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1831,6 +1831,64 @@ costs_add_n_insns (struct full_rtx_costs *c, int n)
   c->size += COSTS_N_INSNS (n);
 }
 
+/* Describes the shape of a subreg:
+
+   inner_mode == the mode of the SUBREG_REG
+   offset     == the SUBREG_BYTE
+   outer_mode == the mode of the SUBREG itself.  */
+struct subreg_shape {
+  subreg_shape (enum machine_mode, unsigned int, enum machine_mode);
+  bool operator == (const subreg_shape &) const;
+  bool operator != (const subreg_shape &) const;
+  unsigned int unique_id () const;
+
+  enum machine_mode inner_mode;
+  unsigned int offset;
+  enum machine_mode outer_mode;
+};
+
+inline
+subreg_shape::subreg_shape (enum machine_mode inner_mode_in,
+                           unsigned int offset_in,
+                           enum machine_mode outer_mode_in)
+  : inner_mode (inner_mode_in), offset (offset_in), outer_mode (outer_mode_in)
+{}
+
+inline bool
+subreg_shape::operator == (const subreg_shape &other) const
+{
+  return (inner_mode == other.inner_mode
+         && offset == other.offset
+         && outer_mode == other.outer_mode);
+}
+
+inline bool
+subreg_shape::operator != (const subreg_shape &other) const
+{
+  return !operator == (other);
+}
+
+/* Return an integer that uniquely identifies this shape.  Structures
+   like rtx_def assume that a mode can fit in an 8-bit bitfield and no
+   current mode is anywhere near being 65536 bytes in size, so the
+   id comfortably fits in an int.  */
+
+inline unsigned int
+subreg_shape::unique_id () const
+{
+  STATIC_ASSERT (MAX_MACHINE_MODE <= 256);
+  return (int) inner_mode + ((int) outer_mode << 8) + (offset << 16);
+}
+
+/* Return the shape of a SUBREG rtx.  */
+
+static inline subreg_shape
+shape_of_subreg (const_rtx x)
+{
+  return subreg_shape (GET_MODE (SUBREG_REG (x)),
+                      SUBREG_BYTE (x), GET_MODE (x));
+}
+
 /* Information about an address.  This structure is supposed to be able
    to represent all supported target addresses.  Please extend it if it
    is not yet general enough.  */
@@ -2727,6 +2785,9 @@ extern bool val_signbit_known_clear_p (enum machine_mode,
 /* In reginfo.c  */
 extern enum machine_mode choose_hard_reg_mode (unsigned int, unsigned int,
                                               bool);
+#ifdef HARD_CONST
+extern const HARD_REG_SET &simplifiable_subregs (const subreg_shape &);
+#endif
 
 /* In emit-rtl.c  */
 extern rtx set_for_reg_notes (rtx);
index 43f9f4a0bb1b3f98ad3b36be2ed0f58d8089d2cb..52ac2c02dfcb47817fa113bd2e70115ee2363aaf 100644 (file)
@@ -125,6 +125,7 @@ target_globals::~target_globals ()
   /* default_target_globals points to static data so shouldn't be freed.  */
   if (this != &default_target_globals)
     {
+      hard_regs->finalize ();
       XDELETE (flag_state);
       XDELETE (regs);
       XDELETE (recog);