hard-reg-set.h: Include hash-table.h.

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
This commit is contained in:
Richard Sandiford 2014-09-22 07:38:12 +00:00 committed by Richard Sandiford
parent 7af3b946a4
commit 6969eb0dcf
6 changed files with 200 additions and 62 deletions

View 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> 2014-09-22 Richard Sandiford <richard.sandiford@arm.com>
* combine.c (subst): Use simplify_subreg_regno rather than * combine.c (subst): Use simplify_subreg_regno rather than

View File

@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_HARD_REG_SET_H #ifndef GCC_HARD_REG_SET_H
#define GCC_HARD_REG_SET_H #define GCC_HARD_REG_SET_H
#include "hash-table.h"
/* Define the type of a set of hard registers. */ /* Define the type of a set of hard registers. */
/* HARD_REG_ELT_TYPE is a typedef of the unsigned integral type which /* 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]; extern char global_regs[FIRST_PSEUDO_REGISTER];
struct simplifiable_subregs_hasher;
struct target_hard_regs { struct target_hard_regs {
void finalize ();
/* The set of registers that actually exist on the current target. */ /* The set of registers that actually exist on the current target. */
HARD_REG_SET x_accessible_reg_set; HARD_REG_SET x_accessible_reg_set;
@ -688,6 +694,10 @@ struct target_hard_regs {
/* Vector indexed by hardware reg giving its name. */ /* Vector indexed by hardware reg giving its name. */
const char *x_reg_names[FIRST_PSEUDO_REGISTER]; 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; extern struct target_hard_regs default_target_hard_regs;

View File

@ -1438,10 +1438,7 @@ print_allocno_costs (FILE *f)
{ {
rclass = cost_classes[k]; rclass = cost_classes[k];
if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
#ifdef CANNOT_CHANGE_MODE_CLASS && ! invalid_mode_change_p (regno, (enum reg_class) rclass))
&& ! invalid_mode_change_p (regno, (enum reg_class) rclass)
#endif
)
{ {
fprintf (f, " %s:%d", reg_class_names[rclass], fprintf (f, " %s:%d", reg_class_names[rclass],
COSTS (costs, i)->cost[k]); COSTS (costs, i)->cost[k]);
@ -1480,10 +1477,7 @@ print_pseudo_costs (FILE *f)
{ {
rclass = cost_classes[k]; rclass = cost_classes[k];
if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
#ifdef CANNOT_CHANGE_MODE_CLASS && ! invalid_mode_change_p (regno, (enum reg_class) rclass))
&& ! invalid_mode_change_p (regno, (enum reg_class) rclass)
#endif
)
fprintf (f, " %s:%d", reg_class_names[rclass], fprintf (f, " %s:%d", reg_class_names[rclass],
COSTS (costs, regno)->cost[k]); 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 /* Ignore classes that are too small or invalid for this
operand. */ operand. */
if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)] if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
#ifdef CANNOT_CHANGE_MODE_CLASS || invalid_mode_change_p (i, (enum reg_class) rclass))
|| invalid_mode_change_p (i, (enum reg_class) rclass)
#endif
)
continue; continue;
if (i_costs[k] < best_cost) 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 /* Ignore classes that are too small or invalid
for this operand. */ for this operand. */
if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)] if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
#ifdef CANNOT_CHANGE_MODE_CLASS || invalid_mode_change_p (i, (enum reg_class) rclass))
|| invalid_mode_change_p (i, (enum reg_class) rclass)
#endif
)
; ;
else if (total_a_costs[k] < best_cost) else if (total_a_costs[k] < best_cost)
{ {

View File

@ -54,6 +54,24 @@ along with GCC; see the file COPYING3. If not see
int max_regno; 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_hard_regs default_target_hard_regs;
struct target_regs default_target_regs; struct target_regs default_target_regs;
@ -1193,64 +1211,102 @@ reg_classes_intersect_p (reg_class_t c1, reg_class_t c2)
} }
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 /* Passes for keeping and updating info about modes of registers
inside subregisters. */ inside subregisters. */
#ifdef CANNOT_CHANGE_MODE_CLASS static HARD_REG_SET **valid_mode_changes;
static obstack valid_mode_changes_obstack;
static bitmap invalid_mode_changes;
static void 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; unsigned int regno;
if (!REG_P (SUBREG_REG (subreg))) if (!REG_P (SUBREG_REG (subreg)))
return; return;
regno = REGNO (SUBREG_REG (subreg)); regno = REGNO (SUBREG_REG (subreg));
mode = GET_MODE (subreg);
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
return; return;
if (bitmap_set_bit (subregs_of_mode, if (valid_mode_changes[regno])
regno * NUM_MACHINE_MODES + (unsigned int) mode)) AND_HARD_REG_SET (*valid_mode_changes[regno],
simplifiable_subregs (shape_of_subreg (subreg)));
else
{ {
unsigned int rclass; valid_mode_changes[regno]
for (rclass = 0; rclass < N_REG_CLASSES; rclass++) = XOBNEW (&valid_mode_changes_obstack, HARD_REG_SET);
if (!bitmap_bit_p (invalid_mode_changes, COPY_HARD_REG_SET (*valid_mode_changes[regno],
regno * N_REG_CLASSES + rclass) simplifiable_subregs (shape_of_subreg (subreg)));
&& CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno),
mode, (enum reg_class) rclass))
bitmap_set_bit (invalid_mode_changes,
regno * N_REG_CLASSES + rclass);
} }
} }
/* Call record_subregs_of_mode for all the subregs in X. */ /* Call record_subregs_of_mode for all the subregs in X. */
static void 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); enum rtx_code code = GET_CODE (x);
const char * const fmt = GET_RTX_FORMAT (code); const char * const fmt = GET_RTX_FORMAT (code);
int i; int i;
if (code == SUBREG) if (code == SUBREG)
record_subregs_of_mode (x, subregs_of_mode); record_subregs_of_mode (x);
/* Time for some deep diving. */ /* Time for some deep diving. */
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{ {
if (fmt[i] == 'e') 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') else if (fmt[i] == 'E')
{ {
int j; int j;
for (j = XVECLEN (x, i) - 1; j >= 0; 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; basic_block bb;
rtx_insn *insn; rtx_insn *insn;
bitmap_obstack srom_obstack;
bitmap subregs_of_mode;
gcc_assert (invalid_mode_changes == NULL); gcc_obstack_init (&valid_mode_changes_obstack);
invalid_mode_changes = BITMAP_ALLOC (NULL); valid_mode_changes = XCNEWVEC (HARD_REG_SET *, max_reg_num ());
bitmap_obstack_initialize (&srom_obstack);
subregs_of_mode = BITMAP_ALLOC (&srom_obstack);
FOR_EACH_BB_FN (bb, cfun) FOR_EACH_BB_FN (bb, cfun)
FOR_BB_INSNS (bb, insn) FOR_BB_INSNS (bb, insn)
if (NONDEBUG_INSN_P (insn)) if (NONDEBUG_INSN_P (insn))
find_subregs_of_mode (PATTERN (insn), subregs_of_mode); find_subregs_of_mode (PATTERN (insn));
BITMAP_FREE (subregs_of_mode);
bitmap_obstack_release (&srom_obstack);
} }
/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM /* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
mode. */ mode. */
bool bool
invalid_mode_change_p (unsigned int regno, invalid_mode_change_p (unsigned int regno, enum reg_class rclass)
enum reg_class rclass)
{ {
return bitmap_bit_p (invalid_mode_changes, return (valid_mode_changes[regno]
regno * N_REG_CLASSES + (unsigned) rclass); && !hard_reg_set_intersect_p (reg_class_contents[rclass],
*valid_mode_changes[regno]));
} }
void void
finish_subregs_of_mode (void) finish_subregs_of_mode (void)
{ {
BITMAP_FREE (invalid_mode_changes); XDELETEVEC (valid_mode_changes);
} obstack_finish (&valid_mode_changes_obstack);
#else
void
init_subregs_of_mode (void)
{
}
void
finish_subregs_of_mode (void)
{
} }
#endif /* CANNOT_CHANGE_MODE_CLASS */ /* Free all data attached to the structure. This isn't a destructor because
we don't want to run on exit. */
void
target_hard_regs::finalize ()
{
delete x_simplifiable_subregs;
}

View File

@ -1831,6 +1831,64 @@ costs_add_n_insns (struct full_rtx_costs *c, int n)
c->size += COSTS_N_INSNS (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 /* Information about an address. This structure is supposed to be able
to represent all supported target addresses. Please extend it if it to represent all supported target addresses. Please extend it if it
is not yet general enough. */ is not yet general enough. */
@ -2727,6 +2785,9 @@ extern bool val_signbit_known_clear_p (enum machine_mode,
/* In reginfo.c */ /* In reginfo.c */
extern enum machine_mode choose_hard_reg_mode (unsigned int, unsigned int, extern enum machine_mode choose_hard_reg_mode (unsigned int, unsigned int,
bool); bool);
#ifdef HARD_CONST
extern const HARD_REG_SET &simplifiable_subregs (const subreg_shape &);
#endif
/* In emit-rtl.c */ /* In emit-rtl.c */
extern rtx set_for_reg_notes (rtx); extern rtx set_for_reg_notes (rtx);

View File

@ -125,6 +125,7 @@ target_globals::~target_globals ()
/* default_target_globals points to static data so shouldn't be freed. */ /* default_target_globals points to static data so shouldn't be freed. */
if (this != &default_target_globals) if (this != &default_target_globals)
{ {
hard_regs->finalize ();
XDELETE (flag_state); XDELETE (flag_state);
XDELETE (regs); XDELETE (regs);
XDELETE (recog); XDELETE (recog);