/* Reload pseudo regs into hard regs for insns that require hard regs.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
reload needs, spilling, assigning reload registers to use for
fixing up each insn, and generating the new insns to copy values
into the reload registers. */
-
-#ifndef LOCAL_REGNO
-#define LOCAL_REGNO(REGNO) 0
-#endif
\f
/* During reload_as_needed, element N contains a REG rtx for the hard reg
into which reg N has been reloaded (perhaps for a previous insn). */
This is only valid if reg_reloaded_contents is set and valid. */
static HARD_REG_SET reg_reloaded_dead;
+/* Indicate whether the register's current value is one that is not
+ safe to retain across a call, even for registers that are normally
+ call-saved. */
+static HARD_REG_SET reg_reloaded_call_part_clobbered;
+
/* Number of spill-regs so far; number of valid elements of spill_regs. */
static int n_spills;
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 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 void *, const void *));
-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 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 function_invariant_p (rtx);
+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 bool inherit_piecemeal_p (int, 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));
-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;
}
else
{
- nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (regno));
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
while (nregs-- > 0)
SET_HARD_REG_BIT (*to, r + nregs);
}
equivalences. */
static void
-replace_pseudos_in (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;
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. */
#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. */
if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
regs_ever_live[i] = 1;
+#ifdef NON_SAVING_SETJMP
+ /* A function that calls setjmp should save and restore all the
+ call-saved registers on a system where longjmp clobbers them. */
+ if (NON_SAVING_SETJMP && current_function_calls_setjmp)
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! call_used_regs[i])
+ regs_ever_live[i] = 1;
+ }
+#endif
+
/* Find all the pseudo registers that didn't get hard regs
but do have known equivalent constants or memory slots.
These include parameters (known equivalent to parameter slots)
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);
- /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
- Also find all paradoxical subregs and find largest such for each pseudo.
- On machines with small register classes, record hard registers that
- are used for user variables. These can never be used for spills.
- Also look for a "constant" REG_SETJMP. This means that all
- caller-saved registers must be marked live. */
+ /* Look for REG_EQUIV notes; record what each pseudo is equivalent
+ to. Also find all paradoxical subregs and find largest such for
+ each pseudo. */
num_eliminable_invariants = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
&& GET_MODE (insn) != VOIDmode)
PUT_MODE (insn, VOIDmode);
- if (GET_CODE (insn) == CALL_INSN
- && find_reg_note (insn, REG_SETJMP, NULL))
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (! call_used_regs[i])
- regs_ever_live[i] = 1;
-
if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
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.
/* Spill any hard regs that we know we can't eliminate. */
CLEAR_HARD_REG_SET (used_spill_regs);
- for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
- if (! ep->can_eliminate)
- spill_hard_reg (ep->from, 1);
+ /* There can be multiple ways to eliminate a register;
+ they should be listed adjacently.
+ Elimination for any register fails only if all possible ways fail. */
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; )
+ {
+ int from = ep->from;
+ int can_eliminate = 0;
+ do
+ {
+ can_eliminate |= ep->can_eliminate;
+ ep++;
+ }
+ while (ep < ®_eliminate[NUM_ELIMINABLE_REGS] && ep->from == from);
+ if (! can_eliminate)
+ spill_hard_reg (from, 1);
+ }
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
if (frame_pointer_needed)
{
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);
&& (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)))))
by this, so unshare everything here. */
unshare_all_rtl_again (first);
+#ifdef STACK_BOUNDARY
+ /* init_emit has set the alignment of the hard frame pointer
+ to STACK_BOUNDARY. It is very likely no longer valid if
+ the hard frame pointer was used for register allocation. */
+ if (!frame_pointer_needed)
+ REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT;
+#endif
+
return failure;
}
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 void *r1p;
- const void *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];
spill_add_cost[r] += freq;
- nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
while (nregs-- > 0)
spill_cost[r + nregs] += freq;
}
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));
+ int nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
if (REGNO_REG_SET_P (&spilled_pseudos, reg)
|| spilled + spilled_nregs <= r || r + nregs <= spilled)
/* 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;
{
int this_cost = spill_cost[regno];
int ok = 1;
- unsigned int this_nregs = HARD_REGNO_NREGS (regno, rl->mode);
+ unsigned int this_nregs = hard_regno_nregs[regno][rl->mode];
for (j = 1; j < this_nregs; j++)
{
if (best_reg == -1)
return 0;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Using reg %d for reload %d\n", best_reg, rnum);
+ if (dump_file)
+ fprintf (dump_file, "Using reg %d for reload %d\n", best_reg, rnum);
- rl->nregs = HARD_REGNO_NREGS (best_reg, rl->mode);
+ rl->nregs = hard_regno_nregs[best_reg][rl->mode];
rl->regno = best_reg;
EXECUTE_IF_SET_IN_REG_SET
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;
int regno = REGNO (chain->rld[i].reg_rtx);
chain->rld[i].regno = regno;
chain->rld[i].nregs
- = HARD_REGNO_NREGS (regno, GET_MODE (chain->rld[i].reg_rtx));
+ = hard_regno_nregs[regno][GET_MODE (chain->rld[i].reg_rtx)];
}
else
chain->rld[i].regno = -1;
CLEAR_HARD_REG_SET (used_spill_regs_local);
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn));
+ if (dump_file)
+ fprintf (dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn));
qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower);
}
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;
i = reg_renumber[regno];
if (i < 0)
return;
- lim = i + HARD_REGNO_NREGS (i, PSEUDO_REGNO_MODE (regno));
+ lim = i + hard_regno_nregs[i][PSEUDO_REGNO_MODE (regno)];
while (i < lim)
regs_ever_live[i++] = 1;
}
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;
and require special code to handle code a reloaded PLUS operand.
Also consider backends where the flags register is clobbered by a
- MINUS, but we can emit a PLUS that does not clobber flags (ia32,
+ MINUS, but we can emit a PLUS that does not clobber flags (IA-32,
lea instruction comes to mind). If we try to reload a MINUS, we
may kill the flags register that was holding a useful value.
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;
struct elim_table *ep;
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
- if (ep->from_rtx == x && ep->can_eliminate)
+ if (ep->from_rtx == x)
ep->can_eliminate = 0;
return;
}
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 substed_operand[MAX_RECOG_OPERANDS];
rtx orig_operand[MAX_RECOG_OPERANDS];
struct elim_table *ep;
+ rtx plus_src;
if (! insn_is_asm && icode < 0)
{
{
rtx base = SET_SRC (old_set);
rtx base_insn = insn;
- int offset = 0;
+ HOST_WIDE_INT offset = 0;
while (base != ep->to_rtx)
{
}
/* We allow one special case which happens to work on all machines we
- currently support: a single set with the source being a PLUS of an
- eliminable register and a constant. */
- if (old_set
- && GET_CODE (SET_DEST (old_set)) == REG
- && GET_CODE (SET_SRC (old_set)) == PLUS
- && GET_CODE (XEXP (SET_SRC (old_set), 0)) == REG
- && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
- && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+ currently support: a single set with the source or a REG_EQUAL
+ note being a PLUS of an eliminable register and a constant. */
+ plus_src = 0;
+ if (old_set && GET_CODE (SET_DEST (old_set)) == REG)
+ {
+ /* First see if the source is of the form (plus (reg) CST). */
+ if (GET_CODE (SET_SRC (old_set)) == PLUS
+ && GET_CODE (XEXP (SET_SRC (old_set), 0)) == REG
+ && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
+ && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+ plus_src = SET_SRC (old_set);
+ else if (GET_CODE (SET_SRC (old_set)) == REG)
+ {
+ /* Otherwise, see if we have a REG_EQUAL note of the form
+ (plus (reg) CST). */
+ rtx links;
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ {
+ if (REG_NOTE_KIND (links) == REG_EQUAL
+ && GET_CODE (XEXP (links, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (links, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT
+ && REGNO (XEXP (XEXP (links, 0), 0)) < FIRST_PSEUDO_REGISTER)
+ {
+ plus_src = XEXP (links, 0);
+ break;
+ }
+ }
+ }
+ }
+ if (plus_src)
{
- rtx reg = XEXP (SET_SRC (old_set), 0);
- int offset = INTVAL (XEXP (SET_SRC (old_set), 1));
+ rtx reg = XEXP (plus_src, 0);
+ HOST_WIDE_INT offset = INTVAL (XEXP (plus_src, 1));
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->from_rtx == reg && ep->can_eliminate)
if (INSN_CODE (insn) < 0)
abort ();
}
- else
+ /* If we have a nonzero offset, and the source is already
+ a simple REG, the following transformation would
+ increase the cost of the insn by replacing a simple REG
+ with (plus (reg sp) CST). So try only when plus_src
+ comes from old_set proper, not REG_NOTES. */
+ else if (SET_SRC (old_set) == plus_src)
{
new_body = old_body;
if (! replace)
XEXP (SET_SRC (old_set), 0) = ep->to_rtx;
XEXP (SET_SRC (old_set), 1) = GEN_INT (offset);
}
+ else
+ break;
+
val = 1;
/* This can't have an effect on elimination offsets, so skip right
to the end. */
eliminate this reg. */
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS];
ep++)
- if (ep->from_rtx == orig_operand[i] && ep->can_eliminate)
+ if (ep->from_rtx == orig_operand[i])
ep->can_eliminate = 0;
}
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? */
frame_pointer_needed = (! flag_omit_frame_pointer
-#ifdef EXIT_IGNORE_STACK
/* ?? If EXIT_IGNORE_STACK is set, we will not save
and restore sp for alloca. So we can't eliminate
the frame pointer in that case. At some point,
sp-adjusting insns for this case. */
|| (current_function_calls_alloca
&& EXIT_IGNORE_STACK)
-#endif
|| FRAME_POINTER_REQUIRED);
num_eliminable = 0;
#endif
/* Count the number of eliminable registers and build the FROM and TO
- REG rtx's. Note that code in gen_rtx will cause, e.g.,
- gen_rtx (REG, Pmode, STACK_POINTER_REGNUM) to equal stack_pointer_rtx.
+ REG rtx's. Note that code in gen_rtx_REG will cause, e.g.,
+ gen_rtx_REG (Pmode, STACK_POINTER_REGNUM) to equal stack_pointer_rtx.
We depend on this. */
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
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;
if (reg_renumber[i] >= 0
&& (unsigned int) reg_renumber[i] <= regno
&& ((unsigned int) reg_renumber[i]
- + HARD_REGNO_NREGS ((unsigned int) reg_renumber[i],
- PSEUDO_REGNO_MODE (i))
+ + hard_regno_nregs[(unsigned int) reg_renumber[i]]
+ [PSEUDO_REGNO_MODE (i)]
> regno))
SET_REGNO_REG_SET (&spilled_pseudos, 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. */
alter_reg (i, reg_old_renumber[i]);
reg_old_renumber[i] = regno;
- if (rtl_dump_file)
+ if (dump_file)
{
if (regno == -1)
- fprintf (rtl_dump_file, " Register %d now on stack.\n\n", i);
+ fprintf (dump_file, " Register %d now on stack.\n\n", i);
else
- fprintf (rtl_dump_file, " Register %d now in %d.\n\n",
+ fprintf (dump_file, " Register %d now in %d.\n\n",
i, reg_renumber[i]);
}
}
return something_changed;
}
\f
-/* Find all paradoxical subregs within X and update reg_max_ref_width.
- Also mark any hard registers used to store user variables as
- forbidden from being used for spill registers. */
+/* Find all paradoxical subregs within X and update reg_max_ref_width. */
static void
-scan_paradoxical_subregs (x)
- rtx x;
+scan_paradoxical_subregs (rtx x)
{
int i;
const char *fmt;
switch (code)
{
case REG:
-#if 0
- if (SMALL_REGISTER_CLASSES && REGNO (x) < FIRST_PSEUDO_REGISTER
- && REG_USERVAR_P (x))
- SET_HARD_REG_BIT (bad_spill_regs_global, REGNO (x));
-#endif
- return;
-
case CONST_INT:
case CONST:
case SYMBOL_REF:
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);
+ CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered);
set_initial_elim_offsets ();
if (n == 1)
{
n = validate_replace_rtx (reload_reg,
- gen_rtx (code, mode,
- reload_reg),
+ gen_rtx_fmt_e (code,
+ mode,
+ reload_reg),
p);
/* We must also verify that the constraints
undo the replacement. */
if (!n)
{
- validate_replace_rtx (gen_rtx (code, mode,
- reload_reg),
+ validate_replace_rtx (gen_rtx_fmt_e (code,
+ mode,
+ reload_reg),
reload_reg, p);
break;
}
CLEAR_HARD_REG_SET (reg_reloaded_valid);
/* Don't assume a reload reg is still good after a call insn
- if it is a call-used reg. */
+ if it is a call-used reg, or if it contains a value that will
+ be partially clobbered by the call. */
else if (GET_CODE (insn) == CALL_INSN)
+ {
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
+ AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+ }
}
/* Clean up. */
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;
{
unsigned int i;
- nr = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ nr = hard_regno_nregs[regno][GET_MODE (x)];
/* Storing into a spilled-reg invalidates its contents.
This can happen if a block-local pseudo is allocated to that reg
and it wasn't spilled because this block's total need is 0.
|| ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
{
CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
+ CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i);
spill_reg_store[regno + i] = 0;
}
}
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 nregs = hard_regno_nregs[regno][mode];
unsigned int i;
for (i = regno; i < nregs + regno; 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 nregs = hard_regno_nregs[regno][mode];
unsigned int start_regno, end_regno, r;
int i;
/* A complication is that for some reload types, inheritance might
unsigned int conflict_start = true_regnum (rld[i].reg_rtx);
unsigned int conflict_end
= (conflict_start
- + HARD_REGNO_NREGS (conflict_start, rld[i].mode));
+ + hard_regno_nregs[conflict_start][rld[i].mode]);
/* If there is an overlap with the first to-be-freed register,
adjust the interval start. */
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 use for anything means we can't use it for RELOAD_OTHER. */
if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
return 0;
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;
return 0;
return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+ && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used, regno));
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
rtx reg = rld[i].reg_rtx;
if (reg && GET_CODE (reg) == REG
&& ((unsigned) regno - true_regnum (reg)
- <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned) 1)
+ <= hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] - (unsigned) 1)
&& i != reloadnum)
{
rtx other_input = rld[i].in;
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);
+ int nregs = hard_regno_nregs[regno][mode];
while (nregs-- > 0)
if (! reload_reg_free_for_value_p (regno, regno + nregs, opnum, type,
value, out, reloadnum,
return 1;
}
+/* Return nonzero if the rtx X is invariant over the current function. */
+/* ??? Actually, the places where we use this expect exactly what
+ * is tested here, and not everything that is function invariant. In
+ * particular, the frame pointer and arg pointer are special cased;
+ * pic_offset_table_rtx is not, and this will cause aborts when we
+ * go to spill these things to memory. */
+
+static int
+function_invariant_p (rtx x)
+{
+ if (CONSTANT_P (x))
+ return 1;
+ if (x == frame_pointer_rtx || x == arg_pointer_rtx)
+ return 1;
+ if (GET_CODE (x) == PLUS
+ && (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx)
+ && CONSTANT_P (XEXP (x, 1)))
+ return 1;
+ return 0;
+}
+
/* Determine whether the reload reg X overlaps any rtx'es used for
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;
&& ! TEST_HARD_REG_BIT (reload_reg_used_for_inherit,
regnum))))
{
- int nr = HARD_REGNO_NREGS (regnum, rld[r].mode);
+ int nr = hard_regno_nregs[regnum][rld[r].mode];
/* Avoid the problem where spilling a GENERAL_OR_FP_REG
(on 68000) got us two FP regs. If NR is 1,
we would reject both of them. */
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 a group is needed, verify that all the subsequent
registers still have their values intact. */
- int nr = HARD_REGNO_NREGS (i, rld[r].mode);
+ int nr = hard_regno_nregs[i][rld[r].mode];
int k;
for (k = 1; k < nr; k++)
{
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],
+ bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
i);
}
&& (regno != HARD_FRAME_POINTER_REGNUM
|| !frame_pointer_needed))
{
- int nr = HARD_REGNO_NREGS (regno, rld[r].mode);
+ int nr = hard_regno_nregs[regno][rld[r].mode];
int k;
rld[r].reg_rtx = equiv;
reload_inherited[r] = 1;
int nr = 1;
if (nregno < FIRST_PSEUDO_REGISTER)
- nr = HARD_REGNO_NREGS (nregno, rld[r].mode);
+ nr = hard_regno_nregs[nregno][rld[r].mode];
while (--nr >= 0)
reg_has_output_reload[nregno + nr] = 1;
if (i >= 0)
{
- nr = HARD_REGNO_NREGS (i, rld[r].mode);
+ nr = hard_regno_nregs[i][rld[r].mode];
while (--nr >= 0)
SET_HARD_REG_BIT (reg_is_output_reload, i + nr);
}
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;
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;
emit_output_reload_insns (chain, rld + j, j);
}
+/* Reload number R reloads from or to a group of hard registers starting at
+ register REGNO. Return true if it can be treated for inheritance purposes
+ like a group of reloads, each one reloading a single hard register.
+ The caller has already checked that the spill register and REGNO use
+ the same number of registers to store the reload value. */
+
+static bool
+inherit_piecemeal_p (int r ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED)
+{
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ return (!REG_CANNOT_CHANGE_MODE_P (reload_spill_index[r],
+ GET_MODE (rld[r].reg_rtx),
+ reg_raw_mode[reload_spill_index[r]])
+ && !REG_CANNOT_CHANGE_MODE_P (regno,
+ GET_MODE (rld[r].reg_rtx),
+ reg_raw_mode[regno]));
+#else
+ return true;
+#endif
+}
+
/* 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;
other_operand_reload_insns = 0;
/* Dump reloads into the dump file. */
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "\nReloads for insn # %d\n", INSN_UID (insn));
- debug_reload_to_stream (rtl_dump_file);
+ fprintf (dump_file, "\nReloads for insn # %d\n", INSN_UID (insn));
+ debug_reload_to_stream (dump_file);
}
/* Now output the instructions to copy the data into and out of the
reloads for the operand. The RELOAD_OTHER output reloads are
output in descending order by reload number. */
- emit_insn_before (other_input_address_reload_insns, insn);
- emit_insn_before (other_input_reload_insns, insn);
+ emit_insn_before_sameloc (other_input_address_reload_insns, insn);
+ emit_insn_before_sameloc (other_input_reload_insns, insn);
for (j = 0; j < reload_n_operands; j++)
{
- emit_insn_before (inpaddr_address_reload_insns[j], insn);
- emit_insn_before (input_address_reload_insns[j], insn);
- emit_insn_before (input_reload_insns[j], insn);
+ emit_insn_before_sameloc (inpaddr_address_reload_insns[j], insn);
+ emit_insn_before_sameloc (input_address_reload_insns[j], insn);
+ emit_insn_before_sameloc (input_reload_insns[j], insn);
}
- emit_insn_before (other_operand_reload_insns, insn);
- emit_insn_before (operand_reload_insns, insn);
+ emit_insn_before_sameloc (other_operand_reload_insns, insn);
+ emit_insn_before_sameloc (operand_reload_insns, insn);
for (j = 0; j < reload_n_operands; j++)
{
- rtx x = emit_insn_after (outaddr_address_reload_insns[j], insn);
- x = emit_insn_after (output_address_reload_insns[j], x);
- x = emit_insn_after (output_reload_insns[j], x);
- emit_insn_after (other_output_reload_insns[j], x);
+ rtx x = emit_insn_after_sameloc (outaddr_address_reload_insns[j], insn);
+ x = emit_insn_after_sameloc (output_address_reload_insns[j], x);
+ x = emit_insn_after_sameloc (output_reload_insns[j], x);
+ emit_insn_after_sameloc (other_output_reload_insns[j], x);
}
/* For all the spill regs newly reloaded in this instruction,
if (i >= 0 && rld[r].reg_rtx != 0)
{
- int nr = HARD_REGNO_NREGS (i, GET_MODE (rld[r].reg_rtx));
+ int nr = hard_regno_nregs[i][GET_MODE (rld[r].reg_rtx)];
int k;
int part_reaches_end = 0;
int all_reaches_end = 1;
If consecutive registers are used, clear them all. */
for (k = 0; k < nr; k++)
+ {
CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k);
+ }
/* Maybe the spill reg contains a copy of reload_out. */
if (rld[r].out != 0
/* AUTO_INC */ : XEXP (rld[r].in_reg, 0));
int nregno = REGNO (out);
int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (rld[r].reg_rtx)));
+ : hard_regno_nregs[nregno]
+ [GET_MODE (rld[r].reg_rtx)]);
+ bool piecemeal;
spill_reg_store[i] = new_spill_reg_store[i];
spill_reg_stored_to[i] = out;
reg_last_reload_reg[nregno] = rld[r].reg_rtx;
+ piecemeal = (nregno < FIRST_PSEUDO_REGISTER
+ && nr == nnr
+ && inherit_piecemeal_p (r, nregno));
+
/* If NREGNO is a hard register, it may occupy more than
one register. If it does, say what is in the
rest of the registers assuming that both registers
if (nregno < FIRST_PSEUDO_REGISTER)
for (k = 1; k < nnr; k++)
reg_last_reload_reg[nregno + k]
- = (nr == nnr
+ = (piecemeal
? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
: 0);
{
CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
reg_reloaded_contents[i + k]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ = (nregno >= FIRST_PSEUDO_REGISTER || !piecemeal
? nregno
: nregno + k);
reg_reloaded_insn[i + k] = insn;
SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i + k, GET_MODE (out)))
+ SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k);
}
}
{
int nregno;
int nnr;
+ rtx in;
+ bool piecemeal;
if (GET_CODE (rld[r].in) == REG
&& REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER)
- nregno = REGNO (rld[r].in);
+ in = rld[r].in;
else if (GET_CODE (rld[r].in_reg) == REG)
- nregno = REGNO (rld[r].in_reg);
+ in = rld[r].in_reg;
else
- nregno = REGNO (XEXP (rld[r].in_reg, 0));
+ in = XEXP (rld[r].in_reg, 0);
+ nregno = REGNO (in);
nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (rld[r].reg_rtx)));
+ : hard_regno_nregs[nregno]
+ [GET_MODE (rld[r].reg_rtx)]);
reg_last_reload_reg[nregno] = rld[r].reg_rtx;
+ piecemeal = (nregno < FIRST_PSEUDO_REGISTER
+ && nr == nnr
+ && inherit_piecemeal_p (r, nregno));
+
if (nregno < FIRST_PSEUDO_REGISTER)
for (k = 1; k < nnr; k++)
reg_last_reload_reg[nregno + k]
- = (nr == nnr
+ = (piecemeal
? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
: 0);
{
CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
reg_reloaded_contents[i + k]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ = (nregno >= FIRST_PSEUDO_REGISTER || !piecemeal
? nregno
: nregno + k);
reg_reloaded_insn[i + k] = insn;
SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i + k, GET_MODE (in)))
+ SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k);
}
}
}
&& REGNO (src_reg) < FIRST_PSEUDO_REGISTER)
{
int src_regno = REGNO (src_reg);
- int nr = HARD_REGNO_NREGS (src_regno, rld[r].mode);
+ int nr = hard_regno_nregs[src_regno][rld[r].mode];
/* The place where to find a death note varies with
PRESERVE_DEATH_INFO_REGNO_P . The condition is not
necessarily checked exactly in the code that moves
reg_reloaded_insn[src_regno + nr] = store_insn;
CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + nr);
SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr);
+ if (HARD_REGNO_CALL_PART_CLOBBERED (src_regno + nr,
+ GET_MODE (src_reg)))
+ SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
+ src_regno + nr);
SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
if (note)
SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
}
reg_last_reload_reg[nregno] = src_reg;
+ /* We have to set reg_has_output_reload here, or else
+ forget_old_reloads_1 will clear reg_last_reload_reg
+ right away. */
+ reg_has_output_reload[nregno] = 1;
}
}
else
{
- int num_regs = HARD_REGNO_NREGS (nregno, GET_MODE (rld[r].out));
+ int num_regs = hard_regno_nregs[nregno][GET_MODE (rld[r].out)];
while (num_regs-- > 0)
reg_last_reload_reg[nregno + num_regs] = 0;
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;
#endif
/* If IN is a simple operand, use gen_move_insn. */
- else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
+ else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
emit_insn (gen_move_insn (out, in));
#ifdef HAVE_reload_load_address
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];
}
/* We will be deleting the insn. Remove the spill reg information. */
- for (k = HARD_REGNO_NREGS (last_reload_reg, GET_MODE (reg)); k-- > 0; )
+ for (k = hard_regno_nregs[last_reload_reg][GET_MODE (reg)]; k-- > 0; )
{
spill_reg_store[last_reload_reg + k] = 0;
spill_reg_stored_to[last_reload_reg + k] = 0;
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;
code = GET_CODE (prev);
if (code == CODE_LABEL || code == JUMP_INSN)
return;
- if (GET_RTX_CLASS (code) != 'i')
+ if (!INSN_P (prev))
continue;
if (reg_set_p (x, PATTERN (prev)))
break;
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);
\f
#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;
== (EDGE_ABNORMAL | EDGE_EH))
break;
}
- if (e && GET_CODE (bb->end) != CALL_INSN && !can_throw_internal (bb->end))
+ if (e && GET_CODE (BB_END (bb)) != CALL_INSN
+ && !can_throw_internal (BB_END (bb)))
{
- rtx insn = bb->end, stop = NEXT_INSN (bb->end);
+ rtx insn = BB_END (bb), stop = NEXT_INSN (BB_END (bb));
rtx next;
for (e = bb->succ; e; e = e->succ_next)
if (e->flags & EDGE_FALLTHRU)
be already deleted. */
while ((GET_CODE (insn) == INSN || GET_CODE (insn) == NOTE)
&& !can_throw_internal (insn)
- && insn != bb->head)
+ && insn != BB_HEAD (bb))
insn = PREV_INSN (insn);
if (GET_CODE (insn) != CALL_INSN && !can_throw_internal (insn))
abort ();
- bb->end = insn;
+ BB_END (bb) = insn;
inserted = true;
insn = NEXT_INSN (insn);
while (insn && insn != stop)