#include "insn-config.h"
#include "ggc.h"
#include "flags.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "vec.h"
+#include "input.h"
#include "function.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "regs.h"
#include "addresses.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfgbuild.h"
#include "basic-block.h"
#include "df.h"
#include "reload.h"
#include "target.h"
#include "emit-rtl.h"
#include "dumpfile.h"
+#include "rtl-iter.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
/* During reload_as_needed, element N contains the insn for which
hard register N was last used. Its contents are significant only
when reg_reloaded_valid is set for this register. */
-static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER];
+static rtx_insn *reg_reloaded_insn[FIRST_PSEUDO_REGISTER];
/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid. */
static HARD_REG_SET reg_reloaded_valid;
/* In parallel with spill_regs, contains nonzero for a spill reg
that was stored after the last time it was used.
The precise value is the insn generated to do the store. */
-static rtx spill_reg_store[FIRST_PSEUDO_REGISTER];
+static rtx_insn *spill_reg_store[FIRST_PSEUDO_REGISTER];
/* This is the register that was stored with spill_reg_store. This is a
copy of reload_out / reload_out_reg when the value was stored; if
static int num_labels;
\f
-static void replace_pseudos_in (rtx *, enum machine_mode, rtx);
+static void replace_pseudos_in (rtx *, 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 void select_reload_regs (void);
static void delete_caller_save_insns (void);
-static void spill_failure (rtx, enum reg_class);
+static void spill_failure (rtx_insn *, enum reg_class);
static void count_spilled_pseudo (int, int, int);
-static void delete_dead_insn (rtx);
+static void delete_dead_insn (rtx_insn *);
static void alter_reg (int, int, bool);
-static void set_label_offsets (rtx, rtx, int);
+static void set_label_offsets (rtx, rtx_insn *, 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 elimination_effects (rtx, machine_mode);
+static rtx eliminate_regs_1 (rtx, machine_mode, rtx, bool, bool);
+static int eliminate_regs_in_insn (rtx_insn *, int);
static void update_eliminable_offsets (void);
static void mark_not_eliminable (rtx, const_rtx, void *);
static void set_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_eliminable_invariants (rtx, bool);
+static void set_offsets_for_label (rtx_insn *);
+static void init_eliminable_invariants (rtx_insn *, bool);
static void init_elim_table (void);
static void free_reg_equiv (void);
static void update_eliminables (HARD_REG_SET *);
static bool update_eliminables_and_spill (void);
-static void elimination_costs_in_insn (rtx);
+static void elimination_costs_in_insn (rtx_insn *);
static void spill_hard_reg (unsigned int, int);
static int finish_spills (int);
static void scan_paradoxical_subregs (rtx);
static void forget_marked_reloads (regset);
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);
+ machine_mode);
static void clear_reload_reg_in_use (unsigned int, int, enum reload_type,
- enum machine_mode);
+ 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,
+static int free_for_value_p (int, machine_mode, int, enum reload_type,
rtx, rtx, int, int);
static int allocate_reload_reg (struct insn_chain *, int, int);
static int conflicts_with_override (rtx);
-static void failed_reload (rtx, int);
+static void failed_reload (rtx_insn *, 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 do_input_reload (struct insn_chain *, struct reload *, int);
static void do_output_reload (struct insn_chain *, struct reload *, int);
static void emit_reload_insns (struct insn_chain *);
-static void delete_output_reload (rtx, int, int, rtx);
-static void delete_address_reloads (rtx, rtx);
-static void delete_address_reloads_1 (rtx, rtx, rtx);
+static void delete_output_reload (rtx_insn *, int, int, rtx);
+static void delete_address_reloads (rtx_insn *, rtx_insn *);
+static void delete_address_reloads_1 (rtx_insn *, rtx, rtx_insn *);
static void inc_for_reload (rtx, rtx, rtx, int);
#ifdef AUTO_INC_DEC
-static void add_auto_inc_notes (rtx, rtx);
+static void add_auto_inc_notes (rtx_insn *, rtx);
#endif
static void substitute (rtx *, const_rtx, rtx);
static bool gen_reload_chain_without_interm_reg_p (int, int);
static int reloads_conflict (int, int);
-static rtx gen_reload (rtx, rtx, int, enum reload_type);
-static rtx emit_insn_if_valid_for_reload (rtx);
+static rtx_insn *gen_reload (rtx, rtx, int, enum reload_type);
+static rtx_insn *emit_insn_if_valid_for_reload (rtx);
\f
/* Initialize the reload pass. This is called at the beginning of compilation
and may be called again if the target is reinitialized. */
equivalences. */
static void
-replace_pseudos_in (rtx *loc, enum machine_mode mem_mode, rtx usage)
+replace_pseudos_in (rtx *loc, machine_mode mem_mode, rtx usage)
{
rtx x = *loc;
enum rtx_code code;
/* Temporary array of pseudo-register number. */
static int *temp_pseudo_reg_arr;
+/* If a pseudo has no hard reg, delete the insns that made the equivalence.
+ If that insn didn't set the register (i.e., it copied the register to
+ memory), just delete that insn instead of the equivalencing insn plus
+ anything now dead. If we call delete_dead_insn on that insn, we may
+ delete the insn that actually sets the register if the register dies
+ there and that is incorrect. */
+static void
+remove_init_insns ()
+{
+ for (int i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ {
+ if (reg_renumber[i] < 0 && reg_equiv_init (i) != 0)
+ {
+ rtx list;
+ for (list = reg_equiv_init (i); list; list = XEXP (list, 1))
+ {
+ rtx_insn *equiv_insn = as_a <rtx_insn *> (XEXP (list, 0));
+
+ /* If we already deleted the insn or if it may trap, we can't
+ delete it. The latter case shouldn't happen, but can
+ if an insn has a variable address, gets a REG_EH_REGION
+ note added to it, and then gets converted into a load
+ from a constant address. */
+ if (NOTE_P (equiv_insn)
+ || can_throw_internal (equiv_insn))
+ ;
+ else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
+ delete_dead_insn (equiv_insn);
+ else
+ SET_INSN_DELETED (equiv_insn);
+ }
+ }
+ }
+}
+
+/* Return true if remove_init_insns will delete INSN. */
+static bool
+will_delete_init_insn_p (rtx_insn *insn)
+{
+ rtx set = single_set (insn);
+ if (!set || !REG_P (SET_DEST (set)))
+ return false;
+ unsigned regno = REGNO (SET_DEST (set));
+
+ if (can_throw_internal (insn))
+ return false;
+
+ if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+ return false;
+
+ for (rtx list = reg_equiv_init (regno); list; list = XEXP (list, 1))
+ {
+ rtx equiv_insn = XEXP (list, 0);
+ if (equiv_insn == insn)
+ return true;
+ }
+ return false;
+}
+
/* Main entry point for the reload pass.
FIRST is the first insn of the function being compiled.
return value is FALSE. */
bool
-reload (rtx first, int global)
+reload (rtx_insn *first, int global)
{
int i, n;
- rtx insn;
+ rtx_insn *insn;
struct elim_table *ep;
basic_block bb;
bool inserted;
if (ep->can_eliminate)
mark_elimination (ep->from, ep->to);
- /* If a pseudo has no hard reg, delete the insns that made the equivalence.
- If that insn didn't set the register (i.e., it copied the register to
- memory), just delete that insn instead of the equivalencing insn plus
- anything now dead. If we call delete_dead_insn on that insn, we may
- delete the insn that actually sets the register if the register dies
- there and that is incorrect. */
-
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- {
- if (reg_renumber[i] < 0 && reg_equiv_init (i) != 0)
- {
- rtx list;
- for (list = reg_equiv_init (i); list; list = XEXP (list, 1))
- {
- rtx equiv_insn = XEXP (list, 0);
-
- /* If we already deleted the insn or if it may trap, we can't
- delete it. The latter case shouldn't happen, but can
- if an insn has a variable address, gets a REG_EH_REGION
- note added to it, and then gets converted into a load
- from a constant address. */
- if (NOTE_P (equiv_insn)
- || can_throw_internal (equiv_insn))
- ;
- else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
- delete_dead_insn (equiv_insn);
- else
- SET_INSN_DELETED (equiv_insn);
- }
- }
- }
+ remove_init_insns ();
/* Use the reload registers where necessary
by generating move instructions to move the must-be-register
if (asm_noperands (PATTERN (insn)) >= 0)
{
extract_insn (insn);
- if (!constrain_operands (1))
+ if (!constrain_operands (1, get_enabled_alternatives (insn)))
{
error_for_asm (insn,
"%<asm%> operand has impossible constraints");
{
#ifdef STACK_REGS
const char *constraints[MAX_RECOG_OPERANDS];
- enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+ machine_mode operand_mode[MAX_RECOG_OPERANDS];
struct insn_chain *chain;
for (chain = reload_insn_chain; chain != 0; chain = chain->next)
switch (c)
{
- case '=': case '+': case '*': case '%': case '?': case '!':
- case '0': case '1': case '2': case '3': case '4': case '<':
- case '>': case 'V': case 'o': case '&': case 'E': case 'F':
- case 's': case 'i': case 'n': case 'X': case 'I': case 'J':
- case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
- case TARGET_MEM_CONSTRAINT:
- break;
-
- case 'p':
- cls = (int) reg_class_subunion[cls]
- [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
- ADDRESS, SCRATCH)];
- break;
-
case 'g':
- case 'r':
cls = (int) reg_class_subunion[cls][(int) GENERAL_REGS];
break;
default:
- if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+ enum constraint_num cn = lookup_constraint (p);
+ if (insn_extra_address_constraint (cn))
cls = (int) reg_class_subunion[cls]
[(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
ADDRESS, SCRATCH)];
else
cls = (int) reg_class_subunion[cls]
- [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
+ [reg_class_for_constraint (cn)];
+ break;
}
p += CONSTRAINT_LEN (c, p);
}
reload_insn_firstobj = XOBNEWVAR (&reload_obstack, char, 0);
for (chain = reload_insn_chain; chain != 0; chain = next)
{
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
next = chain->next;
rtx old_notes = REG_NOTES (insn);
int did_elimination = 0;
int operands_changed = 0;
- 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)))))
- && reg_equiv_init (REGNO (SET_DEST (set))))
+ if (will_delete_init_insn_p (insn))
continue;
/* If needed, eliminate any eliminable registers. */
FOR_EACH_BB_FN (bb, cfun)
{
- rtx insn;
+ rtx_insn *insn;
elim_bb = bb;
FOR_BB_INSNS (bb, insn)
while (c != 0 && c->is_caller_save_insn)
{
struct insn_chain *next = c->next;
- rtx insn = c->insn;
+ rtx_insn *insn = c->insn;
if (c == reload_insn_chain)
reload_insn_chain = next;
INSN should be one of the insns which needed this particular spill reg. */
static void
-spill_failure (rtx insn, enum reg_class rclass)
+spill_failure (rtx_insn *insn, enum reg_class rclass)
{
if (asm_noperands (PATTERN (insn)) >= 0)
error_for_asm (insn, "can%'t find a register in class %qs while "
data that is dead in INSN. */
static void
-delete_dead_insn (rtx insn)
+delete_dead_insn (rtx_insn *insn)
{
- rtx prev = prev_active_insn (insn);
+ rtx_insn *prev = prev_active_insn (insn);
rtx prev_dest;
/* If the previous insn sets a register that dies in our insn make
&& reg_equiv_memory_loc (i) == 0)
{
rtx x = NULL_RTX;
- enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
+ machine_mode mode = GET_MODE (regno_reg_rtx[i]);
unsigned int inherent_size = PSEUDO_REGNO_BYTES (i);
unsigned int inherent_align = GET_MODE_ALIGNMENT (mode);
unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]);
pseudo-reg number REGNO, accessed in MODE. */
static void
-mark_home_live_1 (int regno, enum machine_mode mode)
+mark_home_live_1 (int regno, machine_mode mode)
{
int i, lim;
current offset. */
static void
-set_label_offsets (rtx x, rtx insn, int initial_p)
+set_label_offsets (rtx x, rtx_insn *insn, int initial_p)
{
enum rtx_code code = GET_CODE (x);
rtx tem;
if (LABEL_REF_NONLOCAL_P (x))
return;
- x = XEXP (x, 0);
+ x = LABEL_REF_LABEL (x);
/* ... fall through ... */
case IF_THEN_ELSE:
tem = XEXP (SET_SRC (x), 1);
if (GET_CODE (tem) == LABEL_REF)
- set_label_offsets (XEXP (tem, 0), insn, initial_p);
+ set_label_offsets (LABEL_REF_LABEL (tem), insn, initial_p);
else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN)
break;
tem = XEXP (SET_SRC (x), 2);
if (GET_CODE (tem) == LABEL_REF)
- set_label_offsets (XEXP (tem, 0), insn, initial_p);
+ set_label_offsets (LABEL_REF_LABEL (tem), insn, initial_p);
else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN)
break;
return;
}
}
\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. */
+/* This function examines every reg that occurs in X and adjusts the
+ costs for its elimination which are gathered by IRA. INSN is the
+ insn in which X occurs. We do not recurse into MEM expressions. */
-static int
-note_reg_elim_costly (rtx *px, void *data)
+static void
+note_reg_elim_costly (const_rtx x, rtx insn)
{
- 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 = set_src_cost (new_rtx, optimize_bb_for_speed_p (elim_bb));
- int freq = REG_FREQ_FROM_BB (elim_bb);
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, NONCONST)
+ {
+ const_rtx x = *iter;
+ if (MEM_P (x))
+ iter.skip_subrtxes ();
+ else 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 = set_src_cost (new_rtx, 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);
+ 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
the proper thing. */
static rtx
-eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
+eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn,
bool may_use_invariant, bool for_costs)
{
enum rtx_code code = GET_CODE (x);
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);
+ note_reg_elim_costly (XEXP (x, 0), insn);
return replace_equiv_address_nv (x, new_rtx);
}
rtx
-eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
+eliminate_regs (rtx x, machine_mode mem_mode, rtx insn)
{
+ if (reg_eliminate == NULL)
+ {
+ gcc_assert (targetm.no_register_allocation);
+ return x;
+ }
return eliminate_regs_1 (x, mem_mode, insn, false, false);
}
the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM. */
static void
-elimination_effects (rtx x, enum machine_mode mem_mode)
+elimination_effects (rtx x, machine_mode mem_mode)
{
enum rtx_code code = GET_CODE (x);
struct elim_table *ep;
is returned. Otherwise, 1 is returned. */
static int
-eliminate_regs_in_insn (rtx insn, int replace)
+eliminate_regs_in_insn (rtx_insn *insn, int replace)
{
int icode = recog_memoized (insn);
rtx old_body = PATTERN (insn);
&& ep->to == HARD_FRAME_POINTER_REGNUM)
{
rtx base = SET_SRC (old_set);
- rtx base_insn = insn;
+ rtx_insn *base_insn = insn;
HOST_WIDE_INT offset = 0;
while (base != ep->to_rtx)
{
- rtx prev_insn, prev_set;
+ rtx_insn *prev_insn;
+ rtx prev_set;
if (GET_CODE (base) == PLUS
&& CONST_INT_P (XEXP (base, 1)))
an invariant equivalence would add extra cost. */
static void
-elimination_costs_in_insn (rtx insn)
+elimination_costs_in_insn (rtx_insn *insn)
{
int icode = recog_memoized (insn);
rtx old_body = PATTERN (insn);
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);
+ 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)
static void
set_initial_eh_label_offset (rtx label)
{
- set_label_offsets (label, NULL_RTX, 1);
+ set_label_offsets (label, NULL, 1);
}
/* Initialize the known label offsets.
static void
set_initial_label_offsets (void)
{
- rtx x;
memset (offsets_known_at, 0, num_labels);
- for (x = forced_labels; x; x = XEXP (x, 1))
- if (XEXP (x, 0))
- set_label_offsets (XEXP (x, 0), NULL_RTX, 1);
+ for (rtx_insn_list *x = forced_labels; x; x = x->next ())
+ if (x->insn ())
+ set_label_offsets (x->insn (), NULL, 1);
- for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
- if (XEXP (x, 0))
- set_label_offsets (XEXP (x, 0), NULL_RTX, 1);
+ for (rtx_insn_list *x = nonlocal_goto_handler_labels; x; x = x->next ())
+ if (x->insn ())
+ set_label_offsets (x->insn (), NULL, 1);
for_each_eh_label (set_initial_eh_label_offset);
}
by INSN. */
static void
-set_offsets_for_label (rtx insn)
+set_offsets_for_label (rtx_insn *insn)
{
unsigned int i;
int label_nr = CODE_LABEL_NUMBER (insn);
be substituted eventually by altering the REG-rtx's. */
static void
-init_eliminable_invariants (rtx first, bool do_subregs)
+init_eliminable_invariants (rtx_insn *first, bool do_subregs)
{
int i;
- rtx insn;
+ rtx_insn *insn;
grow_reg_equivs ();
if (do_subregs)
}
else if (function_invariant_p (x))
{
- enum machine_mode mode;
+ machine_mode mode;
mode = GET_MODE (SET_DEST (set));
if (GET_CODE (x) == PLUS)
annotate all that may trap. */
static void
-fixup_eh_region_note (rtx insn, rtx prev, rtx next)
+fixup_eh_region_note (rtx_insn *insn, rtx_insn *prev, rtx_insn *next)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
if (note == NULL)
#if defined (AUTO_INC_DEC)
int i;
#endif
- rtx x, marker;
+ rtx_note *marker;
memset (spill_reg_rtx, 0, sizeof spill_reg_rtx);
memset (spill_reg_store, 0, sizeof spill_reg_store);
for (chain = reload_insn_chain; chain; chain = chain->next)
{
- rtx prev = 0;
- rtx insn = chain->insn;
- rtx old_next = NEXT_INSN (insn);
+ rtx_insn *prev = 0;
+ rtx_insn *insn = chain->insn;
+ rtx_insn *old_next = NEXT_INSN (insn);
#ifdef AUTO_INC_DEC
- rtx old_prev = PREV_INSN (insn);
+ rtx_insn *old_prev = PREV_INSN (insn);
#endif
+ if (will_delete_init_insn_p (insn))
+ continue;
+
/* If we pass a label, copy the offsets from the label information
into the current offsets of each elimination. */
if (LABEL_P (insn))
if (n_reloads > 0)
{
- rtx next = NEXT_INSN (insn);
- rtx p;
+ rtx_insn *next = NEXT_INSN (insn);
/* ??? PREV can get deleted by reload inheritance.
Work around this by emitting a marker note. */
fixup_eh_region_note (insn, prev, next);
/* Adjust the location of REG_ARGS_SIZE. */
- p = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
+ rtx p = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
if (p)
{
remove_note (insn, p);
we have generated are valid. If not, give an error
and delete them. */
if (asm_noperands (PATTERN (insn)) >= 0)
- for (p = NEXT_INSN (prev); p != next; p = NEXT_INSN (p))
+ for (rtx_insn *p = NEXT_INSN (prev);
+ p != next;
+ p = NEXT_INSN (p))
if (p != insn && INSN_P (p)
&& GET_CODE (PATTERN (p)) != USE
&& (recog_memoized (p) < 0
- || (extract_insn (p), ! constrain_operands (1))))
+ || (extract_insn (p),
+ !(constrain_operands (1,
+ get_enabled_alternatives (p))))))
{
error_for_asm (insn,
"%<asm%> operand requires "
/* There may have been CLOBBER insns placed after INSN. So scan
between INSN and NEXT and use them to forget old reloads. */
- for (x = NEXT_INSN (insn); x != old_next; x = NEXT_INSN (x))
+ for (rtx_insn *x = NEXT_INSN (insn); x != old_next; x = NEXT_INSN (x))
if (NONJUMP_INSN_P (x) && GET_CODE (PATTERN (x)) == CLOBBER)
note_stores (PATTERN (x), forget_old_reloads_1, NULL);
{
rtx reload_reg = rld[i].reg_rtx;
- enum machine_mode mode = GET_MODE (reload_reg);
+ machine_mode mode = GET_MODE (reload_reg);
int n = 0;
- rtx p;
+ rtx_insn *p;
for (p = PREV_INSN (old_next); p != prev; p = PREV_INSN (p))
{
if (n)
{
extract_insn (p);
- n = constrain_operands (1);
+ n = constrain_operands (1,
+ get_enabled_alternatives (p));
}
/* If the constraints were not met, then
if (TEST_HARD_REG_BIT (reg_reloaded_valid,
in_hard_regno))
{
- for (x = old_prev ? NEXT_INSN (old_prev) : insn;
+ for (rtx_insn *x = (old_prev ?
+ NEXT_INSN (old_prev) : insn);
x != old_next;
x = NEXT_INSN (x))
if (x == reg_reloaded_insn[in_hard_regno])
/* If a pseudo that got a hard register is auto-incremented,
we must purge records of copying it into pseudos without
hard registers. */
- for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+ for (rtx x = REG_NOTES (insn); x; x = XEXP (x, 1))
if (REG_NOTE_KIND (x) == REG_INC)
{
/* See if this pseudo reg was reloaded in this insn.
static void
mark_reload_reg_in_use (unsigned int regno, int opnum, enum reload_type type,
- enum machine_mode mode)
+ machine_mode mode)
{
switch (type)
{
static void
clear_reload_reg_in_use (unsigned int regno, int opnum,
- enum reload_type type, enum machine_mode mode)
+ enum reload_type type, machine_mode mode)
{
unsigned int nregs = hard_regno_nregs[regno][mode];
unsigned int start_regno, end_regno, r;
chain reloads or do need an intermediate hard registers. */
bool result = true;
int regno, n, code;
- rtx out, in, insn;
- rtx last = get_last_insn ();
+ rtx out, in;
+ rtx_insn *insn;
+ rtx_insn *last = get_last_insn ();
/* Make r2 a component of r1. */
if (reg_mentioned_p (rld[r1].in, rld[r2].in))
/* We want constrain operands to treat this insn strictly in
its validity determination, i.e., the way it would after
reload has completed. */
- result = constrain_operands (1);
+ result = constrain_operands (1, get_enabled_alternatives (insn));
}
delete_insns_since (last);
/* For an inherited reload, this is the insn the reload was inherited from,
if we know it. Otherwise, this is 0. */
-static rtx reload_inheritance_insn[MAX_RELOADS];
+static rtx_insn *reload_inheritance_insn[MAX_RELOADS];
/* If nonzero, this is a place to get the value of the reload,
rather than using reload_in. */
register. */
static int
-free_for_value_p (int regno, enum machine_mode mode, int opnum,
+free_for_value_p (int regno, machine_mode mode, int opnum,
enum reload_type type, rtx value, rtx out, int reloadnum,
int ignore_address_reloads)
{
/* Give an error message saying we failed to find a reload for INSN,
and clear out reload R. */
static void
-failed_reload (rtx insn, int r)
+failed_reload (rtx_insn *insn, int r)
{
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
This used to be one `if', but Sequent compiler can't handle that. */
if (HARD_REGNO_MODE_OK (regno, rld[r].mode))
{
- enum machine_mode test_mode = VOIDmode;
+ machine_mode test_mode = VOIDmode;
if (rld[r].in)
test_mode = GET_MODE (rld[r].in);
/* If rld[r].in has VOIDmode, it means we will load it
otherwise it is NULL. */
static int
-compute_reload_subreg_offset (enum machine_mode outermode,
+compute_reload_subreg_offset (machine_mode outermode,
rtx subreg,
- enum machine_mode innermode)
+ machine_mode innermode)
{
int outer_offset;
- enum machine_mode middlemode;
+ machine_mode middlemode;
if (!subreg)
return subreg_lowpart_offset (outermode, innermode);
static void
choose_reload_regs (struct insn_chain *chain)
{
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
int i, j;
unsigned int max_group_size = 1;
enum reg_class group_class = NO_REGS;
{
int byte = 0;
int regno = -1;
- enum machine_mode mode = VOIDmode;
+ machine_mode mode = VOIDmode;
rtx subreg = NULL_RTX;
if (rld[r].in == 0)
We must clear it, since otherwise emit_reload_insns
might delete the store. */
if (! TEST_HARD_REG_BIT (reg_reloaded_valid, regno))
- spill_reg_store[regno] = NULL_RTX;
+ spill_reg_store[regno] = NULL;
/* If any of the hard registers in EQUIV are spill
registers, mark them as in use for this insn. */
for (k = 0; k < nr; k++)
}
\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;
-static rtx other_input_reload_insns = 0;
-static rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
-static rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
-static rtx output_reload_insns[MAX_RECOG_OPERANDS];
-static rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
-static rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
-static rtx operand_reload_insns = 0;
-static rtx other_operand_reload_insns = 0;
-static rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *input_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *other_input_address_reload_insns = 0;
+static rtx_insn *other_input_reload_insns = 0;
+static rtx_insn *input_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *output_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *output_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx_insn *operand_reload_insns = 0;
+static rtx_insn *other_operand_reload_insns = 0;
+static rtx_insn *other_output_reload_insns[MAX_RECOG_OPERANDS];
/* Values to be put in spill_reg_store are put here first. Instructions
must only be placed here if the associated reload register reaches
the end of the instruction's reload sequence. */
-static rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
+static rtx_insn *new_spill_reg_store[FIRST_PSEUDO_REGISTER];
static HARD_REG_SET reg_reloaded_died;
/* Check if *RELOAD_REG is suitable as an intermediate or scratch register
static bool
reload_adjust_reg_for_temp (rtx *reload_reg, rtx alt_reload_reg,
enum reg_class new_class,
- enum machine_mode new_mode)
+ machine_mode new_mode)
{
rtx reg;
{
enum reg_class new_class = scratch_reload_class (icode);
- enum machine_mode new_mode = insn_data[(int) icode].operand[2].mode;
+ machine_mode new_mode = insn_data[(int) icode].operand[2].mode;
return reload_adjust_reg_for_temp (reload_reg, alt_reload_reg,
new_class, new_mode);
emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
rtx old, int j)
{
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
rtx reloadreg;
rtx oldequiv_reg = 0;
rtx oldequiv = 0;
int special = 0;
- enum machine_mode mode;
- rtx *where;
+ machine_mode mode;
+ rtx_insn **where;
/* delete_output_reload is only invoked properly if old contains
the original pseudo register. Since this is replaced with a
&& free_for_value_p (REGNO (reloadreg), rl->mode, rl->opnum,
rl->when_needed, old, rl->out, j, 0))
{
- rtx temp = PREV_INSN (insn);
+ rtx_insn *temp = PREV_INSN (insn);
while (temp && (NOTE_P (temp) || DEBUG_INSN_P (temp)))
temp = PREV_INSN (temp);
if (temp
autoincrement addressing mode, then the resulting insn
is ill-formed and we must reject this optimization. */
extract_insn (temp);
- if (constrain_operands (1)
+ if (constrain_operands (1, get_enabled_alternatives (temp))
#ifdef AUTO_INC_DEC
&& ! find_reg_note (temp, REG_INC, reloadreg)
#endif
int j)
{
rtx reloadreg;
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
int special = 0;
rtx old = rl->out;
- enum machine_mode mode;
- rtx p;
+ machine_mode mode;
+ rtx_insn *p;
rtx rl_reg_rtx;
if (rl->when_needed == RELOAD_OTHER)
that it is, setting new_spill_reg_store to
that insn will allow an extra optimization. */
rtx s_reg = rld[s].reg_rtx;
- rtx next = NEXT_INSN (p);
+ rtx_insn *next = NEXT_INSN (p);
rld[s].out = rl->out;
rld[s].out_reg = rl->out_reg;
set = single_set (next);
static void
do_input_reload (struct insn_chain *chain, struct reload *rl, int j)
{
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
rtx old = (rl->in && MEM_P (rl->in)
? rl->in_reg : rl->in);
rtx reg_rtx = rl->reg_rtx;
if (old && reg_rtx)
{
- enum machine_mode mode;
+ machine_mode mode;
/* Determine the mode to reload in.
This is very tricky because we have three to choose from.
do_output_reload (struct insn_chain *chain, struct reload *rl, int j)
{
rtx note, old;
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
/* If this is an output reload that stores something that is
not loaded in this same reload, see if we can eliminate a previous
store. */
if (rl->out && reg_rtx)
{
- enum machine_mode mode;
+ machine_mode mode;
/* Determine the mode to reload in.
See comments above (for input reloading). */
static bool
inherit_piecemeal_p (int dest ATTRIBUTE_UNUSED,
int src ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
+ machine_mode mode ATTRIBUTE_UNUSED)
{
#ifdef CANNOT_CHANGE_MODE_CLASS
return (!REG_CANNOT_CHANGE_MODE_P (dest, mode, reg_raw_mode[dest])
static void
emit_reload_insns (struct insn_chain *chain)
{
- rtx insn = chain->insn;
+ rtx_insn *insn = chain->insn;
int j;
reg = reload_reg_rtx_for_output[r];
if (reload_reg_rtx_reaches_end_p (reg, r))
{
- enum machine_mode mode = GET_MODE (reg);
+ machine_mode mode = GET_MODE (reg);
int regno = REGNO (reg);
int nregs = hard_regno_nregs[regno][mode];
rtx out = (REG_P (rld[r].out)
reg = reload_reg_rtx_for_input[r];
if (reload_reg_rtx_reaches_end_p (reg, r))
{
- enum machine_mode mode;
+ machine_mode mode;
int regno;
int nregs;
int in_regno;
rtx out = ((rld[r].out && REG_P (rld[r].out))
? rld[r].out : rld[r].out_reg);
int out_regno = REGNO (out);
- enum machine_mode mode = GET_MODE (out);
+ machine_mode mode = GET_MODE (out);
/* REG_RTX is now set or clobbered by the main instruction.
As the comment above explains, forget_old_reloads_1 only
if (!HARD_REGISTER_NUM_P (out_regno))
{
- rtx src_reg, store_insn = NULL_RTX;
+ rtx src_reg;
+ rtx_insn *store_insn = NULL;
reg_last_reload_reg[out_regno] = 0;
/* Go through the motions to emit INSN and test if it is strictly valid.
Return the emitted insn if valid, else return NULL. */
-static rtx
-emit_insn_if_valid_for_reload (rtx insn)
+static rtx_insn *
+emit_insn_if_valid_for_reload (rtx pat)
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
int code;
- insn = emit_insn (insn);
+ rtx_insn *insn = emit_insn (pat);
code = recog_memoized (insn);
if (code >= 0)
/* We want constrain operands to treat this insn strictly in its
validity determination, i.e., the way it would after reload has
completed. */
- if (constrain_operands (1))
+ if (constrain_operands (1, get_enabled_alternatives (insn)))
return insn;
}
Returns first insn emitted. */
-static rtx
+static rtx_insn *
gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
{
- rtx last = get_last_insn ();
- rtx tem;
+ rtx_insn *last = get_last_insn ();
+ rtx_insn *tem;
#ifdef SECONDARY_MEMORY_NEEDED
rtx tem1, tem2;
#endif
`extract_insn' and it is simpler to emit and then delete the insn if
not valid than to dummy things up. */
- rtx op0, op1, tem, insn;
+ rtx op0, op1, tem;
+ rtx_insn *insn;
enum insn_code code;
op0 = find_replacement (&XEXP (in, 0));
rtx insn;
rtx op1;
rtx out_moded;
- rtx set;
+ rtx_insn *set;
op1 = find_replacement (&XEXP (in, 0));
if (op1 != XEXP (in, 0))
if (insn)
{
set_unique_reg_note (insn, REG_EQUIV, in);
- return insn;
+ return as_a <rtx_insn *> (insn);
}
fatal_insn ("failure trying to reload:", set);
NEW_RELOAD_REG is reload register that reload J is using for REG. */
static void
-delete_output_reload (rtx insn, int j, int last_reload_reg, rtx new_reload_reg)
+delete_output_reload (rtx_insn *insn, int j, int last_reload_reg,
+ rtx new_reload_reg)
{
- rtx output_reload_insn = spill_reg_store[last_reload_reg];
+ rtx_insn *output_reload_insn = spill_reg_store[last_reload_reg];
rtx reg = spill_reg_stored_to[last_reload_reg];
int k;
int n_occurrences;
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 (INSN_DELETED_P (output_reload_insn))
+ if (output_reload_insn->deleted ())
return;
/* Get the raw pseudo-register referred to. */
n_occurrences += count_occurrences (PATTERN (insn),
eliminate_regs (substed, VOIDmode,
NULL_RTX), 0);
- for (i1 = reg_equiv_alt_mem_list (REGNO (reg)); i1; i1 = XEXP (i1, 1))
+ for (rtx i1 = reg_equiv_alt_mem_list (REGNO (reg)); i1; i1 = XEXP (i1, 1))
{
gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed));
n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0);
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);
+ for (rtx_insn *i1 = NEXT_INSN (output_reload_insn);
i1 != insn; i1 = NEXT_INSN (i1))
{
if (NOTE_INSN_BASIC_BLOCK_P (i1))
&& REG_BASIC_BLOCK (REGNO (reg)) >= NUM_FIXED_BLOCKS
&& find_regno_note (insn, REG_DEAD, REGNO (reg)))
{
- rtx i2;
+ rtx_insn *i2;
/* We know that it was used only between here and the beginning of
the current basic block. (We also know that the last use before
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 (rtx dead_insn, rtx current_insn)
+delete_address_reloads (rtx_insn *dead_insn, rtx_insn *current_insn)
{
rtx set = single_set (dead_insn);
- rtx set2, dst, prev, next;
+ rtx set2, dst;
+ rtx_insn *prev, *next;
if (set)
{
rtx dst = SET_DEST (set);
/* Subfunction of delete_address_reloads: process registers found in X. */
static void
-delete_address_reloads_1 (rtx dead_insn, rtx x, rtx current_insn)
+delete_address_reloads_1 (rtx_insn *dead_insn, rtx x, rtx_insn *current_insn)
{
- rtx prev, set, dst, i2;
+ rtx_insn *prev, *i2;
+ rtx set, dst;
int i, j;
enum rtx_code code = GET_CODE (x);
/* Nonzero if increment after copying. */
int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC
|| GET_CODE (value) == POST_MODIFY);
- rtx last;
+ rtx_insn *last;
rtx inc;
- rtx add_insn;
+ rtx_insn *add_insn;
int code;
rtx real_in = in == value ? incloc : in;
if (code >= 0)
{
extract_insn (add_insn);
- if (constrain_operands (1))
+ if (constrain_operands (1, get_enabled_alternatives (add_insn)))
{
/* If this is a pre-increment and we have incremented the value
where it lives, copy the incremented value to RELOADREG to
\f
#ifdef AUTO_INC_DEC
static void
-add_auto_inc_notes (rtx insn, rtx x)
+add_auto_inc_notes (rtx_insn *insn, rtx x)
{
enum rtx_code code = GET_CODE (x);
const char *fmt;