#include "reload.h"
#include "recog.h"
#include "output.h"
-#include "cselib.h"
#include "real.h"
#include "toplev.h"
#include "except.h"
fixing up each insn, and generating the new insns to copy values
into the reload registers. */
-#ifndef REGISTER_MOVE_COST
-#define REGISTER_MOVE_COST(m, x, y) 2
-#endif
-
#ifndef LOCAL_REGNO
#define LOCAL_REGNO(REGNO) 0
#endif
examine. */
struct insn_chain *reload_insn_chain;
-#ifdef TREE_CODE
-extern tree current_function_decl;
-#else
-extern union tree_node *current_function_decl;
-#endif
-
/* List of all insns needing reloads. */
static struct insn_chain *insns_need_reload;
\f
{
int from; /* Register number to be eliminated. */
int to; /* Register number used as replacement. */
- int initial_offset; /* Initial difference between values. */
+ HOST_WIDE_INT initial_offset; /* Initial difference between values. */
int can_eliminate; /* Nonzero if this elimination can be done. */
int can_eliminate_previous; /* Value of CAN_ELIMINATE in previous scan over
insns made by reload. */
- int offset; /* Current offset between the two regs. */
- int previous_offset; /* Offset at end of previous insn. */
+ HOST_WIDE_INT offset; /* Current offset between the two regs. */
+ HOST_WIDE_INT previous_offset;/* Offset at end of previous insn. */
int ref_outside_mem; /* "to" has been referenced outside a MEM. */
rtx from_rtx; /* REG rtx for the register to be eliminated.
We cannot simply compare the number since
static int first_label_num;
static char *offsets_known_at;
-static int (*offsets_at)[NUM_ELIMINABLE_REGS];
+static HOST_WIDE_INT (*offsets_at)[NUM_ELIMINABLE_REGS];
/* Number of labels in the current function. */
static int num_labels;
\f
-static void replace_pseudos_in_call_usage PARAMS ((rtx *,
- enum machine_mode,
- rtx));
-static void maybe_fix_stack_asms PARAMS ((void));
-static void copy_reloads PARAMS ((struct insn_chain *));
-static void calculate_needs_all_insns PARAMS ((int));
-static int find_reg PARAMS ((struct insn_chain *, int));
-static void find_reload_regs PARAMS ((struct insn_chain *));
-static void select_reload_regs PARAMS ((void));
-static void delete_caller_save_insns PARAMS ((void));
-
-static void spill_failure PARAMS ((rtx, enum reg_class));
-static void count_spilled_pseudo PARAMS ((int, int, int));
-static void delete_dead_insn PARAMS ((rtx));
-static void alter_reg PARAMS ((int, int));
-static void set_label_offsets PARAMS ((rtx, rtx, int));
-static void check_eliminable_occurrences PARAMS ((rtx));
-static void elimination_effects PARAMS ((rtx, enum machine_mode));
-static int eliminate_regs_in_insn PARAMS ((rtx, int));
-static void update_eliminable_offsets PARAMS ((void));
-static void mark_not_eliminable PARAMS ((rtx, rtx, void *));
-static void set_initial_elim_offsets PARAMS ((void));
-static void verify_initial_elim_offsets PARAMS ((void));
-static void set_initial_label_offsets PARAMS ((void));
-static void set_offsets_for_label PARAMS ((rtx));
-static void init_elim_table PARAMS ((void));
-static void update_eliminables PARAMS ((HARD_REG_SET *));
-static void spill_hard_reg PARAMS ((unsigned int, int));
-static int finish_spills PARAMS ((int));
-static void ior_hard_reg_set PARAMS ((HARD_REG_SET *, HARD_REG_SET *));
-static void scan_paradoxical_subregs PARAMS ((rtx));
-static void count_pseudo PARAMS ((int));
-static void order_regs_for_reload PARAMS ((struct insn_chain *));
-static void reload_as_needed PARAMS ((int));
-static void forget_old_reloads_1 PARAMS ((rtx, rtx, void *));
-static int reload_reg_class_lower PARAMS ((const PTR, const PTR));
-static void mark_reload_reg_in_use PARAMS ((unsigned int, int,
- enum reload_type,
- enum machine_mode));
-static void clear_reload_reg_in_use PARAMS ((unsigned int, int,
- enum reload_type,
- enum machine_mode));
-static int reload_reg_free_p PARAMS ((unsigned int, int,
- enum reload_type));
-static int reload_reg_free_for_value_p PARAMS ((int, int, int,
- enum reload_type,
- rtx, rtx, int, int));
-static int free_for_value_p PARAMS ((int, enum machine_mode, int,
- enum reload_type, rtx, rtx,
- int, int));
-static int reload_reg_reaches_end_p PARAMS ((unsigned int, int,
- enum reload_type));
-static int allocate_reload_reg PARAMS ((struct insn_chain *, int,
- int));
-static int conflicts_with_override PARAMS ((rtx));
-static void failed_reload PARAMS ((rtx, int));
-static int set_reload_reg PARAMS ((int, int));
-static void choose_reload_regs_init PARAMS ((struct insn_chain *, rtx *));
-static void choose_reload_regs PARAMS ((struct insn_chain *));
-static void merge_assigned_reloads PARAMS ((rtx));
-static void emit_input_reload_insns PARAMS ((struct insn_chain *,
- struct reload *, rtx, int));
-static void emit_output_reload_insns PARAMS ((struct insn_chain *,
- struct reload *, int));
-static void do_input_reload PARAMS ((struct insn_chain *,
- struct reload *, int));
-static void do_output_reload PARAMS ((struct insn_chain *,
- struct reload *, int));
-static void emit_reload_insns PARAMS ((struct insn_chain *));
-static void delete_output_reload PARAMS ((rtx, int, int));
-static void delete_address_reloads PARAMS ((rtx, rtx));
-static void delete_address_reloads_1 PARAMS ((rtx, rtx, rtx));
-static rtx inc_for_reload PARAMS ((rtx, rtx, rtx, int));
-static void reload_cse_regs_1 PARAMS ((rtx));
-static int reload_cse_noop_set_p PARAMS ((rtx));
-static int reload_cse_simplify_set PARAMS ((rtx, rtx));
-static int reload_cse_simplify_operands PARAMS ((rtx, rtx));
-static void reload_combine PARAMS ((void));
-static void reload_combine_note_use PARAMS ((rtx *, rtx));
-static void reload_combine_note_store PARAMS ((rtx, rtx, void *));
-static void reload_cse_move2add PARAMS ((rtx));
-static void move2add_note_store PARAMS ((rtx, rtx, void *));
+static void replace_pseudos_in (rtx *, enum machine_mode, rtx);
+static void maybe_fix_stack_asms (void);
+static void copy_reloads (struct insn_chain *);
+static void calculate_needs_all_insns (int);
+static int find_reg (struct insn_chain *, int);
+static void find_reload_regs (struct insn_chain *);
+static void select_reload_regs (void);
+static void delete_caller_save_insns (void);
+
+static void spill_failure (rtx, enum reg_class);
+static void count_spilled_pseudo (int, int, int);
+static void delete_dead_insn (rtx);
+static void alter_reg (int, int);
+static void set_label_offsets (rtx, rtx, int);
+static void check_eliminable_occurrences (rtx);
+static void elimination_effects (rtx, enum machine_mode);
+static int eliminate_regs_in_insn (rtx, int);
+static void update_eliminable_offsets (void);
+static void mark_not_eliminable (rtx, rtx, void *);
+static void set_initial_elim_offsets (void);
+static void verify_initial_elim_offsets (void);
+static void set_initial_label_offsets (void);
+static void set_offsets_for_label (rtx);
+static void init_elim_table (void);
+static void update_eliminables (HARD_REG_SET *);
+static void spill_hard_reg (unsigned int, int);
+static int finish_spills (int);
+static void ior_hard_reg_set (HARD_REG_SET *, HARD_REG_SET *);
+static void scan_paradoxical_subregs (rtx);
+static void count_pseudo (int);
+static void order_regs_for_reload (struct insn_chain *);
+static void reload_as_needed (int);
+static void forget_old_reloads_1 (rtx, rtx, void *);
+static int reload_reg_class_lower (const void *, const void *);
+static void mark_reload_reg_in_use (unsigned int, int, enum reload_type,
+ enum machine_mode);
+static void clear_reload_reg_in_use (unsigned int, int, enum reload_type,
+ enum machine_mode);
+static int reload_reg_free_p (unsigned int, int, enum reload_type);
+static int reload_reg_free_for_value_p (int, int, int, enum reload_type,
+ rtx, rtx, int, int);
+static int free_for_value_p (int, enum machine_mode, int, enum reload_type,
+ rtx, rtx, int, int);
+static int reload_reg_reaches_end_p (unsigned int, int, enum reload_type);
+static int allocate_reload_reg (struct insn_chain *, int, int);
+static int conflicts_with_override (rtx);
+static void failed_reload (rtx, int);
+static int set_reload_reg (int, int);
+static void choose_reload_regs_init (struct insn_chain *, rtx *);
+static void choose_reload_regs (struct insn_chain *);
+static void merge_assigned_reloads (rtx);
+static void emit_input_reload_insns (struct insn_chain *, struct reload *,
+ rtx, int);
+static void emit_output_reload_insns (struct insn_chain *, struct reload *,
+ int);
+static void do_input_reload (struct insn_chain *, struct reload *, int);
+static void do_output_reload (struct insn_chain *, struct reload *, int);
+static void emit_reload_insns (struct insn_chain *);
+static void delete_output_reload (rtx, int, int);
+static void delete_address_reloads (rtx, rtx);
+static void delete_address_reloads_1 (rtx, rtx, rtx);
+static rtx inc_for_reload (rtx, rtx, rtx, int);
#ifdef AUTO_INC_DEC
-static void add_auto_inc_notes PARAMS ((rtx, rtx));
+static void add_auto_inc_notes (rtx, rtx);
#endif
-static void copy_eh_notes PARAMS ((rtx, rtx));
-static void failed_reload PARAMS ((rtx, int));
-static int set_reload_reg PARAMS ((int, int));
-static void reload_cse_simplify PARAMS ((rtx, rtx));
-void fixup_abnormal_edges PARAMS ((void));
-extern void dump_needs PARAMS ((struct insn_chain *));
+static void copy_eh_notes (rtx, rtx);
\f
/* Initialize the reload pass once per compilation. */
void
-init_reload ()
+init_reload (void)
{
int i;
/* Initialize obstack for our rtl allocation. */
gcc_obstack_init (&reload_obstack);
- reload_startobj = (char *) obstack_alloc (&reload_obstack, 0);
+ reload_startobj = obstack_alloc (&reload_obstack, 0);
INIT_REG_SET (&spilled_pseudos);
INIT_REG_SET (&pseudos_counted);
/* Allocate an empty insn_chain structure. */
struct insn_chain *
-new_insn_chain ()
+new_insn_chain (void)
{
struct insn_chain *c;
if (unused_insn_chains == 0)
{
- c = (struct insn_chain *)
- obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
+ c = obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
INIT_REG_SET (&c->live_throughout);
INIT_REG_SET (&c->dead_or_set);
}
allocated to pseudos in regset FROM. */
void
-compute_use_by_pseudos (to, from)
- HARD_REG_SET *to;
- regset from;
+compute_use_by_pseudos (HARD_REG_SET *to, regset from)
{
unsigned int regno;
equivalences. */
static void
-replace_pseudos_in_call_usage (loc, mem_mode, usage)
- rtx *loc;
- enum machine_mode mem_mode;
- rtx usage;
+replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage)
{
rtx x = *loc;
enum rtx_code code;
if (x != *loc)
{
*loc = x;
- replace_pseudos_in_call_usage (loc, mem_mode, usage);
+ replace_pseudos_in (loc, mem_mode, usage);
return;
}
}
else if (code == MEM)
{
- replace_pseudos_in_call_usage (& XEXP (x, 0), GET_MODE (x), usage);
+ replace_pseudos_in (& XEXP (x, 0), GET_MODE (x), usage);
return;
}
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
if (*fmt == 'e')
- replace_pseudos_in_call_usage (&XEXP (x, i), mem_mode, usage);
+ replace_pseudos_in (&XEXP (x, i), mem_mode, usage);
else if (*fmt == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
- replace_pseudos_in_call_usage (& XVECEXP (x, i, j), mem_mode, usage);
+ replace_pseudos_in (& XVECEXP (x, i, j), mem_mode, usage);
}
\f
and we must not do any more for this function. */
int
-reload (first, global)
- rtx first;
- int global;
+reload (rtx first, int global)
{
int i;
rtx insn;
failure = 0;
- reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+ reload_firstobj = obstack_alloc (&reload_obstack, 0);
/* Make sure that the last insn in the chain
is not something that needs reloading. */
- emit_note (NULL, NOTE_INSN_DELETED);
+ emit_note (NOTE_INSN_DELETED);
/* Enable find_equiv_reg to distinguish insns made by reload. */
reload_first_uid = get_max_uid ();
#endif
/* We don't have a stack slot for any spill reg yet. */
- memset ((char *) spill_stack_slot, 0, sizeof spill_stack_slot);
- memset ((char *) spill_stack_slot_width, 0, sizeof spill_stack_slot_width);
+ memset (spill_stack_slot, 0, sizeof spill_stack_slot);
+ memset (spill_stack_slot_width, 0, sizeof spill_stack_slot_width);
/* Initialize the save area information for caller-save, in case some
are needed. */
Record memory equivalents in reg_mem_equiv so they can
be substituted eventually by altering the REG-rtx's. */
- reg_equiv_constant = (rtx *) xcalloc (max_regno, sizeof (rtx));
- reg_equiv_mem = (rtx *) xcalloc (max_regno, sizeof (rtx));
- reg_equiv_init = (rtx *) xcalloc (max_regno, sizeof (rtx));
- reg_equiv_address = (rtx *) xcalloc (max_regno, sizeof (rtx));
- reg_max_ref_width = (unsigned int *) xcalloc (max_regno, sizeof (int));
- reg_old_renumber = (short *) xcalloc (max_regno, sizeof (short));
+ reg_equiv_constant = xcalloc (max_regno, sizeof (rtx));
+ reg_equiv_mem = xcalloc (max_regno, sizeof (rtx));
+ reg_equiv_init = xcalloc (max_regno, sizeof (rtx));
+ reg_equiv_address = xcalloc (max_regno, sizeof (rtx));
+ reg_max_ref_width = xcalloc (max_regno, sizeof (int));
+ reg_old_renumber = xcalloc (max_regno, sizeof (short));
memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short));
- pseudo_forbidden_regs
- = (HARD_REG_SET *) xmalloc (max_regno * sizeof (HARD_REG_SET));
- pseudo_previous_regs
- = (HARD_REG_SET *) xcalloc (max_regno, sizeof (HARD_REG_SET));
+ pseudo_forbidden_regs = xmalloc (max_regno * sizeof (HARD_REG_SET));
+ pseudo_previous_regs = xcalloc (max_regno, sizeof (HARD_REG_SET));
CLEAR_HARD_REG_SET (bad_spill_regs_global);
allocate would occasionally cause it to exceed the stack limit and
cause a core dump. */
offsets_known_at = xmalloc (num_labels);
- offsets_at
- = (int (*)[NUM_ELIMINABLE_REGS])
- xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
+ offsets_at = xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
/* Alter each pseudo-reg rtx to contain its hard reg number.
Assign stack slots to the pseudos that lack hard regs or equivalents.
{
save_call_clobbered_regs ();
/* That might have allocated new insn_chain structures. */
- reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+ reload_firstobj = obstack_alloc (&reload_obstack, 0);
}
calculate_needs_all_insns (global);
rtx *pnote;
if (GET_CODE (insn) == CALL_INSN)
- replace_pseudos_in_call_usage (& CALL_INSN_FUNCTION_USAGE (insn),
- VOIDmode,
- CALL_INSN_FUNCTION_USAGE (insn));
+ replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn),
+ VOIDmode, CALL_INSN_FUNCTION_USAGE (insn));
if ((GET_CODE (PATTERN (insn)) == USE
/* We mark with QImode USEs introduced by reload itself. */
&& (GET_CODE (XEXP (PATTERN (insn), 0)) != MEM
|| GET_MODE (XEXP (PATTERN (insn), 0)) != BLKmode
|| (GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) != SCRATCH
- && XEXP (XEXP (PATTERN (insn), 0), 0)
+ && XEXP (XEXP (PATTERN (insn), 0), 0)
!= stack_pointer_rtx))
&& (GET_CODE (XEXP (PATTERN (insn), 0)) != REG
|| ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))))
continue;
}
+ /* Some CLOBBERs may survive until here and still reference unassigned
+ pseudos with const equivalent, which may in turn cause ICE in later
+ passes if the reference remains in place. */
+ if (GET_CODE (PATTERN (insn)) == CLOBBER)
+ replace_pseudos_in (& XEXP (PATTERN (insn), 0),
+ VOIDmode, PATTERN (insn));
+
pnote = ®_NOTES (insn);
while (*pnote != 0)
{
The whole thing is rather sick, I'm afraid. */
static void
-maybe_fix_stack_asms ()
+maybe_fix_stack_asms (void)
{
#ifdef STACK_REGS
const char *constraints[MAX_RECOG_OPERANDS];
/* Copy the global variables n_reloads and rld into the corresponding elts
of CHAIN. */
static void
-copy_reloads (chain)
- struct insn_chain *chain;
+copy_reloads (struct insn_chain *chain)
{
chain->n_reloads = n_reloads;
- chain->rld
- = (struct reload *) obstack_alloc (&reload_obstack,
- n_reloads * sizeof (struct reload));
+ chain->rld = obstack_alloc (&reload_obstack,
+ n_reloads * sizeof (struct reload));
memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
- reload_insn_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+ reload_insn_firstobj = obstack_alloc (&reload_obstack, 0);
}
/* Walk the chain of insns, and determine for each whether it needs reloads
and/or eliminations. Build the corresponding insns_need_reload list, and
set something_needs_elimination as appropriate. */
static void
-calculate_needs_all_insns (global)
- int global;
+calculate_needs_all_insns (int global)
{
struct insn_chain **pprev_reload = &insns_need_reload;
struct insn_chain *chain, *next = 0;
something_needs_elimination = 0;
- reload_insn_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+ reload_insn_firstobj = obstack_alloc (&reload_obstack, 0);
for (chain = reload_insn_chain; chain != 0; chain = next)
{
rtx insn = chain->insn;
should be handled first. *P1 and *P2 are the reload numbers. */
static int
-reload_reg_class_lower (r1p, r2p)
- const PTR r1p;
- const PTR r2p;
+reload_reg_class_lower (const void *r1p, const void *r2p)
{
int r1 = *(const short *) r1p, r2 = *(const short *) r2p;
int t;
/* Update the spill cost arrays, considering that pseudo REG is live. */
static void
-count_pseudo (reg)
- int reg;
+count_pseudo (int reg)
{
int freq = REG_FREQ (reg);
int r = reg_renumber[reg];
contents of BAD_SPILL_REGS for the insn described by CHAIN. */
static void
-order_regs_for_reload (chain)
- struct insn_chain *chain;
+order_regs_for_reload (struct insn_chain *chain)
{
int i;
HARD_REG_SET used_by_pseudos;
update SPILL_COST/SPILL_ADD_COST. */
static void
-count_spilled_pseudo (spilled, spilled_nregs, reg)
- int spilled, spilled_nregs, reg;
+count_spilled_pseudo (int spilled, int spilled_nregs, int reg)
{
int r = reg_renumber[reg];
int nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
/* Find reload register to use for reload number ORDER. */
static int
-find_reg (chain, order)
- struct insn_chain *chain;
- int order;
+find_reg (struct insn_chain *chain, int order)
{
int rnum = reload_order[order];
struct reload *rl = rld + rnum;
for a smaller class even though it belongs to that class. */
static void
-find_reload_regs (chain)
- struct insn_chain *chain;
+find_reload_regs (struct insn_chain *chain)
{
int i;
}
static void
-select_reload_regs ()
+select_reload_regs (void)
{
struct insn_chain *chain;
/* Delete all insns that were inserted by emit_caller_save_insns during
this iteration. */
static void
-delete_caller_save_insns ()
+delete_caller_save_insns (void)
{
struct insn_chain *c = reload_insn_chain;
INSN should be one of the insns which needed this particular spill reg. */
static void
-spill_failure (insn, class)
- rtx insn;
- enum reg_class class;
+spill_failure (rtx insn, enum reg_class class)
{
static const char *const reg_class_names[] = REG_CLASS_NAMES;
if (asm_noperands (PATTERN (insn)) >= 0)
data that is dead in INSN. */
static void
-delete_dead_insn (insn)
- rtx insn;
+delete_dead_insn (rtx insn)
{
rtx prev = prev_real_insn (insn);
rtx prev_dest;
can share one stack slot. */
static void
-alter_reg (i, from_reg)
- int i;
- int from_reg;
+alter_reg (int i, int from_reg)
{
/* When outputting an inline function, this can happen
for a reg that isn't actually used. */
used by pseudo-reg number REGNO. */
void
-mark_home_live (regno)
- int regno;
+mark_home_live (int regno)
{
int i, lim;
current offset. */
static void
-set_label_offsets (x, insn, initial_p)
- rtx x;
- rtx insn;
- int initial_p;
+set_label_offsets (rtx x, rtx insn, int initial_p)
{
enum rtx_code code = GET_CODE (x);
rtx tem;
the proper thing. */
rtx
-eliminate_regs (x, mem_mode, insn)
- rtx x;
- enum machine_mode mem_mode;
- rtx insn;
+eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
{
enum rtx_code code = GET_CODE (x);
struct elim_table *ep;
Convert (subreg (mem)) to (mem) if not paradoxical.
Also, if we have a non-paradoxical (subreg (pseudo)) and the
pseudo didn't get a hard reg, we must replace this with the
- eliminated version of the memory location because push_reloads
+ eliminated version of the memory location because push_reload
may do the replacement in certain circumstances. */
if (GET_CODE (SUBREG_REG (x)) == REG
&& (GET_MODE_SIZE (GET_MODE (x))
happen to the entire word. Moreover, it will use the
(reg:m2 R) later, expecting all bits to be preserved.
So if the number of words is the same, preserve the
- subreg so that push_reloads can see it. */
+ subreg so that push_reload can see it. */
&& ! ((x_size - 1) / UNITS_PER_WORD
== (new_size -1 ) / UNITS_PER_WORD)
#endif
if (new != XEXP (x, i) && ! copied)
{
rtx new_x = rtx_alloc (code);
- memcpy (new_x, x,
- (sizeof (*new_x) - sizeof (new_x->fld)
- + sizeof (new_x->fld[0]) * GET_RTX_LENGTH (code)));
+ memcpy (new_x, x, RTX_SIZE (code));
x = new_x;
copied = 1;
}
if (! copied)
{
rtx new_x = rtx_alloc (code);
- memcpy (new_x, x,
- (sizeof (*new_x) - sizeof (new_x->fld)
- + (sizeof (new_x->fld[0])
- * GET_RTX_LENGTH (code))));
+ memcpy (new_x, x, RTX_SIZE (code));
x = new_x;
copied = 1;
}
the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM. */
static void
-elimination_effects (x, mem_mode)
- rtx x;
- enum machine_mode mem_mode;
-
+elimination_effects (rtx x, enum machine_mode mem_mode)
{
enum rtx_code code = GET_CODE (x);
struct elim_table *ep;
eliminable. */
static void
-check_eliminable_occurrences (x)
- rtx x;
+check_eliminable_occurrences (rtx x)
{
const char *fmt;
int i;
is returned. Otherwise, 1 is returned. */
static int
-eliminate_regs_in_insn (insn, replace)
- rtx insn;
- int replace;
+eliminate_regs_in_insn (rtx insn, int replace)
{
int icode = recog_memoized (insn);
rtx old_body = PATTERN (insn);
{
rtx base = SET_SRC (old_set);
rtx base_insn = insn;
- int offset = 0;
+ HOST_WIDE_INT offset = 0;
while (base != ep->to_rtx)
{
&& REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
{
rtx reg = XEXP (SET_SRC (old_set), 0);
- int offset = INTVAL (XEXP (SET_SRC (old_set), 1));
+ HOST_WIDE_INT offset = INTVAL (XEXP (SET_SRC (old_set), 1));
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->from_rtx == reg && ep->can_eliminate)
grow downward) for each elimination pair. */
static void
-update_eliminable_offsets ()
+update_eliminable_offsets (void)
{
struct elim_table *ep;
the insns of the function. */
static void
-mark_not_eliminable (dest, x, data)
- rtx dest;
- rtx x;
- void *data ATTRIBUTE_UNUSED;
+mark_not_eliminable (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
{
unsigned int i;
cause incorrect code to be generated if we did not check for it. */
static void
-verify_initial_elim_offsets ()
+verify_initial_elim_offsets (void)
{
- int t;
+ HOST_WIDE_INT t;
#ifdef ELIMINABLE_REGS
struct elim_table *ep;
/* Reset all offsets on eliminable registers to their initial values. */
static void
-set_initial_elim_offsets ()
+set_initial_elim_offsets (void)
{
struct elim_table *ep = reg_eliminate;
For all other labels, show that we don't know the offsets. */
static void
-set_initial_label_offsets ()
+set_initial_label_offsets (void)
{
rtx x;
memset (offsets_known_at, 0, num_labels);
by INSN. */
static void
-set_offsets_for_label (insn)
- rtx insn;
+set_offsets_for_label (rtx insn)
{
unsigned int i;
int label_nr = CODE_LABEL_NUMBER (insn);
since they can't have changed. */
static void
-update_eliminables (pset)
- HARD_REG_SET *pset;
+update_eliminables (HARD_REG_SET *pset)
{
int previous_frame_pointer_needed = frame_pointer_needed;
struct elim_table *ep;
/* Initialize the table of registers to eliminate. */
static void
-init_elim_table ()
+init_elim_table (void)
{
struct elim_table *ep;
#ifdef ELIMINABLE_REGS
#endif
if (!reg_eliminate)
- reg_eliminate = (struct elim_table *)
- xcalloc (sizeof (struct elim_table), NUM_ELIMINABLE_REGS);
+ reg_eliminate = xcalloc (sizeof (struct elim_table), NUM_ELIMINABLE_REGS);
/* Does this function require a frame pointer? */
Return nonzero if any pseudos needed to be kicked out. */
static void
-spill_hard_reg (regno, cant_eliminate)
- unsigned int regno;
- int cant_eliminate;
+spill_hard_reg (unsigned int regno, int cant_eliminate)
{
int i;
from within EXECUTE_IF_SET_IN_REG_SET. Hence this awkwardness. */
static void
-ior_hard_reg_set (set1, set2)
- HARD_REG_SET *set1, *set2;
+ior_hard_reg_set (HARD_REG_SET *set1, HARD_REG_SET *set2)
{
IOR_HARD_REG_SET (*set1, *set2);
}
spill_regs array for use by choose_reload_regs. */
static int
-finish_spills (global)
- int global;
+finish_spills (int global)
{
struct insn_chain *chain;
int something_changed = 0;
/* Retry global register allocation if possible. */
if (global)
{
- memset ((char *) pseudo_forbidden_regs, 0, max_regno * sizeof (HARD_REG_SET));
+ memset (pseudo_forbidden_regs, 0, max_regno * sizeof (HARD_REG_SET));
/* For every insn that needs reloads, set the registers used as spill
regs in pseudo_forbidden_regs for every pseudo live across the
insn. */
forbidden from being used for spill registers. */
static void
-scan_paradoxical_subregs (x)
- rtx x;
+scan_paradoxical_subregs (rtx x)
{
int i;
const char *fmt;
as the insns are scanned. */
static void
-reload_as_needed (live_known)
- int live_known;
+reload_as_needed (int live_known)
{
struct insn_chain *chain;
#if defined (AUTO_INC_DEC)
#endif
rtx x;
- memset ((char *) spill_reg_rtx, 0, sizeof spill_reg_rtx);
- memset ((char *) spill_reg_store, 0, sizeof spill_reg_store);
- reg_last_reload_reg = (rtx *) xcalloc (max_regno, sizeof (rtx));
- reg_has_output_reload = (char *) xmalloc (max_regno);
+ memset (spill_reg_rtx, 0, sizeof spill_reg_rtx);
+ memset (spill_reg_store, 0, sizeof spill_reg_store);
+ reg_last_reload_reg = xcalloc (max_regno, sizeof (rtx));
+ reg_has_output_reload = xmalloc (max_regno);
CLEAR_HARD_REG_SET (reg_reloaded_valid);
set_initial_elim_offsets ();
or it may be a pseudo reg that was reloaded from. */
static void
-forget_old_reloads_1 (x, ignored, data)
- rtx x;
- rtx ignored ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
+forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
{
unsigned int regno;
unsigned int nr;
actually used. */
static void
-mark_reload_reg_in_use (regno, opnum, type, mode)
- unsigned int regno;
- int opnum;
- enum reload_type type;
- enum machine_mode mode;
+mark_reload_reg_in_use (unsigned int regno, int opnum, enum reload_type type,
+ enum machine_mode mode)
{
unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
unsigned int i;
/* Similarly, but show REGNO is no longer in use for a reload. */
static void
-clear_reload_reg_in_use (regno, opnum, type, mode)
- unsigned int regno;
- int opnum;
- enum reload_type type;
- enum machine_mode mode;
+clear_reload_reg_in_use (unsigned int regno, int opnum,
+ enum reload_type type, enum machine_mode mode)
{
unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
unsigned int start_regno, end_regno, r;
specified by OPNUM and TYPE. */
static int
-reload_reg_free_p (regno, opnum, type)
- unsigned int regno;
- int opnum;
- enum reload_type type;
+reload_reg_free_p (unsigned int regno, int opnum, enum reload_type type)
{
int i;
in case the reg has already been marked in use. */
static int
-reload_reg_reaches_end_p (regno, opnum, type)
- unsigned int regno;
- int opnum;
- enum reload_type type;
+reload_reg_reaches_end_p (unsigned int regno, int opnum, enum reload_type type)
{
int i;
This function uses the same algorithm as reload_reg_free_p above. */
int
-reloads_conflict (r1, r2)
- int r1, r2;
+reloads_conflict (int r1, int r2)
{
enum reload_type r1_type = rld[r1].when_needed;
enum reload_type r2_type = rld[r2].when_needed;
(possibly comprising multiple hard registers) that we are considering. */
static int
-reload_reg_free_for_value_p (start_regno, regno, opnum, type, value, out,
- reloadnum, ignore_address_reloads)
- int start_regno, regno;
- int opnum;
- enum reload_type type;
- rtx value, out;
- int reloadnum;
- int ignore_address_reloads;
+reload_reg_free_for_value_p (int start_regno, int regno, int opnum,
+ enum reload_type type, rtx value, rtx out,
+ int reloadnum, int ignore_address_reloads)
{
int time1;
/* Set if we see an input reload that must not share its reload register
register. */
static int
-free_for_value_p (regno, mode, opnum, type, value, out, reloadnum,
- ignore_address_reloads)
- int regno;
- enum machine_mode mode;
- int opnum;
- enum reload_type type;
- rtx value, out;
- int reloadnum;
- int ignore_address_reloads;
+free_for_value_p (int regno, enum machine_mode mode, int opnum,
+ enum reload_type type, rtx value, rtx out, int reloadnum,
+ int ignore_address_reloads)
{
int nregs = HARD_REGNO_NREGS (regno, mode);
while (nregs-- > 0)
overriding inheritance. Return nonzero if so. */
static int
-conflicts_with_override (x)
- rtx x;
+conflicts_with_override (rtx x)
{
int i;
for (i = 0; i < n_reloads; i++)
/* Give an error message saying we failed to find a reload for INSN,
and clear out reload R. */
static void
-failed_reload (insn, r)
- rtx insn;
- int r;
+failed_reload (rtx insn, int r)
{
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
for reload R. If it's valid, get an rtx for it. Return nonzero if
successful. */
static int
-set_reload_reg (i, r)
- int i, r;
+set_reload_reg (int i, int r)
{
int regno;
rtx reg = spill_reg_rtx[i];
we didn't change anything. */
static int
-allocate_reload_reg (chain, r, last_reload)
- struct insn_chain *chain ATTRIBUTE_UNUSED;
- int r;
- int last_reload;
+allocate_reload_reg (struct insn_chain *chain ATTRIBUTE_UNUSED, int r,
+ int last_reload)
{
int i, pass, count;
is the array we use to restore the reg_rtx field for every reload. */
static void
-choose_reload_regs_init (chain, save_reload_reg_rtx)
- struct insn_chain *chain;
- rtx *save_reload_reg_rtx;
+choose_reload_regs_init (struct insn_chain *chain, rtx *save_reload_reg_rtx)
{
int i;
rld[i].reg_rtx = save_reload_reg_rtx[i];
memset (reload_inherited, 0, MAX_RELOADS);
- memset ((char *) reload_inheritance_insn, 0, MAX_RELOADS * sizeof (rtx));
- memset ((char *) reload_override_in, 0, MAX_RELOADS * sizeof (rtx));
+ memset (reload_inheritance_insn, 0, MAX_RELOADS * sizeof (rtx));
+ memset (reload_override_in, 0, MAX_RELOADS * sizeof (rtx));
CLEAR_HARD_REG_SET (reload_reg_used);
CLEAR_HARD_REG_SET (reload_reg_used_at_all);
finding a reload reg in the proper class. */
static void
-choose_reload_regs (chain)
- struct insn_chain *chain;
+choose_reload_regs (struct insn_chain *chain)
{
rtx insn = chain->insn;
int i, j;
/* If we found a spill reg, reject it unless it is free
and of the desired class. */
- if (equiv != 0
- && ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
+ if (equiv != 0)
+ {
+ int regs_used = 0;
+ int bad_for_class = 0;
+ int max_regno = regno + rld[r].nregs;
+
+ for (i = regno; i < max_regno; i++)
+ {
+ regs_used |= TEST_HARD_REG_BIT (reload_reg_used_at_all,
+ i);
+ bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
+ i);
+ }
+
+ if ((regs_used
&& ! free_for_value_p (regno, rld[r].mode,
rld[r].opnum, rld[r].when_needed,
rld[r].in, rld[r].out, r, 1))
- || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
- regno)))
- equiv = 0;
+ || bad_for_class)
+ equiv = 0;
+ }
if (equiv != 0 && ! HARD_REGNO_MODE_OK (regno, rld[r].mode))
equiv = 0;
remove_address_replacements. */
void
-deallocate_reload_reg (r)
- int r;
+deallocate_reload_reg (int r)
{
int regno;
prevent redundant code. */
static void
-merge_assigned_reloads (insn)
- rtx insn;
+merge_assigned_reloads (rtx insn)
{
int i, j;
? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
/* Check to see if we accidentally converted two reloads
- that use the same reload register to the same type.
- If so, the resulting code won't work, so abort. */
+ that use the same reload register with different inputs
+ to the same type. If so, the resulting code won't work,
+ so abort. */
if (rld[j].reg_rtx)
for (k = 0; k < j; k++)
if (rld[k].in != 0 && rld[k].reg_rtx != 0
&& rld[k].when_needed == rld[j].when_needed
- && rtx_equal_p (rld[k].reg_rtx, rld[j].reg_rtx))
+ && rtx_equal_p (rld[k].reg_rtx, rld[j].reg_rtx)
+ && ! rtx_equal_p (rld[k].in, rld[j].in))
abort ();
}
}
has the number J. OLD contains the value to be used as input. */
static void
-emit_input_reload_insns (chain, rl, old, j)
- struct insn_chain *chain;
- struct reload *rl;
- rtx old;
- int j;
+emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
+ rtx old, int j)
{
rtx insn = chain->insn;
rtx reloadreg = rl->reg_rtx;
/* Generate insns to for the output reload RL, which is for the insn described
by CHAIN and has the number J. */
static void
-emit_output_reload_insns (chain, rl, j)
- struct insn_chain *chain;
- struct reload *rl;
- int j;
+emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
+ int j)
{
rtx reloadreg = rl->reg_rtx;
rtx insn = chain->insn;
/* Do input reloading for reload RL, which is for the insn described by CHAIN
and has the number J. */
static void
-do_input_reload (chain, rl, j)
- struct insn_chain *chain;
- struct reload *rl;
- int j;
+do_input_reload (struct insn_chain *chain, struct reload *rl, int j)
{
rtx insn = chain->insn;
rtx old = (rl->in && GET_CODE (rl->in) == MEM
??? At some point we need to support handling output reloads of
JUMP_INSNs or insns that set cc0. */
static void
-do_output_reload (chain, rl, j)
- struct insn_chain *chain;
- struct reload *rl;
- int j;
+do_output_reload (struct insn_chain *chain, struct reload *rl, int j)
{
rtx note, old;
rtx insn = chain->insn;
/* Output insns to reload values in and out of the chosen reload regs. */
static void
-emit_reload_insns (chain)
- struct insn_chain *chain;
+emit_reload_insns (struct insn_chain *chain)
{
rtx insn = chain->insn;
Returns first insn emitted. */
rtx
-gen_reload (out, in, opnum, type)
- rtx out;
- rtx in;
- int opnum;
- enum reload_type type;
+gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
{
rtx last = get_last_insn ();
rtx tem;
certain that reload J doesn't use REG any longer for input. */
static void
-delete_output_reload (insn, j, last_reload_reg)
- rtx insn;
- int j;
- int last_reload_reg;
+delete_output_reload (rtx insn, int j, int last_reload_reg)
{
rtx output_reload_insn = spill_reg_store[last_reload_reg];
rtx reg = spill_reg_stored_to[last_reload_reg];
reload registers used in DEAD_INSN that are not used till CURRENT_INSN.
CURRENT_INSN is being reloaded, so we have to check its reloads too. */
static void
-delete_address_reloads (dead_insn, current_insn)
- rtx dead_insn, current_insn;
+delete_address_reloads (rtx dead_insn, rtx current_insn)
{
rtx set = single_set (dead_insn);
rtx set2, dst, prev, next;
/* Subfunction of delete_address_reloads: process registers found in X. */
static void
-delete_address_reloads_1 (dead_insn, x, current_insn)
- rtx dead_insn, x, current_insn;
+delete_address_reloads_1 (rtx dead_insn, rtx x, rtx current_insn)
{
rtx prev, set, dst, i2;
int i, j;
Return the instruction that stores into RELOADREG. */
static rtx
-inc_for_reload (reloadreg, in, value, inc_amount)
- rtx reloadreg;
- rtx in, value;
- int inc_amount;
+inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
{
/* REG or MEM to be copied and incremented. */
rtx incloc = XEXP (value, 0);
return store;
}
\f
-
-/* See whether a single set SET is a noop. */
-static int
-reload_cse_noop_set_p (set)
- rtx set;
-{
- if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
- return 0;
-
- return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
-}
-
-/* Try to simplify INSN. */
-static void
-reload_cse_simplify (insn, testreg)
- rtx insn;
- rtx testreg;
-{
- rtx body = PATTERN (insn);
-
- if (GET_CODE (body) == SET)
- {
- int count = 0;
-
- /* Simplify even if we may think it is a no-op.
- We may think a memory load of a value smaller than WORD_SIZE
- is redundant because we haven't taken into account possible
- implicit extension. reload_cse_simplify_set() will bring
- this out, so it's safer to simplify before we delete. */
- count += reload_cse_simplify_set (body, insn);
-
- if (!count && reload_cse_noop_set_p (body))
- {
- rtx value = SET_DEST (body);
- if (REG_P (value)
- && ! REG_FUNCTION_VALUE_P (value))
- value = 0;
- delete_insn_and_edges (insn);
- return;
- }
-
- if (count > 0)
- apply_change_group ();
- else
- reload_cse_simplify_operands (insn, testreg);
- }
- else if (GET_CODE (body) == PARALLEL)
- {
- int i;
- int count = 0;
- rtx value = NULL_RTX;
-
- /* If every action in a PARALLEL is a noop, we can delete
- the entire PARALLEL. */
- for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
- {
- rtx part = XVECEXP (body, 0, i);
- if (GET_CODE (part) == SET)
- {
- if (! reload_cse_noop_set_p (part))
- break;
- if (REG_P (SET_DEST (part))
- && REG_FUNCTION_VALUE_P (SET_DEST (part)))
- {
- if (value)
- break;
- value = SET_DEST (part);
- }
- }
- else if (GET_CODE (part) != CLOBBER)
- break;
- }
-
- if (i < 0)
- {
- delete_insn_and_edges (insn);
- /* We're done with this insn. */
- return;
- }
-
- /* It's not a no-op, but we can try to simplify it. */
- for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
- if (GET_CODE (XVECEXP (body, 0, i)) == SET)
- count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
-
- if (count > 0)
- apply_change_group ();
- else
- reload_cse_simplify_operands (insn, testreg);
- }
-}
-
-/* Do a very simple CSE pass over the hard registers.
-
- This function detects no-op moves where we happened to assign two
- different pseudo-registers to the same hard register, and then
- copied one to the other. Reload will generate a useless
- instruction copying a register to itself.
-
- This function also detects cases where we load a value from memory
- into two different registers, and (if memory is more expensive than
- registers) changes it to simply copy the first register into the
- second register.
-
- Another optimization is performed that scans the operands of each
- instruction to see whether the value is already available in a
- hard register. It then replaces the operand with the hard register
- if possible, much like an optional reload would. */
-
-static void
-reload_cse_regs_1 (first)
- rtx first;
-{
- rtx insn;
- rtx testreg = gen_rtx_REG (VOIDmode, -1);
-
- cselib_init ();
- init_alias_analysis ();
-
- for (insn = first; insn; insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- reload_cse_simplify (insn, testreg);
-
- cselib_process_insn (insn);
- }
-
- /* Clean up. */
- end_alias_analysis ();
- cselib_finish ();
-}
-
-/* Call cse / combine like post-reload optimization phases.
- FIRST is the first instruction. */
-void
-reload_cse_regs (first)
- rtx first;
-{
- reload_cse_regs_1 (first);
- reload_combine ();
- reload_cse_move2add (first);
- if (flag_expensive_optimizations)
- reload_cse_regs_1 (first);
-}
-
-/* Try to simplify a single SET instruction. SET is the set pattern.
- INSN is the instruction it came from.
- This function only handles one case: if we set a register to a value
- which is not a register, we try to find that value in some other register
- and change the set into a register copy. */
-
-static int
-reload_cse_simplify_set (set, insn)
- rtx set;
- rtx insn;
-{
- int did_change = 0;
- int dreg;
- rtx src;
- enum reg_class dclass;
- int old_cost;
- cselib_val *val;
- struct elt_loc_list *l;
-#ifdef LOAD_EXTEND_OP
- enum rtx_code extend_op = NIL;
-#endif
-
- dreg = true_regnum (SET_DEST (set));
- if (dreg < 0)
- return 0;
-
- src = SET_SRC (set);
- if (side_effects_p (src) || true_regnum (src) >= 0)
- return 0;
-
- dclass = REGNO_REG_CLASS (dreg);
-
-#ifdef LOAD_EXTEND_OP
- /* When replacing a memory with a register, we need to honor assumptions
- that combine made wrt the contents of sign bits. We'll do this by
- generating an extend instruction instead of a reg->reg copy. Thus
- the destination must be a register that we can widen. */
- if (GET_CODE (src) == MEM
- && GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
- && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != NIL
- && GET_CODE (SET_DEST (set)) != REG)
- return 0;
-#endif
-
- /* If memory loads are cheaper than register copies, don't change them. */
- if (GET_CODE (src) == MEM)
- old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
- else if (CONSTANT_P (src))
- old_cost = rtx_cost (src, SET);
- else if (GET_CODE (src) == REG)
- old_cost = REGISTER_MOVE_COST (GET_MODE (src),
- REGNO_REG_CLASS (REGNO (src)), dclass);
- else
- /* ??? */
- old_cost = rtx_cost (src, SET);
-
- val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
- if (! val)
- return 0;
- for (l = val->locs; l; l = l->next)
- {
- rtx this_rtx = l->loc;
- int this_cost;
-
- if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
- {
-#ifdef LOAD_EXTEND_OP
- if (extend_op != NIL)
- {
- HOST_WIDE_INT this_val;
-
- /* ??? I'm lazy and don't wish to handle CONST_DOUBLE. Other
- constants, such as SYMBOL_REF, cannot be extended. */
- if (GET_CODE (this_rtx) != CONST_INT)
- continue;
-
- this_val = INTVAL (this_rtx);
- switch (extend_op)
- {
- case ZERO_EXTEND:
- this_val &= GET_MODE_MASK (GET_MODE (src));
- break;
- case SIGN_EXTEND:
- /* ??? In theory we're already extended. */
- if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
- break;
- default:
- abort ();
- }
- this_rtx = GEN_INT (this_val);
- }
-#endif
- this_cost = rtx_cost (this_rtx, SET);
- }
- else if (GET_CODE (this_rtx) == REG)
- {
-#ifdef LOAD_EXTEND_OP
- if (extend_op != NIL)
- {
- this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
- this_cost = rtx_cost (this_rtx, SET);
- }
- else
-#endif
- this_cost = REGISTER_MOVE_COST (GET_MODE (this_rtx),
- REGNO_REG_CLASS (REGNO (this_rtx)),
- dclass);
- }
- else
- continue;
-
- /* If equal costs, prefer registers over anything else. That
- tends to lead to smaller instructions on some machines. */
- if (this_cost < old_cost
- || (this_cost == old_cost
- && GET_CODE (this_rtx) == REG
- && GET_CODE (SET_SRC (set)) != REG))
- {
-#ifdef LOAD_EXTEND_OP
- if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
- && extend_op != NIL
-#ifdef CANNOT_CHANGE_MODE_CLASS
- && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
- word_mode,
- REGNO_REG_CLASS (REGNO (SET_DEST (set))))
-#endif
- )
- {
- rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
- ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
- validate_change (insn, &SET_DEST (set), wide_dest, 1);
- }
-#endif
-
- validate_change (insn, &SET_SRC (set), copy_rtx (this_rtx), 1);
- old_cost = this_cost, did_change = 1;
- }
- }
-
- return did_change;
-}
-
-/* Try to replace operands in INSN with equivalent values that are already
- in registers. This can be viewed as optional reloading.
-
- For each non-register operand in the insn, see if any hard regs are
- known to be equivalent to that operand. Record the alternatives which
- can accept these hard registers. Among all alternatives, select the
- ones which are better or equal to the one currently matching, where
- "better" is in terms of '?' and '!' constraints. Among the remaining
- alternatives, select the one which replaces most operands with
- hard registers. */
-
-static int
-reload_cse_simplify_operands (insn, testreg)
- rtx insn;
- rtx testreg;
-{
- int i, j;
-
- /* For each operand, all registers that are equivalent to it. */
- HARD_REG_SET equiv_regs[MAX_RECOG_OPERANDS];
-
- const char *constraints[MAX_RECOG_OPERANDS];
-
- /* Vector recording how bad an alternative is. */
- int *alternative_reject;
- /* Vector recording how many registers can be introduced by choosing
- this alternative. */
- int *alternative_nregs;
- /* Array of vectors recording, for each operand and each alternative,
- which hard register to substitute, or -1 if the operand should be
- left as it is. */
- int *op_alt_regno[MAX_RECOG_OPERANDS];
- /* Array of alternatives, sorted in order of decreasing desirability. */
- int *alternative_order;
-
- extract_insn (insn);
-
- if (recog_data.n_alternatives == 0 || recog_data.n_operands == 0)
- return 0;
-
- /* Figure out which alternative currently matches. */
- if (! constrain_operands (1))
- fatal_insn_not_found (insn);
-
- alternative_reject = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- alternative_nregs = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- alternative_order = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- memset ((char *) alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
- memset ((char *) alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
-
- /* For each operand, find out which regs are equivalent. */
- for (i = 0; i < recog_data.n_operands; i++)
- {
- cselib_val *v;
- struct elt_loc_list *l;
-
- CLEAR_HARD_REG_SET (equiv_regs[i]);
-
- /* cselib blows up on CODE_LABELs. Trying to fix that doesn't seem
- right, so avoid the problem here. Likewise if we have a constant
- and the insn pattern doesn't tell us the mode we need. */
- if (GET_CODE (recog_data.operand[i]) == CODE_LABEL
- || (CONSTANT_P (recog_data.operand[i])
- && recog_data.operand_mode[i] == VOIDmode))
- continue;
-
- v = cselib_lookup (recog_data.operand[i], recog_data.operand_mode[i], 0);
- if (! v)
- continue;
-
- for (l = v->locs; l; l = l->next)
- if (GET_CODE (l->loc) == REG)
- SET_HARD_REG_BIT (equiv_regs[i], REGNO (l->loc));
- }
-
- for (i = 0; i < recog_data.n_operands; i++)
- {
- enum machine_mode mode;
- int regno;
- const char *p;
-
- op_alt_regno[i] = (int *) alloca (recog_data.n_alternatives * sizeof (int));
- for (j = 0; j < recog_data.n_alternatives; j++)
- op_alt_regno[i][j] = -1;
-
- p = constraints[i] = recog_data.constraints[i];
- mode = recog_data.operand_mode[i];
-
- /* Add the reject values for each alternative given by the constraints
- for this operand. */
- j = 0;
- while (*p != '\0')
- {
- char c = *p++;
- if (c == ',')
- j++;
- else if (c == '?')
- alternative_reject[j] += 3;
- else if (c == '!')
- alternative_reject[j] += 300;
- }
-
- /* We won't change operands which are already registers. We
- also don't want to modify output operands. */
- regno = true_regnum (recog_data.operand[i]);
- if (regno >= 0
- || constraints[i][0] == '='
- || constraints[i][0] == '+')
- continue;
-
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- {
- int class = (int) NO_REGS;
-
- if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
- continue;
-
- REGNO (testreg) = regno;
- PUT_MODE (testreg, mode);
-
- /* We found a register equal to this operand. Now look for all
- alternatives that can accept this register and have not been
- assigned a register they can use yet. */
- j = 0;
- p = constraints[i];
- for (;;)
- {
- char c = *p;
-
- switch (c)
- {
- case '=': case '+': case '?':
- case '#': case '&': case '!':
- case '*': case '%':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'm': case '<': case '>': case 'V': case 'o':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P':
- case 'p': case 'X':
- /* These don't say anything we care about. */
- break;
-
- case 'g': case 'r':
- class = reg_class_subunion[(int) class][(int) GENERAL_REGS];
- break;
-
- default:
- class
- = (reg_class_subunion
- [(int) class]
- [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
- break;
-
- case ',': case '\0':
- /* See if REGNO fits this alternative, and set it up as the
- replacement register if we don't have one for this
- alternative yet and the operand being replaced is not
- a cheap CONST_INT. */
- if (op_alt_regno[i][j] == -1
- && reg_fits_class_p (testreg, class, 0, mode)
- && (GET_CODE (recog_data.operand[i]) != CONST_INT
- || (rtx_cost (recog_data.operand[i], SET)
- > rtx_cost (testreg, SET))))
- {
- alternative_nregs[j]++;
- op_alt_regno[i][j] = regno;
- }
- j++;
- break;
- }
- p += CONSTRAINT_LEN (c, p);
-
- if (c == '\0')
- break;
- }
- }
- }
-
- /* Record all alternatives which are better or equal to the currently
- matching one in the alternative_order array. */
- for (i = j = 0; i < recog_data.n_alternatives; i++)
- if (alternative_reject[i] <= alternative_reject[which_alternative])
- alternative_order[j++] = i;
- recog_data.n_alternatives = j;
-
- /* Sort it. Given a small number of alternatives, a dumb algorithm
- won't hurt too much. */
- for (i = 0; i < recog_data.n_alternatives - 1; i++)
- {
- int best = i;
- int best_reject = alternative_reject[alternative_order[i]];
- int best_nregs = alternative_nregs[alternative_order[i]];
- int tmp;
-
- for (j = i + 1; j < recog_data.n_alternatives; j++)
- {
- int this_reject = alternative_reject[alternative_order[j]];
- int this_nregs = alternative_nregs[alternative_order[j]];
-
- if (this_reject < best_reject
- || (this_reject == best_reject && this_nregs < best_nregs))
- {
- best = j;
- best_reject = this_reject;
- best_nregs = this_nregs;
- }
- }
-
- tmp = alternative_order[best];
- alternative_order[best] = alternative_order[i];
- alternative_order[i] = tmp;
- }
-
- /* Substitute the operands as determined by op_alt_regno for the best
- alternative. */
- j = alternative_order[0];
-
- for (i = 0; i < recog_data.n_operands; i++)
- {
- enum machine_mode mode = recog_data.operand_mode[i];
- if (op_alt_regno[i][j] == -1)
- continue;
-
- validate_change (insn, recog_data.operand_loc[i],
- gen_rtx_REG (mode, op_alt_regno[i][j]), 1);
- }
-
- for (i = recog_data.n_dups - 1; i >= 0; i--)
- {
- int op = recog_data.dup_num[i];
- enum machine_mode mode = recog_data.operand_mode[op];
-
- if (op_alt_regno[op][j] == -1)
- continue;
-
- validate_change (insn, recog_data.dup_loc[i],
- gen_rtx_REG (mode, op_alt_regno[op][j]), 1);
- }
-
- return apply_change_group ();
-}
-\f
-/* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
- addressing now.
- This code might also be useful when reload gave up on reg+reg addressing
- because of clashes between the return register and INDEX_REG_CLASS. */
-
-/* The maximum number of uses of a register we can keep track of to
- replace them with reg+reg addressing. */
-#define RELOAD_COMBINE_MAX_USES 6
-
-/* INSN is the insn where a register has ben used, and USEP points to the
- location of the register within the rtl. */
-struct reg_use { rtx insn, *usep; };
-
-/* If the register is used in some unknown fashion, USE_INDEX is negative.
- If it is dead, USE_INDEX is RELOAD_COMBINE_MAX_USES, and STORE_RUID
- indicates where it becomes live again.
- Otherwise, USE_INDEX is the index of the last encountered use of the
- register (which is first among these we have seen since we scan backwards),
- OFFSET contains the constant offset that is added to the register in
- all encountered uses, and USE_RUID indicates the first encountered, i.e.
- last, of these uses.
- STORE_RUID is always meaningful if we only want to use a value in a
- register in a different place: it denotes the next insn in the insn
- stream (i.e. the last encountered) that sets or clobbers the register. */
-static struct
- {
- struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
- int use_index;
- rtx offset;
- int store_ruid;
- int use_ruid;
- } reg_state[FIRST_PSEUDO_REGISTER];
-
-/* Reverse linear uid. This is increased in reload_combine while scanning
- the instructions from last to first. It is used to set last_label_ruid
- and the store_ruid / use_ruid fields in reg_state. */
-static int reload_combine_ruid;
-
-#define LABEL_LIVE(LABEL) \
- (label_live[CODE_LABEL_NUMBER (LABEL) - min_labelno])
-
-static void
-reload_combine ()
-{
- rtx insn, set;
- int first_index_reg = -1;
- int last_index_reg = 0;
- int i;
- basic_block bb;
- unsigned int r;
- int last_label_ruid;
- int min_labelno, n_labels;
- HARD_REG_SET ever_live_at_start, *label_live;
-
- /* If reg+reg can be used in offsetable memory addresses, the main chunk of
- reload has already used it where appropriate, so there is no use in
- trying to generate it now. */
- if (double_reg_address_ok && INDEX_REG_CLASS != NO_REGS)
- return;
-
- /* To avoid wasting too much time later searching for an index register,
- determine the minimum and maximum index register numbers. */
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
- {
- if (first_index_reg == -1)
- first_index_reg = r;
-
- last_index_reg = r;
- }
-
- /* If no index register is available, we can quit now. */
- if (first_index_reg == -1)
- return;
-
- /* Set up LABEL_LIVE and EVER_LIVE_AT_START. The register lifetime
- information is a bit fuzzy immediately after reload, but it's
- still good enough to determine which registers are live at a jump
- destination. */
- min_labelno = get_first_label_num ();
- n_labels = max_label_num () - min_labelno;
- label_live = (HARD_REG_SET *) xmalloc (n_labels * sizeof (HARD_REG_SET));
- CLEAR_HARD_REG_SET (ever_live_at_start);
-
- FOR_EACH_BB_REVERSE (bb)
- {
- insn = bb->head;
- if (GET_CODE (insn) == CODE_LABEL)
- {
- HARD_REG_SET live;
-
- REG_SET_TO_HARD_REG_SET (live,
- bb->global_live_at_start);
- compute_use_by_pseudos (&live,
- bb->global_live_at_start);
- COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
- IOR_HARD_REG_SET (ever_live_at_start, live);
- }
- }
-
- /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */
- last_label_ruid = reload_combine_ruid = 0;
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- {
- reg_state[r].store_ruid = reload_combine_ruid;
- if (fixed_regs[r])
- reg_state[r].use_index = -1;
- else
- reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
- }
-
- for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
- {
- rtx note;
-
- /* We cannot do our optimization across labels. Invalidating all the use
- information we have would be costly, so we just note where the label
- is and then later disable any optimization that would cross it. */
- if (GET_CODE (insn) == CODE_LABEL)
- last_label_ruid = reload_combine_ruid;
- else if (GET_CODE (insn) == BARRIER)
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (! fixed_regs[r])
- reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
-
- if (! INSN_P (insn))
- continue;
-
- reload_combine_ruid++;
-
- /* Look for (set (REGX) (CONST_INT))
- (set (REGX) (PLUS (REGX) (REGY)))
- ...
- ... (MEM (REGX)) ...
- and convert it to
- (set (REGZ) (CONST_INT))
- ...
- ... (MEM (PLUS (REGZ) (REGY)))... .
-
- First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
- and that we know all uses of REGX before it dies. */
- set = single_set (insn);
- if (set != NULL_RTX
- && GET_CODE (SET_DEST (set)) == REG
- && (HARD_REGNO_NREGS (REGNO (SET_DEST (set)),
- GET_MODE (SET_DEST (set)))
- == 1)
- && GET_CODE (SET_SRC (set)) == PLUS
- && GET_CODE (XEXP (SET_SRC (set), 1)) == REG
- && rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
- && last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
- {
- rtx reg = SET_DEST (set);
- rtx plus = SET_SRC (set);
- rtx base = XEXP (plus, 1);
- rtx prev = prev_nonnote_insn (insn);
- rtx prev_set = prev ? single_set (prev) : NULL_RTX;
- unsigned int regno = REGNO (reg);
- rtx const_reg = NULL_RTX;
- rtx reg_sum = NULL_RTX;
-
- /* Now, we need an index register.
- We'll set index_reg to this index register, const_reg to the
- register that is to be loaded with the constant
- (denoted as REGZ in the substitution illustration above),
- and reg_sum to the register-register that we want to use to
- substitute uses of REG (typically in MEMs) with.
- First check REG and BASE for being index registers;
- we can use them even if they are not dead. */
- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
- || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
- REGNO (base)))
- {
- const_reg = reg;
- reg_sum = plus;
- }
- else
- {
- /* Otherwise, look for a free index register. Since we have
- checked above that neiter REG nor BASE are index registers,
- if we find anything at all, it will be different from these
- two registers. */
- for (i = first_index_reg; i <= last_index_reg; i++)
- {
- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
- i)
- && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
- && reg_state[i].store_ruid <= reg_state[regno].use_ruid
- && HARD_REGNO_NREGS (i, GET_MODE (reg)) == 1)
- {
- rtx index_reg = gen_rtx_REG (GET_MODE (reg), i);
-
- const_reg = index_reg;
- reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
- break;
- }
- }
- }
-
- /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
- (REGY), i.e. BASE, is not clobbered before the last use we'll
- create. */
- if (prev_set != 0
- && GET_CODE (SET_SRC (prev_set)) == CONST_INT
- && rtx_equal_p (SET_DEST (prev_set), reg)
- && reg_state[regno].use_index >= 0
- && (reg_state[REGNO (base)].store_ruid
- <= reg_state[regno].use_ruid)
- && reg_sum != 0)
- {
- int i;
-
- /* Change destination register and, if necessary, the
- constant value in PREV, the constant loading instruction. */
- validate_change (prev, &SET_DEST (prev_set), const_reg, 1);
- if (reg_state[regno].offset != const0_rtx)
- validate_change (prev,
- &SET_SRC (prev_set),
- GEN_INT (INTVAL (SET_SRC (prev_set))
- + INTVAL (reg_state[regno].offset)),
- 1);
-
- /* Now for every use of REG that we have recorded, replace REG
- with REG_SUM. */
- for (i = reg_state[regno].use_index;
- i < RELOAD_COMBINE_MAX_USES; i++)
- validate_change (reg_state[regno].reg_use[i].insn,
- reg_state[regno].reg_use[i].usep,
- /* Each change must have its own
- replacement. */
- copy_rtx (reg_sum), 1);
-
- if (apply_change_group ())
- {
- rtx *np;
-
- /* Delete the reg-reg addition. */
- delete_insn (insn);
-
- if (reg_state[regno].offset != const0_rtx)
- /* Previous REG_EQUIV / REG_EQUAL notes for PREV
- are now invalid. */
- for (np = ®_NOTES (prev); *np;)
- {
- if (REG_NOTE_KIND (*np) == REG_EQUAL
- || REG_NOTE_KIND (*np) == REG_EQUIV)
- *np = XEXP (*np, 1);
- else
- np = &XEXP (*np, 1);
- }
-
- reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
- reg_state[REGNO (const_reg)].store_ruid
- = reload_combine_ruid;
- continue;
- }
- }
- }
-
- note_stores (PATTERN (insn), reload_combine_note_store, NULL);
-
- if (GET_CODE (insn) == CALL_INSN)
- {
- rtx link;
-
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (call_used_regs[r])
- {
- reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
- reg_state[r].store_ruid = reload_combine_ruid;
- }
-
- for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
- link = XEXP (link, 1))
- {
- rtx usage_rtx = XEXP (XEXP (link, 0), 0);
- if (GET_CODE (usage_rtx) == REG)
- {
- unsigned int i;
- unsigned int start_reg = REGNO (usage_rtx);
- unsigned int num_regs =
- HARD_REGNO_NREGS (start_reg, GET_MODE (usage_rtx));
- unsigned int end_reg = start_reg + num_regs - 1;
- for (i = start_reg; i <= end_reg; i++)
- if (GET_CODE (XEXP (link, 0)) == CLOBBER)
- {
- reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
- reg_state[i].store_ruid = reload_combine_ruid;
- }
- else
- reg_state[i].use_index = -1;
- }
- }
-
- }
- else if (GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) != RETURN)
- {
- /* Non-spill registers might be used at the call destination in
- some unknown fashion, so we have to mark the unknown use. */
- HARD_REG_SET *live;
-
- if ((condjump_p (insn) || condjump_in_parallel_p (insn))
- && JUMP_LABEL (insn))
- live = &LABEL_LIVE (JUMP_LABEL (insn));
- else
- live = &ever_live_at_start;
-
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
- if (TEST_HARD_REG_BIT (*live, i))
- reg_state[i].use_index = -1;
- }
-
- reload_combine_note_use (&PATTERN (insn), insn);
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- {
- if (REG_NOTE_KIND (note) == REG_INC
- && GET_CODE (XEXP (note, 0)) == REG)
- {
- int regno = REGNO (XEXP (note, 0));
-
- reg_state[regno].store_ruid = reload_combine_ruid;
- reg_state[regno].use_index = -1;
- }
- }
- }
-
- free (label_live);
-}
-
-/* Check if DST is a register or a subreg of a register; if it is,
- update reg_state[regno].store_ruid and reg_state[regno].use_index
- accordingly. Called via note_stores from reload_combine. */
-
-static void
-reload_combine_note_store (dst, set, data)
- rtx dst, set;
- void *data ATTRIBUTE_UNUSED;
-{
- int regno = 0;
- int i;
- enum machine_mode mode = GET_MODE (dst);
-
- if (GET_CODE (dst) == SUBREG)
- {
- regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
- GET_MODE (SUBREG_REG (dst)),
- SUBREG_BYTE (dst),
- GET_MODE (dst));
- dst = SUBREG_REG (dst);
- }
- if (GET_CODE (dst) != REG)
- return;
- regno += REGNO (dst);
-
- /* note_stores might have stripped a STRICT_LOW_PART, so we have to be
- careful with registers / register parts that are not full words.
-
- Similarly for ZERO_EXTRACT and SIGN_EXTRACT. */
- if (GET_CODE (set) != SET
- || GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
- || GET_CODE (SET_DEST (set)) == SIGN_EXTRACT
- || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
- {
- for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
- {
- reg_state[i].use_index = -1;
- reg_state[i].store_ruid = reload_combine_ruid;
- }
- }
- else
- {
- for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
- {
- reg_state[i].store_ruid = reload_combine_ruid;
- reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
- }
- }
-}
-
-/* XP points to a piece of rtl that has to be checked for any uses of
- registers.
- *XP is the pattern of INSN, or a part of it.
- Called from reload_combine, and recursively by itself. */
-static void
-reload_combine_note_use (xp, insn)
- rtx *xp, insn;
-{
- rtx x = *xp;
- enum rtx_code code = x->code;
- const char *fmt;
- int i, j;
- rtx offset = const0_rtx; /* For the REG case below. */
-
- switch (code)
- {
- case SET:
- if (GET_CODE (SET_DEST (x)) == REG)
- {
- reload_combine_note_use (&SET_SRC (x), insn);
- return;
- }
- break;
-
- case USE:
- /* If this is the USE of a return value, we can't change it. */
- if (GET_CODE (XEXP (x, 0)) == REG && REG_FUNCTION_VALUE_P (XEXP (x, 0)))
- {
- /* Mark the return register as used in an unknown fashion. */
- rtx reg = XEXP (x, 0);
- int regno = REGNO (reg);
- int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-
- while (--nregs >= 0)
- reg_state[regno + nregs].use_index = -1;
- return;
- }
- break;
-
- case CLOBBER:
- if (GET_CODE (SET_DEST (x)) == REG)
- {
- /* No spurious CLOBBERs of pseudo registers may remain. */
- if (REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER)
- abort ();
- return;
- }
- break;
-
- case PLUS:
- /* We are interested in (plus (reg) (const_int)) . */
- if (GET_CODE (XEXP (x, 0)) != REG
- || GET_CODE (XEXP (x, 1)) != CONST_INT)
- break;
- offset = XEXP (x, 1);
- x = XEXP (x, 0);
- /* Fall through. */
- case REG:
- {
- int regno = REGNO (x);
- int use_index;
- int nregs;
-
- /* No spurious USEs of pseudo registers may remain. */
- if (regno >= FIRST_PSEUDO_REGISTER)
- abort ();
-
- nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
-
- /* We can't substitute into multi-hard-reg uses. */
- if (nregs > 1)
- {
- while (--nregs >= 0)
- reg_state[regno + nregs].use_index = -1;
- return;
- }
-
- /* If this register is already used in some unknown fashion, we
- can't do anything.
- If we decrement the index from zero to -1, we can't store more
- uses, so this register becomes used in an unknown fashion. */
- use_index = --reg_state[regno].use_index;
- if (use_index < 0)
- return;
-
- if (use_index != RELOAD_COMBINE_MAX_USES - 1)
- {
- /* We have found another use for a register that is already
- used later. Check if the offsets match; if not, mark the
- register as used in an unknown fashion. */
- if (! rtx_equal_p (offset, reg_state[regno].offset))
- {
- reg_state[regno].use_index = -1;
- return;
- }
- }
- else
- {
- /* This is the first use of this register we have seen since we
- marked it as dead. */
- reg_state[regno].offset = offset;
- reg_state[regno].use_ruid = reload_combine_ruid;
- }
- reg_state[regno].reg_use[use_index].insn = insn;
- reg_state[regno].reg_use[use_index].usep = xp;
- return;
- }
-
- default:
- break;
- }
-
- /* Recursively process the components of X. */
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- reload_combine_note_use (&XEXP (x, i), insn);
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- reload_combine_note_use (&XVECEXP (x, i, j), insn);
- }
- }
-}
-\f
-/* See if we can reduce the cost of a constant by replacing a move
- with an add. We track situations in which a register is set to a
- constant or to a register plus a constant. */
-/* We cannot do our optimization across labels. Invalidating all the
- information about register contents we have would be costly, so we
- use move2add_last_label_luid to note where the label is and then
- later disable any optimization that would cross it.
- reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if
- reg_set_luid[n] is greater than move2add_last_label_luid. */
-static int reg_set_luid[FIRST_PSEUDO_REGISTER];
-
-/* If reg_base_reg[n] is negative, register n has been set to
- reg_offset[n] in mode reg_mode[n] .
- If reg_base_reg[n] is non-negative, register n has been set to the
- sum of reg_offset[n] and the value of register reg_base_reg[n]
- before reg_set_luid[n], calculated in mode reg_mode[n] . */
-static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
-static int reg_base_reg[FIRST_PSEUDO_REGISTER];
-static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
-
-/* move2add_luid is linearly increased while scanning the instructions
- from first to last. It is used to set reg_set_luid in
- reload_cse_move2add and move2add_note_store. */
-static int move2add_luid;
-
-/* move2add_last_label_luid is set whenever a label is found. Labels
- invalidate all previously collected reg_offset data. */
-static int move2add_last_label_luid;
-
-/* ??? We don't know how zero / sign extension is handled, hence we
- can't go from a narrower to a wider mode. */
-#define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
- (GET_MODE_SIZE (OUTMODE) == GET_MODE_SIZE (INMODE) \
- || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
- && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
- GET_MODE_BITSIZE (INMODE))))
-
-static void
-reload_cse_move2add (first)
- rtx first;
-{
- int i;
- rtx insn;
-
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
- reg_set_luid[i] = 0;
-
- move2add_last_label_luid = 0;
- move2add_luid = 2;
- for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++)
- {
- rtx pat, note;
-
- if (GET_CODE (insn) == CODE_LABEL)
- {
- move2add_last_label_luid = move2add_luid;
- /* We're going to increment move2add_luid twice after a
- label, so that we can use move2add_last_label_luid + 1 as
- the luid for constants. */
- move2add_luid++;
- continue;
- }
- if (! INSN_P (insn))
- continue;
- pat = PATTERN (insn);
- /* For simplicity, we only perform this optimization on
- straightforward SETs. */
- if (GET_CODE (pat) == SET
- && GET_CODE (SET_DEST (pat)) == REG)
- {
- rtx reg = SET_DEST (pat);
- int regno = REGNO (reg);
- rtx src = SET_SRC (pat);
-
- /* Check if we have valid information on the contents of this
- register in the mode of REG. */
- if (reg_set_luid[regno] > move2add_last_label_luid
- && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]))
- {
- /* Try to transform (set (REGX) (CONST_INT A))
- ...
- (set (REGX) (CONST_INT B))
- to
- (set (REGX) (CONST_INT A))
- ...
- (set (REGX) (plus (REGX) (CONST_INT B-A)))
- or
- (set (REGX) (CONST_INT A))
- ...
- (set (STRICT_LOW_PART (REGX)) (CONST_INT B))
- */
-
- if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
- {
- rtx new_src =
- GEN_INT (trunc_int_for_mode (INTVAL (src)
- - reg_offset[regno],
- GET_MODE (reg)));
- /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
- use (set (reg) (reg)) instead.
- We don't delete this insn, nor do we convert it into a
- note, to avoid losing register notes or the return
- value flag. jump2 already knows how to get rid of
- no-op moves. */
- if (new_src == const0_rtx)
- validate_change (insn, &SET_SRC (pat), reg, 0);
- else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
- && have_add2_insn (reg, new_src))
- {
- rtx newpat = gen_add2_insn (reg, new_src);
- if (INSN_P (newpat) && NEXT_INSN (newpat) == NULL_RTX)
- newpat = PATTERN (newpat);
- /* If it was the first insn of a sequence or
- some other emitted insn, validate_change will
- reject it. */
- validate_change (insn, &PATTERN (insn),
- newpat, 0);
- }
- else
- {
- enum machine_mode narrow_mode;
- for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
- narrow_mode != GET_MODE (reg);
- narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
- {
- if (have_insn_for (STRICT_LOW_PART, narrow_mode)
- && ((reg_offset[regno]
- & ~GET_MODE_MASK (narrow_mode))
- == (INTVAL (src)
- & ~GET_MODE_MASK (narrow_mode))))
- {
- rtx narrow_reg = gen_rtx_REG (narrow_mode,
- REGNO (reg));
- rtx narrow_src =
- GEN_INT (trunc_int_for_mode (INTVAL (src),
- narrow_mode));
- rtx new_set =
- gen_rtx_SET (VOIDmode,
- gen_rtx_STRICT_LOW_PART (VOIDmode,
- narrow_reg),
- narrow_src);
- if (validate_change (insn, &PATTERN (insn),
- new_set, 0))
- break;
- }
- }
- }
- reg_set_luid[regno] = move2add_luid;
- reg_mode[regno] = GET_MODE (reg);
- reg_offset[regno] = INTVAL (src);
- continue;
- }
-
- /* Try to transform (set (REGX) (REGY))
- (set (REGX) (PLUS (REGX) (CONST_INT A)))
- ...
- (set (REGX) (REGY))
- (set (REGX) (PLUS (REGX) (CONST_INT B)))
- to
- (set (REGX) (REGY))
- (set (REGX) (PLUS (REGX) (CONST_INT A)))
- ...
- (set (REGX) (plus (REGX) (CONST_INT B-A))) */
- else if (GET_CODE (src) == REG
- && reg_set_luid[regno] == reg_set_luid[REGNO (src)]
- && reg_base_reg[regno] == reg_base_reg[REGNO (src)]
- && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg),
- reg_mode[REGNO (src)]))
- {
- rtx next = next_nonnote_insn (insn);
- rtx set = NULL_RTX;
- if (next)
- set = single_set (next);
- if (set
- && SET_DEST (set) == reg
- && GET_CODE (SET_SRC (set)) == PLUS
- && XEXP (SET_SRC (set), 0) == reg
- && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
- {
- rtx src3 = XEXP (SET_SRC (set), 1);
- HOST_WIDE_INT added_offset = INTVAL (src3);
- HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
- HOST_WIDE_INT regno_offset = reg_offset[regno];
- rtx new_src =
- GEN_INT (trunc_int_for_mode (added_offset
- + base_offset
- - regno_offset,
- GET_MODE (reg)));
- int success = 0;
-
- if (new_src == const0_rtx)
- /* See above why we create (set (reg) (reg)) here. */
- success
- = validate_change (next, &SET_SRC (set), reg, 0);
- else if ((rtx_cost (new_src, PLUS)
- < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
- && have_add2_insn (reg, new_src))
- {
- rtx newpat = gen_add2_insn (reg, new_src);
- if (INSN_P (newpat)
- && NEXT_INSN (newpat) == NULL_RTX)
- newpat = PATTERN (newpat);
- success
- = validate_change (next, &PATTERN (next),
- newpat, 0);
- }
- if (success)
- delete_insn (insn);
- insn = next;
- reg_mode[regno] = GET_MODE (reg);
- reg_offset[regno] =
- trunc_int_for_mode (added_offset + base_offset,
- GET_MODE (reg));
- continue;
- }
- }
- }
- }
-
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- {
- if (REG_NOTE_KIND (note) == REG_INC
- && GET_CODE (XEXP (note, 0)) == REG)
- {
- /* Reset the information about this register. */
- int regno = REGNO (XEXP (note, 0));
- if (regno < FIRST_PSEUDO_REGISTER)
- reg_set_luid[regno] = 0;
- }
- }
- note_stores (PATTERN (insn), move2add_note_store, NULL);
- /* If this is a CALL_INSN, all call used registers are stored with
- unknown values. */
- if (GET_CODE (insn) == CALL_INSN)
- {
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
- {
- if (call_used_regs[i])
- /* Reset the information about this register. */
- reg_set_luid[i] = 0;
- }
- }
- }
-}
-
-/* SET is a SET or CLOBBER that sets DST.
- Update reg_set_luid, reg_offset and reg_base_reg accordingly.
- Called from reload_cse_move2add via note_stores. */
-
-static void
-move2add_note_store (dst, set, data)
- rtx dst, set;
- void *data ATTRIBUTE_UNUSED;
-{
- unsigned int regno = 0;
- unsigned int i;
- enum machine_mode mode = GET_MODE (dst);
-
- if (GET_CODE (dst) == SUBREG)
- {
- regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
- GET_MODE (SUBREG_REG (dst)),
- SUBREG_BYTE (dst),
- GET_MODE (dst));
- dst = SUBREG_REG (dst);
- }
-
- /* Some targets do argument pushes without adding REG_INC notes. */
-
- if (GET_CODE (dst) == MEM)
- {
- dst = XEXP (dst, 0);
- if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC
- || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC)
- reg_set_luid[REGNO (XEXP (dst, 0))] = 0;
- return;
- }
- if (GET_CODE (dst) != REG)
- return;
-
- regno += REGNO (dst);
-
- if (SCALAR_INT_MODE_P (mode)
- && HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
- && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
- && GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
- && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
- {
- rtx src = SET_SRC (set);
- rtx base_reg;
- HOST_WIDE_INT offset;
- int base_regno;
- /* This may be different from mode, if SET_DEST (set) is a
- SUBREG. */
- enum machine_mode dst_mode = GET_MODE (dst);
-
- switch (GET_CODE (src))
- {
- case PLUS:
- if (GET_CODE (XEXP (src, 0)) == REG)
- {
- base_reg = XEXP (src, 0);
-
- if (GET_CODE (XEXP (src, 1)) == CONST_INT)
- offset = INTVAL (XEXP (src, 1));
- else if (GET_CODE (XEXP (src, 1)) == REG
- && (reg_set_luid[REGNO (XEXP (src, 1))]
- > move2add_last_label_luid)
- && (MODES_OK_FOR_MOVE2ADD
- (dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
- {
- if (reg_base_reg[REGNO (XEXP (src, 1))] < 0)
- offset = reg_offset[REGNO (XEXP (src, 1))];
- /* Maybe the first register is known to be a
- constant. */
- else if (reg_set_luid[REGNO (base_reg)]
- > move2add_last_label_luid
- && (MODES_OK_FOR_MOVE2ADD
- (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))
- && reg_base_reg[REGNO (base_reg)] < 0)
- {
- offset = reg_offset[REGNO (base_reg)];
- base_reg = XEXP (src, 1);
- }
- else
- goto invalidate;
- }
- else
- goto invalidate;
-
- break;
- }
-
- goto invalidate;
-
- case REG:
- base_reg = src;
- offset = 0;
- break;
-
- case CONST_INT:
- /* Start tracking the register as a constant. */
- reg_base_reg[regno] = -1;
- reg_offset[regno] = INTVAL (SET_SRC (set));
- /* We assign the same luid to all registers set to constants. */
- reg_set_luid[regno] = move2add_last_label_luid + 1;
- reg_mode[regno] = mode;
- return;
-
- default:
- invalidate:
- /* Invalidate the contents of the register. */
- reg_set_luid[regno] = 0;
- return;
- }
-
- base_regno = REGNO (base_reg);
- /* If information about the base register is not valid, set it
- up as a new base register, pretending its value is known
- starting from the current insn. */
- if (reg_set_luid[base_regno] <= move2add_last_label_luid)
- {
- reg_base_reg[base_regno] = base_regno;
- reg_offset[base_regno] = 0;
- reg_set_luid[base_regno] = move2add_luid;
- reg_mode[base_regno] = mode;
- }
- else if (! MODES_OK_FOR_MOVE2ADD (dst_mode,
- reg_mode[base_regno]))
- goto invalidate;
-
- reg_mode[regno] = mode;
-
- /* Copy base information from our base register. */
- reg_set_luid[regno] = reg_set_luid[base_regno];
- reg_base_reg[regno] = reg_base_reg[base_regno];
-
- /* Compute the sum of the offsets or constants. */
- reg_offset[regno] = trunc_int_for_mode (offset
- + reg_offset[base_regno],
- dst_mode);
- }
- else
- {
- unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
-
- for (i = regno; i < endregno; i++)
- /* Reset the information about this register. */
- reg_set_luid[i] = 0;
- }
-}
-
#ifdef AUTO_INC_DEC
static void
-add_auto_inc_notes (insn, x)
- rtx insn;
- rtx x;
+add_auto_inc_notes (rtx insn, rtx x)
{
enum rtx_code code = GET_CODE (x);
const char *fmt;
/* Copy EH notes from an insn to its reloads. */
static void
-copy_eh_notes (insn, x)
- rtx insn;
- rtx x;
+copy_eh_notes (rtx insn, rtx x)
{
rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
if (eh_note)
Similar handle instructions throwing exceptions internally. */
void
-fixup_abnormal_edges ()
+fixup_abnormal_edges (void)
{
bool inserted = false;
basic_block bb;