===================================================================
@@ -20,6 +20,8 @@ Software Foundation; either version 3, o
#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 @@ #define EXECUTE_IF_SET_IN_HARD_REG_SET(S
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;
===================================================================
@@ -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);
===================================================================
@@ -1822,6 +1822,64 @@ costs_add_n_insns (struct full_rtx_costs
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. */
@@ -2718,6 +2776,9 @@ extern bool val_signbit_known_clear_p (e
/* 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);
===================================================================
@@ -54,6 +54,24 @@ Software Foundation; either version 3, o
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 *);
+};
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,
}
+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 */
===================================================================
@@ -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)
{