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:
parent
7af3b946a4
commit
6969eb0dcf
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
140
gcc/reginfo.c
140
gcc/reginfo.c
@ -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 *);
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
void
|
||||
finish_subregs_of_mode (void)
|
||||
{
|
||||
XDELETEVEC (valid_mode_changes);
|
||||
obstack_finish (&valid_mode_changes_obstack);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
61
gcc/rtl.h
61
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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user