#include "machmode.h"
#include "hard-reg-set.h"
-#include "rtl.h"
+#include "rtl-error.h"
#include "tm_p.h"
#include "obstack.h"
#include "insn-config.h"
#include "regs.h"
#include "addresses.h"
#include "basic-block.h"
+#include "df.h"
#include "reload.h"
#include "recog.h"
#include "output.h"
-#include "toplev.h"
#include "except.h"
#include "tree.h"
#include "ira.h"
-#include "df.h"
#include "target.h"
#include "emit-rtl.h"
fixing up each insn, and generating the new insns to copy values
into the reload registers. */
\f
+struct target_reload default_target_reload;
+#if SWITCHABLE_TARGET
+struct target_reload *this_target_reload = &default_target_reload;
+#endif
+
+#define spill_indirect_levels \
+ (this_target_reload->x_spill_indirect_levels)
+
/* 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). */
static rtx *reg_last_reload_reg;
a round-robin fashion. */
static int last_spill_reg;
-/* Nonzero if indirect addressing is supported on the machine; this means
- that spilling (REG n) does not require reloading it into a register in
- order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The
- value indicates the level of indirect addressing supported, e.g., two
- means that (MEM (MEM (REG n))) is also valid if (REG n) does not get
- a hard register. */
-static char spill_indirect_levels;
-
-/* Nonzero if indirect addressing is supported when the innermost MEM is
- of the form (MEM (SYMBOL_REF sym)). It is assumed that the level to
- which these are valid is the same as spill_indirect_levels, above. */
-char indirect_symref_ok;
-
-/* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid. */
-char double_reg_address_ok;
-
/* Record the stack slot for each spilled hard register. */
static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER];
Required by some machines to handle any generated moves differently. */
int reload_in_progress = 0;
-/* These arrays record the insn_code of insns that may be needed to
- perform input and output reloads of special objects. They provide a
- place to pass a scratch register. */
-enum insn_code reload_in_optab[NUM_MACHINE_MODES];
-enum insn_code reload_out_optab[NUM_MACHINE_MODES];
-
/* This obstack is used for allocation of rtl during register elimination.
The allocated storage can be freed once find_reloads has processed the
insn. */
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);
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 *,
if (regno < FIRST_PSEUDO_REGISTER)
return;
- x = eliminate_regs (x, mem_mode, usage);
+ x = eliminate_regs_1 (x, mem_mode, usage, true, false);
if (x != *loc)
{
*loc = x;
if (reg_equiv_constant[regno])
*loc = reg_equiv_constant[regno];
+ else if (reg_equiv_invariant[regno])
+ *loc = reg_equiv_invariant[regno];
else if (reg_equiv_mem[regno])
*loc = reg_equiv_mem[regno];
else if (reg_equiv_address[regno])
/* Now see if there's a reachable block with an exceptional incoming
edge. */
FOR_EACH_BB (bb)
- if (bb->flags & BB_REACHABLE)
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (e->flags & EDGE_ABNORMAL)
- return true;
+ if (bb->flags & BB_REACHABLE && bb_has_abnormal_pred (bb))
+ return true;
/* No exceptional block reached exit unexceptionally. */
return false;
\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. */
spill_hard_reg (from, 1);
}
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
if (frame_pointer_needed)
spill_hard_reg (HARD_FRAME_POINTER_REGNUM, 1);
#endif
}
}
- /* 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);
VEC_free (rtx_p, heap, substitute_stack);
+ gcc_assert (bitmap_empty_p (&spilled_pseudos));
+
return failure;
}
*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. */
spill_failure (rtx insn, enum reg_class rclass)
{
if (asm_noperands (PATTERN (insn)) >= 0)
- error_for_asm (insn, "can't find a register in class %qs while "
+ error_for_asm (insn, "can%'t find a register in class %qs while "
"reloading %<asm%>",
reg_class_names[rclass]);
else
static void
delete_dead_insn (rtx insn)
{
- rtx prev = prev_real_insn (insn);
+ rtx prev = prev_active_insn (insn);
rtx prev_dest;
/* If the previous insn sets a register that dies in our insn, delete it
}
}
\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;
case CLOBBER:
+ case ASM_OPERANDS:
gcc_assert (insn && DEBUG_INSN_P (insn));
break;
- case ASM_OPERANDS:
case SET:
gcc_unreachable ();
{
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
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate)
{
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
/* If this is setting the frame pointer register to the
hardware frame pointer register and this is an elimination
that will be done (tested above), this insn is really
/* 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 flag_pic and we have constant, verify it's legitimate. */
+ if (!CONSTANT_P (x)
+ || !flag_pic || 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.
Record the choices of reload reg in reload_reg_rtx. */
choose_reload_regs (chain);
- /* Merge any reloads that we didn't combine for fear of
- increasing the number of spill registers needed but now
- discover can be safely merged. */
- if (targetm.small_register_classes_for_mode_p (VOIDmode))
- merge_assigned_reloads (insn);
-
/* Generate the insns to reload operands into or out of
their reload regs. */
emit_reload_insns (chain);
subst_reloads (insn);
/* Adjust the exception region notes for loads and stores. */
- if (flag_non_call_exceptions && !CALL_P (insn))
+ if (cfun->can_throw_non_call_exceptions && !CALL_P (insn))
fixup_eh_region_note (insn, prev, next);
/* If this was an ASM, make sure that all the reload insns
return 1;
if (GET_CODE (x) == PLUS
&& (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx)
- && CONSTANT_P (XEXP (x, 1)))
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
return 1;
return 0;
}
static int
set_reload_reg (int i, int r)
{
- int regno;
+ /* regno is 'set but not used' if HARD_REGNO_MODE_OK doesn't use its first
+ parameter. */
+ int regno ATTRIBUTE_UNUSED;
rtx reg = spill_reg_rtx[i];
if (reg == 0 || GET_MODE (reg) != rld[r].mode)
take any reg in the right class and not in use.
If we want a consecutive group, here is where we look for it.
- We use two passes so we can first look for reload regs to
+ We use three passes so we can first look for reload regs to
reuse, which are already in use for other reloads in this insn,
- and only then use additional registers.
+ and only then use additional registers which are not "bad", then
+ finally any register.
+
I think that maximizing reuse is needed to make sure we don't
run out of reload regs. Suppose we have three reloads, and
reloads A and B can share regs. These need two regs.
Suppose A and B are given different regs.
That leaves none for C. */
- for (pass = 0; pass < 2; pass++)
+ for (pass = 0; pass < 3; pass++)
{
/* I is the index in spill_regs.
We advance it round-robin between insns to use all spill regs
regnum))))
{
int nr = hard_regno_nregs[regnum][rld[r].mode];
+
+ /* During the second pass we want to avoid reload registers
+ which are "bad" for this reload. */
+ if (pass == 1
+ && ira_bad_reload_regno (regnum, rld[r].in, rld[r].out))
+ continue;
+
/* 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. */
}
}
- /* If we found something on pass 1, omit pass 2. */
+ /* If we found something on the current pass, omit later passes. */
if (count < n_spills)
break;
}
register, we might use it for reload_override_in,
if copying it to the desired class is cheap
enough. */
- || ((REGISTER_MOVE_COST (mode, last_class, rclass)
- < MEMORY_MOVE_COST (mode, rclass, 1))
+ || ((register_move_cost (mode, last_class, rclass)
+ < memory_move_cost (mode, rclass, true))
&& (secondary_reload_class (1, rclass, mode,
last_reg)
== NO_REGS)
reload_spill_index[r] = -1;
}
\f
-/* If the small_register_classes_for_mode_p target hook returns true for
- some machine modes, we may not have merged two reloads of the same item
- for fear that we might not have enough reload registers. However,
- normally they will get the same reload register and hence actually need
- not be loaded twice.
-
- Here we check for the most common case of this phenomenon: when we have
- a number of reloads for the same object, each of which were allocated
- the same reload_reg_rtx, that reload_reg_rtx is not used for any other
- reload, and is not modified in the insn itself. If we find such,
- merge all the reloads and set the resulting reload to RELOAD_OTHER.
- This will not increase the number of spill registers needed and will
- prevent redundant code. */
-
-static void
-merge_assigned_reloads (rtx insn)
-{
- int i, j;
-
- /* Scan all the reloads looking for ones that only load values and
- are not already RELOAD_OTHER and ones whose reload_reg_rtx are
- assigned and not modified by INSN. */
-
- for (i = 0; i < n_reloads; i++)
- {
- int conflicting_input = 0;
- int max_input_address_opnum = -1;
- int min_conflicting_input_opnum = MAX_RECOG_OPERANDS;
-
- if (rld[i].in == 0 || rld[i].when_needed == RELOAD_OTHER
- || rld[i].out != 0 || rld[i].reg_rtx == 0
- || reg_set_p (rld[i].reg_rtx, insn))
- continue;
-
- /* Look at all other reloads. Ensure that the only use of this
- reload_reg_rtx is in a reload that just loads the same value
- as we do. Note that any secondary reloads must be of the identical
- class since the values, modes, and result registers are the
- same, so we need not do anything with any secondary reloads. */
-
- for (j = 0; j < n_reloads; j++)
- {
- if (i == j || rld[j].reg_rtx == 0
- || ! reg_overlap_mentioned_p (rld[j].reg_rtx,
- rld[i].reg_rtx))
- continue;
-
- if (rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- && rld[j].opnum > max_input_address_opnum)
- max_input_address_opnum = rld[j].opnum;
-
- /* If the reload regs aren't exactly the same (e.g, different modes)
- or if the values are different, we can't merge this reload.
- But if it is an input reload, we might still merge
- RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS reloads. */
-
- if (! rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx)
- || rld[j].out != 0 || rld[j].in == 0
- || ! rtx_equal_p (rld[i].in, rld[j].in))
- {
- if (rld[j].when_needed != RELOAD_FOR_INPUT
- || ((rld[i].when_needed != RELOAD_FOR_INPUT_ADDRESS
- || rld[i].opnum > rld[j].opnum)
- && rld[i].when_needed != RELOAD_FOR_OTHER_ADDRESS))
- break;
- conflicting_input = 1;
- if (min_conflicting_input_opnum > rld[j].opnum)
- min_conflicting_input_opnum = rld[j].opnum;
- }
- }
-
- /* If all is OK, merge the reloads. Only set this to RELOAD_OTHER if
- we, in fact, found any matching reloads. */
-
- if (j == n_reloads
- && max_input_address_opnum <= min_conflicting_input_opnum)
- {
- gcc_assert (rld[i].when_needed != RELOAD_FOR_OUTPUT);
-
- for (j = 0; j < n_reloads; j++)
- if (i != j && rld[j].reg_rtx != 0
- && rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx)
- && (! conflicting_input
- || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- || rld[j].when_needed == RELOAD_FOR_OTHER_ADDRESS))
- {
- rld[i].when_needed = RELOAD_OTHER;
- rld[j].in = 0;
- reload_spill_index[j] = -1;
- transfer_replacements (i, j);
- }
-
- /* If this is now RELOAD_OTHER, look for any reloads that
- load parts of this operand and set them to
- RELOAD_FOR_OTHER_ADDRESS if they were for inputs,
- RELOAD_OTHER for outputs. Note that this test is
- equivalent to looking for reloads for this operand
- number.
-
- We must take special care with RELOAD_FOR_OUTPUT_ADDRESS;
- it may share registers with a RELOAD_FOR_INPUT, so we can
- not change it to RELOAD_FOR_OTHER_ADDRESS. We should
- never need to, since we do not modify RELOAD_FOR_OUTPUT.
-
- It is possible that the RELOAD_FOR_OPERAND_ADDRESS
- instruction is assigned the same register as the earlier
- RELOAD_FOR_OTHER_ADDRESS instruction. Merging these two
- instructions will cause the RELOAD_FOR_OTHER_ADDRESS
- instruction to be deleted later on. */
-
- if (rld[i].when_needed == RELOAD_OTHER)
- for (j = 0; j < n_reloads; j++)
- if (rld[j].in != 0
- && rld[j].when_needed != RELOAD_OTHER
- && rld[j].when_needed != RELOAD_FOR_OTHER_ADDRESS
- && rld[j].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
- && rld[j].when_needed != RELOAD_FOR_OPERAND_ADDRESS
- && (! conflicting_input
- || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
- && reg_overlap_mentioned_for_reload_p (rld[j].in,
- rld[i].in))
- {
- int k;
-
- rld[j].when_needed
- = ((rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- || 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. */
- if (rld[j].reg_rtx)
- for (k = 0; k < j; k++)
- gcc_assert (rld[k].in == 0 || rld[k].reg_rtx == 0
- || rld[k].when_needed != rld[j].when_needed
- || !rtx_equal_p (rld[k].reg_rtx,
- rld[j].reg_rtx)
- || rtx_equal_p (rld[k].in,
- rld[j].in));
- }
- }
- }
-}
-\f
/* These arrays are filled by emit_reload_insns and its subroutines. */
static rtx input_reload_insns[MAX_RECOG_OPERANDS];
static rtx other_input_address_reload_insns = 0;
sri.icode = CODE_FOR_nothing;
sri.prev_sri = NULL;
- new_class = targetm.secondary_reload (1, real_oldequiv, rl->rclass,
- mode, &sri);
+ new_class
+ = (enum reg_class) targetm.secondary_reload (1, real_oldequiv,
+ rl->rclass, mode,
+ &sri);
if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing)
second_reload_reg = 0;
{
sri2.icode = CODE_FOR_nothing;
sri2.prev_sri = &sri;
- new_t_class = targetm.secondary_reload (1, real_oldequiv,
- new_class, mode, &sri);
+ new_t_class
+ = (enum reg_class) targetm.secondary_reload (1, real_oldequiv,
+ new_class, mode,
+ &sri);
if (new_t_class == NO_REGS && sri2.icode == CODE_FOR_nothing)
{
if (reload_adjust_reg_for_temp (&second_reload_reg,
|| (reg_equiv_constant
[REGNO (SUBREG_REG (oldequiv))] != 0)))
|| (CONSTANT_P (oldequiv)
- && (PREFERRED_RELOAD_CLASS (oldequiv,
- REGNO_REG_CLASS (REGNO (reloadreg)))
+ && (targetm.preferred_reload_class (oldequiv,
+ REGNO_REG_CLASS (REGNO (reloadreg)))
== NO_REGS)))
real_oldequiv = rl->in;
gen_reload (reloadreg, real_oldequiv, rl->opnum,
rl->when_needed);
}
- if (flag_non_call_exceptions)
+ if (cfun->can_throw_non_call_exceptions)
copy_reg_eh_region_note_forward (insn, get_insns (), NULL);
/* End this sequence. */
else
output_reload_insns[rl->opnum] = get_insns ();
- if (flag_non_call_exceptions)
+ if (cfun->can_throw_non_call_exceptions)
copy_reg_eh_region_note_forward (insn, get_insns (), NULL);
end_sequence ();
DEFINE_PEEPHOLE should be specified that recognizes the sequence
we emit below. */
- code = (int) optab_handler (add_optab, GET_MODE (out))->insn_code;
+ code = (int) optab_handler (add_optab, GET_MODE (out));
if (CONSTANT_P (op1) || MEM_P (op1) || GET_CODE (op1) == SUBREG
|| (REG_P (op1)
return insn;
}
- fatal_insn ("Failure trying to reload:", set);
+ fatal_insn ("failure trying to reload:", set);
}
/* If IN is a simple operand, use gen_move_insn. */
else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
int n_inherited = 0;
rtx i1;
rtx substed;
+ unsigned regno;
+ int nregs;
/* It is possible that this reload has been only used to set another reload
we eliminated earlier and thus deleted this instruction too. */
if (n_occurrences > n_inherited)
return;
+ regno = REGNO (reg);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ nregs = 1;
+ else
+ nregs = hard_regno_nregs[regno][GET_MODE (reg)];
+
/* If the pseudo-reg we are reloading is no longer referenced
anywhere between the store into it and here,
and we're within the same basic block, then the value can only
if (NOTE_INSN_BASIC_BLOCK_P (i1))
return;
if ((NONJUMP_INSN_P (i1) || CALL_P (i1))
- && reg_mentioned_p (reg, PATTERN (i1)))
+ && refers_to_regno_p (regno, regno + nregs, PATTERN (i1), NULL))
{
/* If this is USE in front of INSN, we only have to check that
there are no more references than accounted for by inheritance. */
BB_END (bb) = insn;
insn = NEXT_INSN (insn);
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_FALLTHRU)
- break;
+ e = find_fallthru_edge (bb->succs);
while (insn && insn != stop)
{
}
/* We've possibly turned single trapping insn into multiple ones. */
- if (flag_non_call_exceptions)
+ if (cfun->can_throw_non_call_exceptions)
{
sbitmap blocks;
blocks = sbitmap_alloc (last_basic_block);