/* 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, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
/* Element N is the list of insns that initialized reg N from its equivalent
constant or memory slot. */
-static rtx *reg_equiv_init;
+rtx *reg_equiv_init;
+int reg_equiv_init_size;
/* Vector to remember old contents of reg_renumber before spilling. */
static short *reg_old_renumber;
/* This obstack is used for allocation of rtl during register elimination.
The allocated storage can be freed once find_reloads has processed the
insn. */
-struct obstack reload_obstack;
+static struct obstack reload_obstack;
/* Points to the beginning of the reload_obstack. All insn_chain structures
are allocated first. */
-char *reload_startobj;
+static char *reload_startobj;
/* The point after all insn_chain structures. Used to quickly deallocate
memory allocated in copy_reloads during calculate_needs_all_insns. */
-char *reload_firstobj;
+static char *reload_firstobj;
/* This points before all local rtl generated by register elimination.
Used to quickly free all memory after processing one insn. */
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 bool 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 *);
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 add_auto_inc_notes (rtx, rtx);
#endif
static void copy_eh_notes (rtx, rtx);
+static int reloads_conflict (int, int);
+static rtx gen_reload (rtx, rtx, int, enum reload_type);
\f
/* Initialize the reload pass once per compilation. */
/* Set during calculate_needs if an insn needs register elimination. */
static int something_needs_elimination;
/* Set during calculate_needs if an insn needs an operand changed. */
-int something_needs_operands_changed;
+static int something_needs_operands_changed;
/* Nonzero means we couldn't get enough spill regs. */
static int failure;
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)
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));
&& GET_MODE (insn) != VOIDmode)
PUT_MODE (insn, VOIDmode);
+ if (INSN_P (insn))
+ scan_paradoxical_subregs (PATTERN (insn));
+
if (set != 0 && REG_P (SET_DEST (set)))
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- if (note
- && (! function_invariant_p (XEXP (note, 0))
- || ! flag_pic
- /* A function invariant is often CONSTANT_P but may
- include a register. We promise to only pass
- CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
- || (CONSTANT_P (XEXP (note, 0))
- && LEGITIMATE_PIC_OPERAND_P (XEXP (note, 0)))))
+ rtx x;
+
+ if (! note)
+ continue;
+
+ i = REGNO (SET_DEST (set));
+ x = XEXP (note, 0);
+
+ if (i <= LAST_VIRTUAL_REGISTER)
+ continue;
+
+ if (! function_invariant_p (x)
+ || ! flag_pic
+ /* A function invariant is often CONSTANT_P but may
+ include a register. We promise to only pass
+ CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
+ || (CONSTANT_P (x)
+ && LEGITIMATE_PIC_OPERAND_P (x)))
{
- rtx x = XEXP (note, 0);
- i = REGNO (SET_DEST (set));
- if (i > LAST_VIRTUAL_REGISTER)
+ /* It can happen that a REG_EQUIV note contains a MEM
+ that is not a legitimate memory operand. As later
+ stages of reload assume that all addresses found
+ in the reg_equiv_* arrays were originally legitimate,
+ we ignore such REG_EQUIV notes. */
+ if (memory_operand (x, VOIDmode))
+ {
+ /* Always unshare the equivalence, so we can
+ substitute into this insn without touching the
+ equivalence. */
+ reg_equiv_memory_loc[i] = copy_rtx (x);
+ }
+ else if (function_invariant_p (x))
{
- /* It can happen that a REG_EQUIV note contains a MEM
- that is not a legitimate memory operand. As later
- stages of reload assume that all addresses found
- in the reg_equiv_* arrays were originally legitimate,
- we ignore such REG_EQUIV notes. */
- if (memory_operand (x, VOIDmode))
+ if (GET_CODE (x) == PLUS)
{
- /* Always unshare the equivalence, so we can
- substitute into this insn without touching the
- equivalence. */
- reg_equiv_memory_loc[i] = copy_rtx (x);
+ /* This is PLUS of frame pointer and a constant,
+ and might be shared. Unshare it. */
+ reg_equiv_constant[i] = copy_rtx (x);
+ num_eliminable_invariants++;
}
- else if (function_invariant_p (x))
+ else if (x == frame_pointer_rtx
+ || x == arg_pointer_rtx)
{
- if (GET_CODE (x) == PLUS)
- {
- /* This is PLUS of frame pointer and a constant,
- and might be shared. Unshare it. */
- reg_equiv_constant[i] = copy_rtx (x);
- num_eliminable_invariants++;
- }
- else if (x == frame_pointer_rtx
- || x == arg_pointer_rtx)
- {
- reg_equiv_constant[i] = x;
- num_eliminable_invariants++;
- }
- else if (LEGITIMATE_CONSTANT_P (x))
- reg_equiv_constant[i] = x;
- else
- {
- reg_equiv_memory_loc[i]
- = force_const_mem (GET_MODE (SET_DEST (set)), x);
- if (!reg_equiv_memory_loc[i])
- continue;
- }
+ reg_equiv_constant[i] = x;
+ num_eliminable_invariants++;
}
+ else if (LEGITIMATE_CONSTANT_P (x))
+ reg_equiv_constant[i] = x;
else
- continue;
-
- /* If this register is being made equivalent to a MEM
- and the MEM is not SET_SRC, the equivalencing insn
- is one with the MEM as a SET_DEST and it occurs later.
- So don't mark this insn now. */
- if (!MEM_P (x)
- || rtx_equal_p (SET_SRC (set), x))
- reg_equiv_init[i]
- = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[i]);
+ {
+ reg_equiv_memory_loc[i]
+ = force_const_mem (GET_MODE (SET_DEST (set)), x);
+ if (! reg_equiv_memory_loc[i])
+ reg_equiv_init[i] = NULL_RTX;
+ }
+ }
+ else
+ {
+ reg_equiv_init[i] = NULL_RTX;
+ continue;
}
}
+ else
+ reg_equiv_init[i] = NULL_RTX;
}
-
- /* If this insn is setting a MEM from a register equivalent to it,
- this is the equivalencing insn. */
- else if (set && MEM_P (SET_DEST (set))
- && REG_P (SET_SRC (set))
- && reg_equiv_memory_loc[REGNO (SET_SRC (set))]
- && rtx_equal_p (SET_DEST (set),
- reg_equiv_memory_loc[REGNO (SET_SRC (set))]))
- reg_equiv_init[REGNO (SET_SRC (set))]
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- reg_equiv_init[REGNO (SET_SRC (set))]);
-
- if (INSN_P (insn))
- scan_paradoxical_subregs (PATTERN (insn));
}
+ if (dump_file)
+ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ if (reg_equiv_init[i])
+ {
+ fprintf (dump_file, "init_insns for %u: ", i);
+ print_inline_rtx (dump_file, reg_equiv_init[i], 20);
+ fprintf (dump_file, "\n");
+ }
+
init_elim_table ();
first_label_num = get_first_label_num ();
if (starting_frame_size != get_frame_size ())
something_changed = 1;
+ /* Even if the frame size remained the same, we might still have
+ changed elimination offsets, e.g. if find_reloads called
+ force_const_mem requiring the back end to allocate a constant
+ pool base register that needs to be saved on the stack. */
+ else if (!verify_initial_elim_offsets ())
+ something_changed = 1;
+
{
HARD_REG_SET to_spill;
CLEAR_HARD_REG_SET (to_spill);
gcc_assert (old_frame_size == get_frame_size ());
- if (num_eliminable)
- verify_initial_elim_offsets ();
+ gcc_assert (verify_initial_elim_offsets ());
}
/* If we were able to eliminate the frame pointer, show that it is no
CLEAR_REGNO_REG_SET (bb->global_live_at_start,
HARD_FRAME_POINTER_REGNUM);
- /* Come here (with failure set nonzero) if we can't get enough spill regs
- and we decide not to abort about it. */
+ /* Come here (with failure set nonzero) if we can't get enough spill
+ regs. */
failed:
CLEAR_REG_SET (&spilled_pseudos);
replace_pseudos_in (& XEXP (PATTERN (insn), 0),
VOIDmode, PATTERN (insn));
+ /* Discard obvious no-ops, even without -O. This optimization
+ is fast and doesn't interfere with debugging. */
+ if (NONJUMP_INSN_P (insn)
+ && GET_CODE (PATTERN (insn)) == SET
+ && REG_P (SET_SRC (PATTERN (insn)))
+ && REG_P (SET_DEST (PATTERN (insn)))
+ && (REGNO (SET_SRC (PATTERN (insn)))
+ == REGNO (SET_DEST (PATTERN (insn)))))
+ {
+ delete_insn (insn);
+ continue;
+ }
+
pnote = ®_NOTES (insn);
while (*pnote != 0)
{
if (size > STACK_CHECK_MAX_FRAME_SIZE)
{
- warning ("frame size too large for reliable stack checking");
+ warning (0, "frame size too large for reliable stack checking");
if (! verbose_warned)
{
- warning ("try reducing the number of local variables");
+ warning (0, "try reducing the number of local variables");
verbose_warned = 1;
}
}
free (offsets_at);
free (reg_equiv_mem);
- free (reg_equiv_init);
+ reg_equiv_init = 0;
free (reg_equiv_address);
free (reg_max_ref_width);
free (reg_old_renumber);
static void
order_regs_for_reload (struct insn_chain *chain)
{
- int i;
+ unsigned i;
HARD_REG_SET used_by_pseudos;
HARD_REG_SET used_by_pseudos2;
reg_set_iterator rsi;
static void
spill_failure (rtx insn, enum reg_class class)
{
- static const char *const reg_class_names[] = REG_CLASS_NAMES;
if (asm_noperands (PATTERN (insn)) >= 0)
error_for_asm (insn, "can't find a register in class %qs while "
"reloading %<asm%>",
where something illegal happened during reload_as_needed that could
cause incorrect code to be generated if we did not check for it. */
-static void
+static bool
verify_initial_elim_offsets (void)
{
HOST_WIDE_INT t;
-#ifdef ELIMINABLE_REGS
- struct elim_table *ep;
+ if (!num_eliminable)
+ return true;
- for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
- {
- INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
- gcc_assert (t == ep->initial_offset);
- }
+#ifdef ELIMINABLE_REGS
+ {
+ struct elim_table *ep;
+
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ {
+ INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
+ if (t != ep->initial_offset)
+ return false;
+ }
+ }
#else
INITIAL_FRAME_POINTER_OFFSET (t);
- gcc_assert (t == reg_eliminate[0].initial_offset);
+ if (t != reg_eliminate[0].initial_offset)
+ return false;
#endif
+
+ return true;
}
/* Reset all offsets on eliminable registers to their initial values. */
num_not_at_initial_offset = 0;
}
+/* Subroutine of set_initial_label_offsets called via for_each_eh_label. */
+
+static void
+set_initial_eh_label_offset (rtx label)
+{
+ set_label_offsets (label, NULL_RTX, 1);
+}
+
/* Initialize the known label offsets.
Set a known offset for each forced label to be at the initial offset
of each elimination. We do this because we assume that all
for (x = forced_labels; x; x = XEXP (x, 1))
if (XEXP (x, 0))
set_label_offsets (XEXP (x, 0), NULL_RTX, 1);
+
+ for_each_eh_label (set_initial_eh_label_offset);
}
/* Set all elimination offsets to the known values for the code label given
SET_REGNO_REG_SET (&spilled_pseudos, i);
}
-/* I'm getting weird preprocessor errors if I use IOR_HARD_REG_SET
- from within EXECUTE_IF_SET_IN_REG_SET. Hence this awkwardness. */
-
-static void
-ior_hard_reg_set (HARD_REG_SET *set1, HARD_REG_SET *set2)
-{
- IOR_HARD_REG_SET (*set1, *set2);
-}
-
/* After find_reload_regs has been run for all insn that need reloads,
and/or spill_hard_regs was called, this function is used to actually
spill pseudo registers and try to reallocate them. It also sets up the
{
struct insn_chain *chain;
int something_changed = 0;
- int i;
+ unsigned i;
reg_set_iterator rsi;
/* Build the spill_regs array for the function. */
EXECUTE_IF_SET_IN_REG_SET
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi)
{
- ior_hard_reg_set (pseudo_forbidden_regs + i,
- &chain->used_spill_regs);
+ IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
+ chain->used_spill_regs);
}
EXECUTE_IF_SET_IN_REG_SET
(&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
{
- ior_hard_reg_set (pseudo_forbidden_regs + i,
- &chain->used_spill_regs);
+ IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
+ chain->used_spill_regs);
}
}
and call retry_global_alloc.
We change spill_pseudos here to only contain pseudos that did not
get a new hard register. */
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
{
HARD_REG_SET forbidden;
}
/* Let alter_reg modify the reg rtx's for the modified pseudos. */
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
{
int regno = reg_renumber[i];
if (reg_old_renumber[i] == regno)
unsigned int nr;
/* note_stores does give us subregs of hard regs,
- subreg_regno_offset will abort if it is not a hard reg. */
+ subreg_regno_offset requires a hard reg. */
while (GET_CODE (x) == SUBREG)
{
/* We ignore the subreg offset when calculating the regno,
This function uses the same algorithm as reload_reg_free_p above. */
-int
+static int
reloads_conflict (int r1, int r2)
{
enum reload_type r1_type = rld[r1].when_needed;
\f
/* Indexed by reload number, 1 if incoming value
inherited from previous insns. */
-char reload_inherited[MAX_RELOADS];
+static char reload_inherited[MAX_RELOADS];
/* For an inherited reload, this is the insn the reload was inherited from,
if we know it. Otherwise, this is 0. */
-rtx reload_inheritance_insn[MAX_RELOADS];
+static rtx reload_inheritance_insn[MAX_RELOADS];
/* If nonzero, this is a place to get the value of the reload,
rather than using reload_in. */
-rtx reload_override_in[MAX_RELOADS];
+static rtx reload_override_in[MAX_RELOADS];
/* For each reload, the hard register number of the register used,
or -1 if we did not need a register for this reload. */
-int reload_spill_index[MAX_RELOADS];
+static int reload_spill_index[MAX_RELOADS];
/* Subroutine of free_for_value_p, used to check a single register.
START_REGNO is the starting regno of the full reload register
}
/* 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. */
+/* ??? 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 we must not spill these things to
+ memory. */
-static int
+int
function_invariant_p (rtx x)
{
if (CONSTANT_P (x))
need_mode = mode;
else
need_mode
- = smallest_mode_for_size (GET_MODE_SIZE (mode) + byte,
+ = smallest_mode_for_size (GET_MODE_BITSIZE (mode)
+ + byte * BITS_PER_UNIT,
GET_MODE_CLASS (mode));
- if (
-#ifdef CANNOT_CHANGE_MODE_CLASS
- (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
- need_mode)
- &&
-#endif
- (GET_MODE_SIZE (GET_MODE (last_reg))
+ if ((GET_MODE_SIZE (GET_MODE (last_reg))
>= GET_MODE_SIZE (need_mode))
#ifdef CANNOT_CHANGE_MODE_CLASS
- )
+ /* Verify that the register in "i" can be obtained
+ from LAST_REG. */
+ && !REG_CANNOT_CHANGE_MODE_P (REGNO (last_reg),
+ GET_MODE (last_reg),
+ mode)
#endif
&& reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
gcc_assert (GET_CODE (equiv) == SUBREG);
regno = subreg_regno (equiv);
equiv = gen_rtx_REG (rld[r].mode, regno);
+ /* If we choose EQUIV as the reload register, but the
+ loop below decides to cancel the inheritance, we'll
+ end up reloading EQUIV in rld[r].mode, not the mode
+ it had originally. That isn't safe when EQUIV isn't
+ available as a spill register since its value might
+ still be live at this point. */
+ for (i = regno; i < regno + (int) rld[r].nregs; i++)
+ if (TEST_HARD_REG_BIT (reload_reg_unavailable, i))
+ equiv = 0;
}
}
|| rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
- /* Check to see if we accidentally converted two reloads
- that use the same reload register with different inputs
- to the same type. If so, the resulting code won't work,
- so abort. */
+ /* Check to see if we accidentally converted two
+ reloads that use the same reload register with
+ different inputs to the same type. If so, the
+ resulting code won't work. */
if (rld[j].reg_rtx)
for (k = 0; k < j; k++)
gcc_assert (rld[k].in == 0 || rld[k].reg_rtx == 0
|| !(set = single_set (insn))
|| rtx_equal_p (old, SET_DEST (set))
|| !reg_mentioned_p (old, SET_SRC (set))
- || !regno_clobbered_p (REGNO (old), insn, rl->mode, 0))
+ || !((REGNO (old) < FIRST_PSEUDO_REGISTER)
+ && regno_clobbered_p (REGNO (old), insn, rl->mode, 0)))
gen_reload (old, reloadreg, rl->opnum,
rl->when_needed);
}
actually no need to store the old value in it. */
if (optimize
+ /* Only attempt this for input reloads; for RELOAD_OTHER we miss
+ that there may be multiple uses of the previous output reload.
+ Restricting to RELOAD_FOR_INPUT is mostly paranoia. */
+ && rl->when_needed == RELOAD_FOR_INPUT
&& (reload_inherited[j] || reload_override_in[j])
&& rl->reg_rtx
&& REG_P (rl->reg_rtx)
Returns first insn emitted. */
-rtx
+static rtx
gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
{
rtx last = get_last_insn ();
/* If the pseudo-reg we are reloading is no longer referenced
anywhere between the store into it and here,
- and no jumps or labels intervene, then the value can get
- here through the reload reg alone.
+ and we're within the same basic block, then the value can only
+ pass through the reload reg and end up here.
Otherwise, give up--return. */
for (i1 = NEXT_INSN (output_reload_insn);
i1 != insn; i1 = NEXT_INSN (i1))
{
- if (LABEL_P (i1) || JUMP_P (i1))
+ if (NOTE_INSN_BASIC_BLOCK_P (i1))
return;
if ((NONJUMP_INSN_P (i1) || CALL_P (i1))
&& reg_mentioned_p (reg, PATTERN (i1)))