static void set_label_offsets (rtx, rtx, int);
static void check_eliminable_occurrences (rtx);
static void elimination_effects (rtx, enum machine_mode);
+static rtx eliminate_regs_1 (rtx, enum machine_mode, rtx, bool, bool);
static int eliminate_regs_in_insn (rtx, int);
static void update_eliminable_offsets (void);
static void mark_not_eliminable (rtx, const_rtx, 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_eliminable_invariants (rtx, bool);
static void init_elim_table (void);
+static void free_reg_equiv (void);
static void update_eliminables (HARD_REG_SET *);
+static void elimination_costs_in_insn (rtx);
static void spill_hard_reg (unsigned int, int);
static int finish_spills (int);
static void scan_paradoxical_subregs (rtx);
\f
/* Global variables used by reload and its subroutines. */
+/* The current basic block while in calculate_elim_costs_all_insns. */
+static basic_block elim_bb;
+
/* 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. */
if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
df_set_regs_ever_live (i, true);
- /* 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)
- and cse'd or loop-moved constant memory addresses.
-
- Record constant equivalents in reg_equiv_constant
- so they will be substituted by find_reloads.
- Record memory equivalents in reg_mem_equiv so they can
- be substituted eventually by altering the REG-rtx's. */
-
- reg_equiv_constant = XCNEWVEC (rtx, max_regno);
- reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
- reg_equiv_mem = XCNEWVEC (rtx, max_regno);
- reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
- reg_equiv_address = XCNEWVEC (rtx, max_regno);
- reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
reg_old_renumber = XCNEWVEC (short, max_regno);
memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short));
pseudo_forbidden_regs = XNEWVEC (HARD_REG_SET, max_regno);
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. */
-
- num_eliminable_invariants = 0;
- for (insn = first; insn; insn = NEXT_INSN (insn))
- {
- rtx set = single_set (insn);
-
- /* We may introduce USEs that we want to remove at the end, so
- we'll mark them with QImode. Make sure there are no
- previously-marked insns left by say regmove. */
- if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE
- && GET_MODE (insn) != VOIDmode)
- PUT_MODE (insn, VOIDmode);
-
- if (NONDEBUG_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);
- 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)))
- {
- /* 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))
- {
- if (GET_CODE (x) == PLUS)
- {
- /* This is PLUS of frame pointer and a constant,
- and might be shared. Unshare it. */
- reg_equiv_invariant[i] = copy_rtx (x);
- num_eliminable_invariants++;
- }
- else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
- {
- reg_equiv_invariant[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])
- reg_equiv_init[i] = NULL_RTX;
- }
- }
- else
- {
- reg_equiv_init[i] = NULL_RTX;
- continue;
- }
- }
- else
- reg_equiv_init[i] = NULL_RTX;
- }
- }
-
- 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_eliminable_invariants (first, true);
init_elim_table ();
- first_label_num = get_first_label_num ();
- num_labels = max_label_num () - first_label_num;
-
- /* Allocate the tables used to store offset information at labels. */
- /* We used to use alloca here, but the size of what it would try to
- allocate would occasionally cause it to exceed the stack limit and
- cause a core dump. */
- offsets_known_at = XNEWVEC (char, num_labels);
- offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) 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.
Do not touch virtual registers. */
}
}
- /* Indicate that we no longer have known memory locations or constants. */
- if (reg_equiv_constant)
- free (reg_equiv_constant);
- if (reg_equiv_invariant)
- free (reg_equiv_invariant);
- reg_equiv_constant = 0;
- reg_equiv_invariant = 0;
- VEC_free (rtx, gc, reg_equiv_memory_loc_vec);
- reg_equiv_memory_loc = 0;
-
free (temp_pseudo_reg_arr);
- if (offsets_known_at)
- free (offsets_known_at);
- if (offsets_at)
- free (offsets_at);
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (reg_equiv_alt_mem_list[i])
- free_EXPR_LIST_list (®_equiv_alt_mem_list[i]);
- free (reg_equiv_alt_mem_list);
-
- free (reg_equiv_mem);
+ /* Indicate that we no longer have known memory locations or constants. */
+ free_reg_equiv ();
reg_equiv_init = 0;
- free (reg_equiv_address);
free (reg_max_ref_width);
free (reg_old_renumber);
free (pseudo_previous_regs);
*pprev_reload = 0;
}
\f
+/* This function is called from the register allocator to set up estimates
+ for the cost of eliminating pseudos which have REG_EQUIV equivalences to
+ an invariant. The structure is similar to calculate_needs_all_insns. */
+
+void
+calculate_elim_costs_all_insns (void)
+{
+ int *reg_equiv_init_cost;
+ basic_block bb;
+ int i;
+
+ reg_equiv_init_cost = XCNEWVEC (int, max_regno);
+ init_elim_table ();
+ init_eliminable_invariants (get_insns (), false);
+
+ set_initial_elim_offsets ();
+ set_initial_label_offsets ();
+
+ FOR_EACH_BB (bb)
+ {
+ rtx insn;
+ elim_bb = bb;
+
+ FOR_BB_INSNS (bb, insn)
+ {
+ /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might
+ include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see
+ what effects this has on the known offsets at labels. */
+
+ if (LABEL_P (insn) || JUMP_P (insn)
+ || (INSN_P (insn) && REG_NOTES (insn) != 0))
+ set_label_offsets (insn, insn, 0);
+
+ if (INSN_P (insn))
+ {
+ rtx set = single_set (insn);
+
+ /* Skip insns that only set an equivalence. */
+ if (set && REG_P (SET_DEST (set))
+ && reg_renumber[REGNO (SET_DEST (set))] < 0
+ && (reg_equiv_constant[REGNO (SET_DEST (set))]
+ || (reg_equiv_invariant[REGNO (SET_DEST (set))])))
+ {
+ unsigned regno = REGNO (SET_DEST (set));
+ rtx init = reg_equiv_init[regno];
+ if (init)
+ {
+ rtx t = eliminate_regs_1 (SET_SRC (set), VOIDmode, insn,
+ false, true);
+ int cost = rtx_cost (t, SET,
+ optimize_bb_for_speed_p (bb));
+ int freq = REG_FREQ_FROM_BB (bb);
+
+ reg_equiv_init_cost[regno] = cost * freq;
+ continue;
+ }
+ }
+ /* If needed, eliminate any eliminable registers. */
+ if (num_eliminable || num_eliminable_invariants)
+ elimination_costs_in_insn (insn);
+
+ if (num_eliminable)
+ update_eliminable_offsets ();
+ }
+ }
+ }
+ for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ {
+ if (reg_equiv_invariant[i])
+ {
+ if (reg_equiv_init[i])
+ {
+ int cost = reg_equiv_init_cost[i];
+ if (dump_file)
+ fprintf (dump_file,
+ "Reg %d has equivalence, initial gains %d\n", i, cost);
+ if (cost != 0)
+ ira_adjust_equiv_reg_cost (i, cost);
+ }
+ else
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Reg %d had equivalence, but can't be eliminated\n",
+ i);
+ ira_adjust_equiv_reg_cost (i, 0);
+ }
+ }
+ }
+
+ free_reg_equiv ();
+ free (reg_equiv_init_cost);
+}
+\f
/* Comparison function for qsort to decide which of two reloads
should be handled first. *P1 and *P2 are the reload numbers. */
}
}
\f
+/* Called through for_each_rtx, this function examines every reg that occurs
+ in PX and adjusts the costs for its elimination which are gathered by IRA.
+ DATA is the insn in which PX occurs. We do not recurse into MEM
+ expressions. */
+
+static int
+note_reg_elim_costly (rtx *px, void *data)
+{
+ rtx insn = (rtx)data;
+ rtx x = *px;
+
+ if (MEM_P (x))
+ return -1;
+
+ if (REG_P (x)
+ && REGNO (x) >= FIRST_PSEUDO_REGISTER
+ && reg_equiv_init[REGNO (x)]
+ && reg_equiv_invariant[REGNO (x)])
+ {
+ rtx t = reg_equiv_invariant[REGNO (x)];
+ rtx new_rtx = eliminate_regs_1 (t, Pmode, insn, true, true);
+ int cost = rtx_cost (new_rtx, SET, optimize_bb_for_speed_p (elim_bb));
+ int freq = REG_FREQ_FROM_BB (elim_bb);
+
+ if (cost != 0)
+ ira_adjust_equiv_reg_cost (REGNO (x), -cost * freq);
+ }
+ return 0;
+}
+
/* Scan X and replace any eliminable registers (such as fp) with a
replacement (such as sp), plus an offset.
This means, do not set ref_outside_mem even if the reference
is outside of MEMs.
+ If FOR_COSTS is true, we are being called before reload in order to
+ estimate the costs of keeping registers with an equivalence unallocated.
+
REG_EQUIV_MEM and REG_EQUIV_ADDRESS contain address that have had
replacements done assuming all offsets are at their initial values. If
they are not, or if REG_EQUIV_ADDRESS is nonzero for a pseudo we
static rtx
eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
- bool may_use_invariant)
+ bool may_use_invariant, bool for_costs)
{
enum rtx_code code = GET_CODE (x);
struct elim_table *ep;
{
if (may_use_invariant || (insn && DEBUG_INSN_P (insn)))
return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]),
- mem_mode, insn, true);
+ mem_mode, insn, true, for_costs);
/* There exists at least one use of REGNO that cannot be
eliminated. Prevent the defining insn from being deleted. */
reg_equiv_init[regno] = NULL_RTX;
- alter_reg (regno, -1, true);
+ if (!for_costs)
+ alter_reg (regno, -1, true);
}
return x;
operand of a load-address insn. */
{
- rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true);
- rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true);
+ rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true,
+ for_costs);
+ rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true,
+ for_costs);
if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)))
{
case GE: case GT: case GEU: case GTU:
case LE: case LT: case LEU: case LTU:
{
- rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false);
+ rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false,
+ for_costs);
rtx new1 = XEXP (x, 1)
- ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false) : 0;
+ ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false,
+ for_costs) : 0;
if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1);
/* If we have something in XEXP (x, 0), the usual case, eliminate it. */
if (XEXP (x, 0))
{
- new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true);
+ new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true,
+ for_costs);
if (new_rtx != XEXP (x, 0))
{
/* If this is a REG_DEAD note, it is not valid anymore.
REG_DEAD note for the stack or frame pointer. */
if (REG_NOTE_KIND (x) == REG_DEAD)
return (XEXP (x, 1)
- ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true)
+ ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true,
+ for_costs)
: NULL_RTX);
x = alloc_reg_note (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1));
strictly needed, but it simplifies the code. */
if (XEXP (x, 1))
{
- new_rtx = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true);
+ new_rtx = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true,
+ for_costs);
if (new_rtx != XEXP (x, 1))
return
gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new_rtx);
&& XEXP (XEXP (x, 1), 0) == XEXP (x, 0))
{
rtx new_rtx = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode,
- insn, true);
+ insn, true, for_costs);
if (new_rtx != XEXP (XEXP (x, 1), 1))
return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0),
case POPCOUNT:
case PARITY:
case BSWAP:
- new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false);
+ new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false,
+ for_costs);
if (new_rtx != XEXP (x, 0))
return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx);
return x;
new_rtx = SUBREG_REG (x);
}
else
- new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false);
+ new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false,
+ for_costs);
if (new_rtx != SUBREG_REG (x))
{
/* Our only special processing is to pass the mode of the MEM to our
recursive call and copy the flags. While we are here, handle this
case more efficiently. */
- return
- replace_equiv_address_nv (x,
- eliminate_regs_1 (XEXP (x, 0), GET_MODE (x),
- insn, true));
+
+ new_rtx = eliminate_regs_1 (XEXP (x, 0), GET_MODE (x), insn, true,
+ for_costs);
+ if (for_costs
+ && memory_address_p (GET_MODE (x), XEXP (x, 0))
+ && !memory_address_p (GET_MODE (x), new_rtx))
+ for_each_rtx (&XEXP (x, 0), note_reg_elim_costly, insn);
+
+ return replace_equiv_address_nv (x, new_rtx);
case USE:
/* Handle insn_list USE that a call to a pure function may generate. */
- new_rtx = eliminate_regs_1 (XEXP (x, 0), VOIDmode, insn, false);
+ new_rtx = eliminate_regs_1 (XEXP (x, 0), VOIDmode, insn, false,
+ for_costs);
if (new_rtx != XEXP (x, 0))
return gen_rtx_USE (GET_MODE (x), new_rtx);
return x;
{
if (*fmt == 'e')
{
- new_rtx = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false);
+ new_rtx = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false,
+ for_costs);
if (new_rtx != XEXP (x, i) && ! copied)
{
x = shallow_copy_rtx (x);
int copied_vec = 0;
for (j = 0; j < XVECLEN (x, i); j++)
{
- new_rtx = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false);
+ new_rtx = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false,
+ for_costs);
if (new_rtx != XVECEXP (x, i, j) && ! copied_vec)
{
rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
rtx
eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
{
- return eliminate_regs_1 (x, mem_mode, insn, false);
+ return eliminate_regs_1 (x, mem_mode, insn, false, false);
}
/* Scan rtx X for modifications of elimination target registers. Update
/* Companion to the above plus substitution, we can allow
invariants as the source of a plain move. */
is_set_src = false;
- if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set))
+ if (old_set
+ && recog_data.operand_loc[i] == &SET_SRC (old_set))
is_set_src = true;
in_plus = false;
if (plus_src
substed_operand[i]
= eliminate_regs_1 (recog_data.operand[i], VOIDmode,
replace ? insn : NULL_RTX,
- is_set_src || in_plus);
+ is_set_src || in_plus, false);
if (substed_operand[i] != orig_operand[i])
val = 1;
/* Terminate the search in check_eliminable_occurrences at
the pre-passes. */
if (val && REG_NOTES (insn) != 0)
REG_NOTES (insn)
- = eliminate_regs_1 (REG_NOTES (insn), VOIDmode, REG_NOTES (insn), true);
+ = eliminate_regs_1 (REG_NOTES (insn), VOIDmode, REG_NOTES (insn), true,
+ false);
return val;
}
+/* Like eliminate_regs_in_insn, but only estimate costs for the use of the
+ register allocator. INSN is the instruction we need to examine, we perform
+ eliminations in its operands and record cases where eliminating a reg with
+ an invariant equivalence would add extra cost. */
+
+static void
+elimination_costs_in_insn (rtx insn)
+{
+ int icode = recog_memoized (insn);
+ rtx old_body = PATTERN (insn);
+ int insn_is_asm = asm_noperands (old_body) >= 0;
+ rtx old_set = single_set (insn);
+ int i;
+ rtx orig_operand[MAX_RECOG_OPERANDS];
+ rtx orig_dup[MAX_RECOG_OPERANDS];
+ struct elim_table *ep;
+ rtx plus_src, plus_cst_src;
+ bool sets_reg_p;
+
+ if (! insn_is_asm && icode < 0)
+ {
+ gcc_assert (GET_CODE (PATTERN (insn)) == USE
+ || GET_CODE (PATTERN (insn)) == CLOBBER
+ || GET_CODE (PATTERN (insn)) == ADDR_VEC
+ || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+ || GET_CODE (PATTERN (insn)) == ASM_INPUT
+ || DEBUG_INSN_P (insn));
+ return;
+ }
+
+ if (old_set != 0 && REG_P (SET_DEST (old_set))
+ && REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER)
+ {
+ /* Check for setting an eliminable register. */
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate)
+ return;
+ }
+
+ /* We allow one special case which happens to work on all machines we
+ 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 = plus_cst_src = 0;
+ sets_reg_p = false;
+ if (old_set && REG_P (SET_DEST (old_set)))
+ {
+ sets_reg_p = true;
+ if (GET_CODE (SET_SRC (old_set)) == PLUS)
+ plus_src = SET_SRC (old_set);
+ /* First see if the source is of the form (plus (...) CST). */
+ if (plus_src
+ && CONST_INT_P (XEXP (plus_src, 1)))
+ plus_cst_src = plus_src;
+ else if (REG_P (SET_SRC (old_set))
+ || plus_src)
+ {
+ /* Otherwise, see if we have a REG_EQUAL note of the form
+ (plus (...) CST). */
+ rtx links;
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ {
+ if ((REG_NOTE_KIND (links) == REG_EQUAL
+ || REG_NOTE_KIND (links) == REG_EQUIV)
+ && GET_CODE (XEXP (links, 0)) == PLUS
+ && CONST_INT_P (XEXP (XEXP (links, 0), 1)))
+ {
+ plus_cst_src = XEXP (links, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Determine the effects of this insn on elimination offsets. */
+ elimination_effects (old_body, VOIDmode);
+
+ /* Eliminate all eliminable registers occurring in operands that
+ can be handled by reload. */
+ extract_insn (insn);
+ for (i = 0; i < recog_data.n_dups; i++)
+ orig_dup[i] = *recog_data.dup_loc[i];
+
+ for (i = 0; i < recog_data.n_operands; i++)
+ {
+ orig_operand[i] = recog_data.operand[i];
+
+ /* For an asm statement, every operand is eliminable. */
+ if (insn_is_asm || insn_data[icode].operand[i].eliminable)
+ {
+ bool is_set_src, in_plus;
+
+ /* Check for setting a register that we know about. */
+ if (recog_data.operand_type[i] != OP_IN
+ && REG_P (orig_operand[i]))
+ {
+ /* If we are assigning to a register that can be eliminated, it
+ must be as part of a PARALLEL, since the code above handles
+ single SETs. We must indicate that we can no longer
+ eliminate this reg. */
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS];
+ ep++)
+ if (ep->from_rtx == orig_operand[i])
+ ep->can_eliminate = 0;
+ }
+
+ /* Companion to the above plus substitution, we can allow
+ invariants as the source of a plain move. */
+ is_set_src = false;
+ if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set))
+ is_set_src = true;
+ if (is_set_src && !sets_reg_p)
+ note_reg_elim_costly (&SET_SRC (old_set), insn);
+ in_plus = false;
+ if (plus_src && sets_reg_p
+ && (recog_data.operand_loc[i] == &XEXP (plus_src, 0)
+ || recog_data.operand_loc[i] == &XEXP (plus_src, 1)))
+ in_plus = true;
+
+ eliminate_regs_1 (recog_data.operand[i], VOIDmode,
+ NULL_RTX,
+ is_set_src || in_plus, true);
+ /* Terminate the search in check_eliminable_occurrences at
+ this point. */
+ *recog_data.operand_loc[i] = 0;
+ }
+ }
+
+ for (i = 0; i < recog_data.n_dups; i++)
+ *recog_data.dup_loc[i]
+ = *recog_data.operand_loc[(int) recog_data.dup_num[i]];
+
+ /* If any eliminable remain, they aren't eliminable anymore. */
+ check_eliminable_occurrences (old_body);
+
+ /* Restore the old body. */
+ for (i = 0; i < recog_data.n_operands; i++)
+ *recog_data.operand_loc[i] = orig_operand[i];
+ for (i = 0; i < recog_data.n_dups; i++)
+ *recog_data.dup_loc[i] = orig_dup[i];
+
+ /* Update all elimination pairs to reflect the status after the current
+ insn. The changes we make were determined by the earlier call to
+ elimination_effects. */
+
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ {
+ if (ep->previous_offset != ep->offset && ep->ref_outside_mem)
+ ep->can_eliminate = 0;
+
+ ep->ref_outside_mem = 0;
+ }
+
+ return;
+}
+
/* Loop through all elimination pairs.
Recalculate the number not at initial offset.
ep->to_rtx = gen_rtx_REG (Pmode, ep->to);
}
}
+
+/* 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)
+ and cse'd or loop-moved constant memory addresses.
+
+ Record constant equivalents in reg_equiv_constant
+ so they will be substituted by find_reloads.
+ Record memory equivalents in reg_mem_equiv so they can
+ be substituted eventually by altering the REG-rtx's. */
+
+static void
+init_eliminable_invariants (rtx first, bool do_subregs)
+{
+ int i;
+ rtx insn;
+
+ reg_equiv_constant = XCNEWVEC (rtx, max_regno);
+ reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
+ reg_equiv_mem = XCNEWVEC (rtx, max_regno);
+ reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
+ reg_equiv_address = XCNEWVEC (rtx, max_regno);
+ if (do_subregs)
+ reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
+ else
+ reg_max_ref_width = NULL;
+
+ num_eliminable_invariants = 0;
+
+ first_label_num = get_first_label_num ();
+ num_labels = max_label_num () - first_label_num;
+
+ /* Allocate the tables used to store offset information at labels. */
+ offsets_known_at = XNEWVEC (char, num_labels);
+ offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
+
+/* Look for REG_EQUIV notes; record what each pseudo is equivalent
+ to. If DO_SUBREGS is true, also find all paradoxical subregs and
+ find largest such for each pseudo. FIRST is the head of the insn
+ list. */
+
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ rtx set = single_set (insn);
+
+ /* We may introduce USEs that we want to remove at the end, so
+ we'll mark them with QImode. Make sure there are no
+ previously-marked insns left by say regmove. */
+ if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE
+ && GET_MODE (insn) != VOIDmode)
+ PUT_MODE (insn, VOIDmode);
+
+ if (do_subregs && NONDEBUG_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);
+ 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)))
+ {
+ /* 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))
+ {
+ if (GET_CODE (x) == PLUS)
+ {
+ /* This is PLUS of frame pointer and a constant,
+ and might be shared. Unshare it. */
+ reg_equiv_invariant[i] = copy_rtx (x);
+ num_eliminable_invariants++;
+ }
+ else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
+ {
+ reg_equiv_invariant[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])
+ reg_equiv_init[i] = NULL_RTX;
+ }
+ }
+ else
+ {
+ reg_equiv_init[i] = NULL_RTX;
+ continue;
+ }
+ }
+ else
+ reg_equiv_init[i] = NULL_RTX;
+ }
+ }
+
+ 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");
+ }
+}
+
+/* Indicate that we no longer have known memory locations or constants.
+ Free all data involved in tracking these. */
+
+static void
+free_reg_equiv (void)
+{
+ int i;
+
+ if (reg_equiv_constant)
+ free (reg_equiv_constant);
+ if (reg_equiv_invariant)
+ free (reg_equiv_invariant);
+ reg_equiv_constant = 0;
+ reg_equiv_invariant = 0;
+ VEC_free (rtx, gc, reg_equiv_memory_loc_vec);
+ reg_equiv_memory_loc = 0;
+
+ if (offsets_known_at)
+ free (offsets_known_at);
+ if (offsets_at)
+ free (offsets_at);
+ offsets_at = 0;
+ offsets_known_at = 0;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (reg_equiv_alt_mem_list[i])
+ free_EXPR_LIST_list (®_equiv_alt_mem_list[i]);
+ free (reg_equiv_alt_mem_list);
+
+ free (reg_equiv_mem);
+ free (reg_equiv_address);
+}
\f
/* Kick all pseudos out of hard register REGNO.