/* Reload pseudo regs into hard regs for insns that require hard regs.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
reload needs, spilling, assigning reload registers to use for
fixing up each insn, and generating the new insns to copy values
into the reload registers. */
-
-#ifndef LOCAL_REGNO
-#define LOCAL_REGNO(REGNO) 0
-#endif
\f
/* During reload_as_needed, element N contains a REG rtx for the hard reg
into which reg N has been reloaded (perhaps for a previous insn). */
is transferred to either reg_equiv_address or reg_equiv_mem. */
rtx *reg_equiv_memory_loc;
+/* We allocate reg_equiv_memory_loc inside a varray so that the garbage
+ collector can keep track of what is inside. */
+varray_type reg_equiv_memory_loc_varray;
+
/* Element N is the address of stack slot to which pseudo reg N is equivalent.
This is used when the address is not valid as a memory address
(because its displacement is too big for the machine.) */
This is only valid if reg_reloaded_contents is set and valid. */
static HARD_REG_SET reg_reloaded_dead;
+/* Indicate whether the register's current value is one that is not
+ safe to retain across a call, even for registers that are normally
+ call-saved. */
+static HARD_REG_SET reg_reloaded_call_part_clobbered;
+
/* Number of spill-regs so far; number of valid elements of spill_regs. */
static int n_spills;
static void update_eliminables (HARD_REG_SET *);
static void spill_hard_reg (unsigned int, int);
static int finish_spills (int);
-static void ior_hard_reg_set (HARD_REG_SET *, HARD_REG_SET *);
static void scan_paradoxical_subregs (rtx);
static void count_pseudo (int);
static void order_regs_for_reload (struct insn_chain *);
rtx, rtx, int, int);
static int free_for_value_p (int, enum machine_mode, int, enum reload_type,
rtx, rtx, int, int);
+static int function_invariant_p (rtx);
static int reload_reg_reaches_end_p (unsigned int, int, enum reload_type);
static int allocate_reload_reg (struct insn_chain *, int, int);
static int conflicts_with_override (rtx);
int);
static void do_input_reload (struct insn_chain *, struct reload *, int);
static void do_output_reload (struct insn_chain *, struct reload *, int);
+static bool inherit_piecemeal_p (int, int);
static void emit_reload_insns (struct insn_chain *);
static void delete_output_reload (rtx, int, int);
static void delete_address_reloads (rtx, rtx);
static void add_auto_inc_notes (rtx, rtx);
#endif
static void copy_eh_notes (rtx, rtx);
+static int reloads_conflict (int, int);
+static rtx gen_reload (rtx, rtx, int, enum reload_type);
\f
/* Initialize the reload pass once per compilation. */
INIT_REG_SET (&spilled_pseudos);
INIT_REG_SET (&pseudos_counted);
+ VARRAY_RTX_INIT (reg_equiv_memory_loc_varray, 0, "reg_equiv_memory_loc");
}
/* List of insn chains that are currently unused. */
compute_use_by_pseudos (HARD_REG_SET *to, regset from)
{
unsigned int regno;
+ reg_set_iterator rsi;
- EXECUTE_IF_SET_IN_REG_SET
- (from, FIRST_PSEUDO_REGISTER, regno,
- {
- int r = reg_renumber[regno];
- int nregs;
-
- if (r < 0)
- {
- /* reload_combine uses the information from
- BASIC_BLOCK->global_live_at_start, which might still
- contain registers that have not actually been allocated
- since they have an equivalence. */
- if (! reload_completed)
- abort ();
- }
- else
- {
- nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (regno));
- while (nregs-- > 0)
- SET_HARD_REG_BIT (*to, r + nregs);
- }
- });
+ EXECUTE_IF_SET_IN_REG_SET (from, FIRST_PSEUDO_REGISTER, regno, rsi)
+ {
+ int r = reg_renumber[regno];
+ int nregs;
+
+ if (r < 0)
+ {
+ /* reload_combine uses the information from
+ BASIC_BLOCK->global_live_at_start, which might still
+ contain registers that have not actually been allocated
+ since they have an equivalence. */
+ gcc_assert (reload_completed);
+ }
+ else
+ {
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+ while (nregs-- > 0)
+ SET_HARD_REG_BIT (*to, r + nregs);
+ }
+ }
}
/* Replace all pseudos found in LOC with their corresponding
*loc = reg_equiv_mem[regno];
else if (reg_equiv_address[regno])
*loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]);
- else if (GET_CODE (regno_reg_rtx[regno]) != REG
- || REGNO (regno_reg_rtx[regno]) != regno)
- *loc = regno_reg_rtx[regno];
else
- abort ();
+ {
+ gcc_assert (!REG_P (regno_reg_rtx[regno])
+ || REGNO (regno_reg_rtx[regno]) != regno);
+ *loc = regno_reg_rtx[regno];
+ }
return;
}
if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
regs_ever_live[i] = 1;
+#ifdef NON_SAVING_SETJMP
+ /* A function that calls setjmp should save and restore all the
+ call-saved registers on a system where longjmp clobbers them. */
+ if (NON_SAVING_SETJMP && current_function_calls_setjmp)
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! call_used_regs[i])
+ regs_ever_live[i] = 1;
+ }
+#endif
+
/* Find all the pseudo registers that didn't get hard regs
but do have known equivalent constants or memory slots.
These include parameters (known equivalent to parameter slots)
CLEAR_HARD_REG_SET (bad_spill_regs_global);
- /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
- Also find all paradoxical subregs and find largest such for each pseudo.
- On machines with small register classes, record hard registers that
- are used for user variables. These can never be used for spills.
- Also look for a "constant" REG_SETJMP. This means that all
- caller-saved registers must be marked live. */
+ /* Look for REG_EQUIV notes; record what each pseudo is equivalent
+ to. Also find all paradoxical subregs and find largest such for
+ each pseudo. */
num_eliminable_invariants = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
&& GET_MODE (insn) != VOIDmode)
PUT_MODE (insn, VOIDmode);
- if (GET_CODE (insn) == CALL_INSN
- && find_reg_note (insn, REG_SETJMP, NULL))
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (! call_used_regs[i])
- regs_ever_live[i] = 1;
-
- if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
+ if (set != 0 && REG_P (SET_DEST (set)))
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
if (note
-#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! function_invariant_p (XEXP (note, 0))
|| ! flag_pic
/* A function invariant is often CONSTANT_P but may
include a register. We promise to only pass
CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
|| (CONSTANT_P (XEXP (note, 0))
- && LEGITIMATE_PIC_OPERAND_P (XEXP (note, 0))))
-#endif
- )
+ && LEGITIMATE_PIC_OPERAND_P (XEXP (note, 0)))))
{
rtx x = XEXP (note, 0);
i = REGNO (SET_DEST (set));
and the MEM is not SET_SRC, the equivalencing insn
is one with the MEM as a SET_DEST and it occurs later.
So don't mark this insn now. */
- if (GET_CODE (x) != MEM
+ if (!MEM_P (x)
|| rtx_equal_p (SET_SRC (set), x))
reg_equiv_init[i]
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[i]);
/* If this insn is setting a MEM from a register equivalent to it,
this is the equivalencing insn. */
- else if (set && GET_CODE (SET_DEST (set)) == MEM
- && GET_CODE (SET_SRC (set)) == REG
+ else if (set && MEM_P (SET_DEST (set))
+ && REG_P (SET_SRC (set))
&& reg_equiv_memory_loc[REGNO (SET_SRC (set))]
&& rtx_equal_p (SET_DEST (set),
reg_equiv_memory_loc[REGNO (SET_SRC (set))]))
main reload loop in the most common case where register elimination
cannot be done. */
for (insn = first; insn && num_eliminable; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
- || GET_CODE (insn) == CALL_INSN)
+ if (INSN_P (insn))
note_stores (PATTERN (insn), mark_not_eliminable, NULL);
maybe_fix_stack_asms ();
/* Spill any hard regs that we know we can't eliminate. */
CLEAR_HARD_REG_SET (used_spill_regs);
- for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
- if (! ep->can_eliminate)
- spill_hard_reg (ep->from, 1);
+ /* There can be multiple ways to eliminate a register;
+ they should be listed adjacently.
+ Elimination for any register fails only if all possible ways fail. */
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; )
+ {
+ int from = ep->from;
+ int can_eliminate = 0;
+ do
+ {
+ can_eliminate |= ep->can_eliminate;
+ ep++;
+ }
+ while (ep < ®_eliminate[NUM_ELIMINABLE_REGS] && ep->from == from);
+ if (! can_eliminate)
+ spill_hard_reg (from, 1);
+ }
#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
if (frame_pointer_needed)
if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i])
{
rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX);
- enum reg_class class = MODE_BASE_REG_CLASS (GET_MODE (x));
if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]),
XEXP (x, 0)))
reg_equiv_mem[i] = x, reg_equiv_address[i] = 0;
- else if ((CONSTANT_P (x)
- && LEGITIMATE_CONSTANT_P (x)
- && PREFERRED_RELOAD_CLASS (x, class) != NO_REGS)
- || (GET_CODE (XEXP (x, 0)) == REG
+ else if (CONSTANT_P (XEXP (x, 0))
+ || (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
|| (GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+ && REG_P (XEXP (XEXP (x, 0), 0))
&& (REGNO (XEXP (XEXP (x, 0), 0))
< FIRST_PSEUDO_REGISTER)
- && (CONSTANT_P (XEXP (XEXP (x, 0), 1))
- && LEGITIMATE_CONSTANT_P (XEXP (XEXP (x, 0), 1))
- && PREFERRED_RELOAD_CLASS (XEXP (XEXP (x, 0), 1), class)
- != NO_REGS)))
+ && CONSTANT_P (XEXP (XEXP (x, 0), 1))))
reg_equiv_address[i] = XEXP (x, 0), reg_equiv_mem[i] = 0;
else
{
if an insn has a variable address, gets a REG_EH_REGION
note added to it, and then gets converted into an load
from a constant address. */
- if (GET_CODE (equiv_insn) == NOTE
+ 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
- {
- PUT_CODE (equiv_insn, NOTE);
- NOTE_SOURCE_FILE (equiv_insn) = 0;
- NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
- }
+ SET_INSN_DELETED (equiv_insn);
}
}
}
reload_as_needed (global);
- if (old_frame_size != get_frame_size ())
- abort ();
+ gcc_assert (old_frame_size == get_frame_size ());
if (num_eliminable)
verify_initial_elim_offsets ();
MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc[i]);
else
{
- RTX_UNCHANGING_P (reg) = MEM_IN_STRUCT_P (reg)
- = MEM_SCALAR_P (reg) = 0;
+ MEM_IN_STRUCT_P (reg) = MEM_SCALAR_P (reg) = 0;
MEM_ATTRS (reg) = 0;
}
}
{
rtx *pnote;
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn),
VOIDmode, CALL_INSN_FUNCTION_USAGE (insn));
&& (GET_MODE (insn) == QImode
|| find_reg_note (insn, REG_EQUAL, NULL_RTX)))
|| (GET_CODE (PATTERN (insn)) == CLOBBER
- && (GET_CODE (XEXP (PATTERN (insn), 0)) != MEM
+ && (!MEM_P (XEXP (PATTERN (insn), 0))
|| GET_MODE (XEXP (PATTERN (insn), 0)) != BLKmode
|| (GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) != SCRATCH
&& XEXP (XEXP (PATTERN (insn), 0), 0)
!= stack_pointer_rtx))
- && (GET_CODE (XEXP (PATTERN (insn), 0)) != REG
+ && (!REG_P (XEXP (PATTERN (insn), 0))
|| ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))))
{
delete_insn (insn);
if (reg_equiv_constant)
free (reg_equiv_constant);
reg_equiv_constant = 0;
- if (reg_equiv_memory_loc)
- free (reg_equiv_memory_loc);
+ VARRAY_GROW (reg_equiv_memory_loc_varray, 0);
reg_equiv_memory_loc = 0;
if (offsets_known_at)
by this, so unshare everything here. */
unshare_all_rtl_again (first);
+#ifdef STACK_BOUNDARY
+ /* init_emit has set the alignment of the hard frame pointer
+ to STACK_BOUNDARY. It is very likely no longer valid if
+ the hard frame pointer was used for register allocation. */
+ if (!frame_pointer_needed)
+ REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT;
+#endif
+
return failure;
}
include REG_LABEL), we need to see what effects this has on the
known offsets at labels. */
- if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN
+ if (LABEL_P (insn) || JUMP_P (insn)
|| (INSN_P (insn) && REG_NOTES (insn) != 0))
set_label_offsets (insn, insn, 0);
rtx set = single_set (insn);
/* Skip insns that only set an equivalence. */
- if (set && GET_CODE (SET_DEST (set)) == REG
+ if (set && REG_P (SET_DEST (set))
&& reg_renumber[REGNO (SET_DEST (set))] < 0
&& reg_equiv_constant[REGNO (SET_DEST (set))])
continue;
rtx set = single_set (insn);
if (set
&& SET_SRC (set) == SET_DEST (set)
- && GET_CODE (SET_SRC (set)) == REG
+ && REG_P (SET_SRC (set))
&& REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
{
delete_insn (insn);
SET_REGNO_REG_SET (&pseudos_counted, reg);
- if (r < 0)
- abort ();
+ gcc_assert (r >= 0);
spill_add_cost[r] += freq;
- nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
+ nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
while (nregs-- > 0)
spill_cost[r + nregs] += freq;
}
static void
order_regs_for_reload (struct insn_chain *chain)
{
- int i;
+ unsigned i;
HARD_REG_SET used_by_pseudos;
HARD_REG_SET used_by_pseudos2;
+ reg_set_iterator rsi;
COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set);
CLEAR_REG_SET (&pseudos_counted);
EXECUTE_IF_SET_IN_REG_SET
- (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
- {
- count_pseudo (i);
- });
+ (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi)
+ {
+ count_pseudo (i);
+ }
EXECUTE_IF_SET_IN_REG_SET
- (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
- {
- count_pseudo (i);
- });
+ (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
+ {
+ count_pseudo (i);
+ }
CLEAR_REG_SET (&pseudos_counted);
}
\f
count_spilled_pseudo (int spilled, int spilled_nregs, int reg)
{
int r = reg_renumber[reg];
- int nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
+ int nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (reg)];
if (REGNO_REG_SET_P (&spilled_pseudos, reg)
|| spilled + spilled_nregs <= r || r + nregs <= spilled)
int k;
HARD_REG_SET not_usable;
HARD_REG_SET used_by_other_reload;
+ reg_set_iterator rsi;
COPY_HARD_REG_SET (not_usable, bad_spill_regs);
IOR_HARD_REG_SET (not_usable, bad_spill_regs_global);
{
int this_cost = spill_cost[regno];
int ok = 1;
- unsigned int this_nregs = HARD_REGNO_NREGS (regno, rl->mode);
+ unsigned int this_nregs = hard_regno_nregs[regno][rl->mode];
for (j = 1; j < this_nregs; j++)
{
}
if (! ok)
continue;
- if (rl->in && GET_CODE (rl->in) == REG && REGNO (rl->in) == regno)
+ if (rl->in && REG_P (rl->in) && REGNO (rl->in) == regno)
this_cost--;
- if (rl->out && GET_CODE (rl->out) == REG && REGNO (rl->out) == regno)
+ if (rl->out && REG_P (rl->out) && REGNO (rl->out) == regno)
this_cost--;
if (this_cost < best_cost
/* Among registers with equal cost, prefer caller-saved ones, or
if (best_reg == -1)
return 0;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Using reg %d for reload %d\n", best_reg, rnum);
+ if (dump_file)
+ fprintf (dump_file, "Using reg %d for reload %d\n", best_reg, rnum);
- rl->nregs = HARD_REGNO_NREGS (best_reg, rl->mode);
+ rl->nregs = hard_regno_nregs[best_reg][rl->mode];
rl->regno = best_reg;
EXECUTE_IF_SET_IN_REG_SET
- (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
- {
- count_spilled_pseudo (best_reg, rl->nregs, j);
- });
+ (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, rsi)
+ {
+ count_spilled_pseudo (best_reg, rl->nregs, j);
+ }
EXECUTE_IF_SET_IN_REG_SET
- (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
- {
- count_spilled_pseudo (best_reg, rl->nregs, j);
- });
+ (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, rsi)
+ {
+ count_spilled_pseudo (best_reg, rl->nregs, j);
+ }
for (i = 0; i < rl->nregs; i++)
{
- if (spill_cost[best_reg + i] != 0
- || spill_add_cost[best_reg + i] != 0)
- abort ();
+ gcc_assert (spill_cost[best_reg + i] == 0);
+ gcc_assert (spill_add_cost[best_reg + i] == 0);
SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i);
}
return 1;
int regno = REGNO (chain->rld[i].reg_rtx);
chain->rld[i].regno = regno;
chain->rld[i].nregs
- = HARD_REGNO_NREGS (regno, GET_MODE (chain->rld[i].reg_rtx));
+ = hard_regno_nregs[regno][GET_MODE (chain->rld[i].reg_rtx)];
}
else
chain->rld[i].regno = -1;
CLEAR_HARD_REG_SET (used_spill_regs_local);
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn));
+ if (dump_file)
+ fprintf (dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn));
qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower);
{
static const char *const reg_class_names[] = REG_CLASS_NAMES;
if (asm_noperands (PATTERN (insn)) >= 0)
- error_for_asm (insn, "can't find a register in class `%s' while reloading `asm'",
+ error_for_asm (insn, "can't find a register in class %qs while "
+ "reloading %<asm%>",
reg_class_names[class]);
else
{
- error ("unable to find a register to spill in class `%s'",
+ error ("unable to find a register to spill in class %qs",
reg_class_names[class]);
fatal_insn ("this is the insn:", insn);
}
/* If the previous insn sets a register that dies in our insn, delete it
too. */
if (prev && GET_CODE (PATTERN (prev)) == SET
- && (prev_dest = SET_DEST (PATTERN (prev)), GET_CODE (prev_dest) == REG)
+ && (prev_dest = SET_DEST (PATTERN (prev)), REG_P (prev_dest))
&& reg_mentioned_p (prev_dest, PATTERN (insn))
&& find_regno_note (insn, REG_DEAD, REGNO (prev_dest))
&& ! side_effects_p (SET_SRC (PATTERN (prev))))
delete_dead_insn (prev);
- PUT_CODE (insn, NOTE);
- NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (insn) = 0;
+ SET_INSN_DELETED (insn);
}
/* Modify the home of pseudo-reg I.
/* If the reg got changed to a MEM at rtl-generation time,
ignore it. */
- if (GET_CODE (regno_reg_rtx[i]) != REG)
+ if (!REG_P (regno_reg_rtx[i]))
return;
/* Modify the reg-rtx to contain the new hard reg
below. */
adjust = inherent_size - total_size;
- RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
-
/* Nothing can alias this slot except this pseudo. */
set_mem_alias_set (x, new_alias_set ());
}
/* If we have a decl for the original register, set it for the
memory. If this is a shared MEM, make a copy. */
if (REG_EXPR (regno_reg_rtx[i])
- && TREE_CODE_CLASS (TREE_CODE (REG_EXPR (regno_reg_rtx[i]))) == 'd')
+ && DECL_P (REG_EXPR (regno_reg_rtx[i])))
{
rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
any copies of it, since otherwise when the stack slot
is reused, nonoverlapping_memrefs_p might think they
cannot overlap. */
- if (decl && GET_CODE (decl) == REG && REGNO (decl) == (unsigned) i)
+ if (decl && REG_P (decl) && REGNO (decl) == (unsigned) i)
{
if (from_reg != -1 && spill_stack_slot[from_reg] == x)
x = copy_rtx (x);
i = reg_renumber[regno];
if (i < 0)
return;
- lim = i + HARD_REGNO_NREGS (i, PSEUDO_REGNO_MODE (regno));
+ lim = i + hard_regno_nregs[i][PSEUDO_REGNO_MODE (regno)];
while (i < lim)
regs_ever_live[i++] = 1;
}
else if (x == insn
&& (tem = prev_nonnote_insn (insn)) != 0
- && GET_CODE (tem) == BARRIER)
+ && BARRIER_P (tem))
set_offsets_for_label (insn);
else
/* If neither of the above cases is true, compare each offset
return;
case LABEL_REF:
- set_label_offsets (XEXP (SET_SRC (x), 0), insn, initial_p);
+ set_label_offsets (SET_SRC (x), insn, initial_p);
return;
case IF_THEN_ELSE:
case RETURN:
return x;
- case ADDRESSOF:
- /* This is only for the benefit of the debugging backends, which call
- eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
- removed after CSE. */
- new = eliminate_regs (XEXP (x, 0), 0, insn);
- if (GET_CODE (new) == MEM)
- return XEXP (new, 0);
- return x;
-
case REG:
regno = REGNO (x);
and require special code to handle code a reloaded PLUS operand.
Also consider backends where the flags register is clobbered by a
- MINUS, but we can emit a PLUS that does not clobber flags (ia32,
+ MINUS, but we can emit a PLUS that does not clobber flags (IA-32,
lea instruction comes to mind). If we try to reload a MINUS, we
may kill the flags register that was holding a useful value.
case PLUS:
/* If this is the sum of an eliminable register and a constant, rework
the sum. */
- if (GET_CODE (XEXP (x, 0)) == REG
+ if (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
&& CONSTANT_P (XEXP (x, 1)))
{
didn't get a hard register but has a reg_equiv_constant,
we must replace the constant here since it may no longer
be in the position of any operand. */
- if (GET_CODE (new0) == PLUS && GET_CODE (new1) == REG
+ if (GET_CODE (new0) == PLUS && REG_P (new1)
&& REGNO (new1) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (new1)] < 0
&& reg_equiv_constant != 0
&& reg_equiv_constant[REGNO (new1)] != 0)
new1 = reg_equiv_constant[REGNO (new1)];
- else if (GET_CODE (new1) == PLUS && GET_CODE (new0) == REG
+ else if (GET_CODE (new1) == PLUS && REG_P (new0)
&& REGNO (new0) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (new0)] < 0
&& reg_equiv_constant[REGNO (new0)] != 0)
so that we have (plus (mult ..) ..). This is needed in order
to keep load-address insns valid. This case is pathological.
We ignore the possibility of overflow here. */
- if (GET_CODE (XEXP (x, 0)) == REG
+ if (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS];
pseudo didn't get a hard reg, we must replace this with the
eliminated version of the memory location because push_reload
may do the replacement in certain circumstances. */
- if (GET_CODE (SUBREG_REG (x)) == REG
+ if (REG_P (SUBREG_REG (x))
&& (GET_MODE_SIZE (GET_MODE (x))
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
&& reg_equiv_memory_loc != 0
int x_size = GET_MODE_SIZE (GET_MODE (x));
int new_size = GET_MODE_SIZE (GET_MODE (new));
- if (GET_CODE (new) == MEM
+ if (MEM_P (new)
&& ((x_size < new_size
#ifdef WORD_REGISTER_OPERATIONS
/* On these machines, combine can create rtl of the form
return x;
case MEM:
- /* This is only for the benefit of the debugging backends, which call
- eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
- removed after CSE. */
- if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
- return eliminate_regs (XEXP (XEXP (x, 0), 0), 0, insn);
-
/* 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. */
case CLOBBER:
case ASM_OPERANDS:
case SET:
- abort ();
+ gcc_unreachable ();
default:
break;
case RETURN:
return;
- case ADDRESSOF:
- abort ();
-
case REG:
regno = REGNO (x);
return;
case SUBREG:
- if (GET_CODE (SUBREG_REG (x)) == REG
+ if (REG_P (SUBREG_REG (x))
&& (GET_MODE_SIZE (GET_MODE (x))
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
&& reg_equiv_memory_loc != 0
case SET:
/* Check for setting a register that we know about. */
- if (GET_CODE (SET_DEST (x)) == REG)
+ if (REG_P (SET_DEST (x)))
{
/* See if this is setting the replacement register for an
elimination.
return;
case MEM:
- if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
- abort ();
-
/* Our only special processing is to pass the mode of the MEM to our
recursive call. */
elimination_effects (XEXP (x, 0), GET_MODE (x));
struct elim_table *ep;
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
- if (ep->from_rtx == x && ep->can_eliminate)
+ if (ep->from_rtx == x)
ep->can_eliminate = 0;
return;
}
rtx substed_operand[MAX_RECOG_OPERANDS];
rtx orig_operand[MAX_RECOG_OPERANDS];
struct elim_table *ep;
+ rtx plus_src;
if (! insn_is_asm && icode < 0)
{
- if (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)
- return 0;
- abort ();
+ 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);
+ return 0;
}
- if (old_set != 0 && GET_CODE (SET_DEST (old_set)) == REG
+ if (old_set != 0 && REG_P (SET_DEST (old_set))
&& REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER)
{
/* Check for setting an eliminable register. */
}
/* We allow one special case which happens to work on all machines we
- currently support: a single set with the source being a PLUS of an
- eliminable register and a constant. */
- if (old_set
- && GET_CODE (SET_DEST (old_set)) == REG
- && GET_CODE (SET_SRC (old_set)) == PLUS
- && GET_CODE (XEXP (SET_SRC (old_set), 0)) == REG
- && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
- && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+ currently support: a single set with the source or a REG_EQUAL
+ note being a PLUS of an eliminable register and a constant. */
+ plus_src = 0;
+ if (old_set && REG_P (SET_DEST (old_set)))
+ {
+ /* First see if the source is of the form (plus (reg) CST). */
+ if (GET_CODE (SET_SRC (old_set)) == PLUS
+ && REG_P (XEXP (SET_SRC (old_set), 0))
+ && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
+ && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+ plus_src = SET_SRC (old_set);
+ else if (REG_P (SET_SRC (old_set)))
+ {
+ /* Otherwise, see if we have a REG_EQUAL note of the form
+ (plus (reg) CST). */
+ rtx links;
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ {
+ if (REG_NOTE_KIND (links) == REG_EQUAL
+ && GET_CODE (XEXP (links, 0)) == PLUS
+ && REG_P (XEXP (XEXP (links, 0), 0))
+ && GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT
+ && REGNO (XEXP (XEXP (links, 0), 0)) < FIRST_PSEUDO_REGISTER)
+ {
+ plus_src = XEXP (links, 0);
+ break;
+ }
+ }
+ }
+ }
+ if (plus_src)
{
- rtx reg = XEXP (SET_SRC (old_set), 0);
- HOST_WIDE_INT offset = INTVAL (XEXP (SET_SRC (old_set), 1));
+ rtx reg = XEXP (plus_src, 0);
+ HOST_WIDE_INT offset = INTVAL (XEXP (plus_src, 1));
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->from_rtx == reg && ep->can_eliminate)
PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec);
add_clobbers (PATTERN (insn), INSN_CODE (insn));
}
- if (INSN_CODE (insn) < 0)
- abort ();
+ gcc_assert (INSN_CODE (insn) >= 0);
}
- else
+ /* If we have a nonzero offset, and the source is already
+ a simple REG, the following transformation would
+ increase the cost of the insn by replacing a simple REG
+ with (plus (reg sp) CST). So try only when plus_src
+ comes from old_set proper, not REG_NOTES. */
+ else if (SET_SRC (old_set) == plus_src)
{
new_body = old_body;
if (! replace)
XEXP (SET_SRC (old_set), 0) = ep->to_rtx;
XEXP (SET_SRC (old_set), 1) = GEN_INT (offset);
}
+ else
+ break;
+
val = 1;
/* This can't have an effect on elimination offsets, so skip right
to the end. */
{
/* Check for setting a register that we know about. */
if (recog_data.operand_type[i] != OP_IN
- && GET_CODE (orig_operand[i]) == REG)
+ && 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
eliminate this reg. */
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS];
ep++)
- if (ep->from_rtx == orig_operand[i] && ep->can_eliminate)
+ if (ep->from_rtx == orig_operand[i])
ep->can_eliminate = 0;
}
/* If an output operand changed from a REG to a MEM and INSN is an
insn, write a CLOBBER insn. */
if (recog_data.operand_type[i] != OP_IN
- && GET_CODE (orig_operand[i]) == REG
- && GET_CODE (substed_operand[i]) == MEM
+ && REG_P (orig_operand[i])
+ && MEM_P (substed_operand[i])
&& replace)
emit_insn_after (gen_rtx_CLOBBER (VOIDmode, orig_operand[i]),
insn);
thing always? */
if (! insn_is_asm
&& old_set != 0
- && ((GET_CODE (SET_SRC (old_set)) == REG
+ && ((REG_P (SET_SRC (old_set))
&& (GET_CODE (new_body) != SET
- || GET_CODE (SET_SRC (new_body)) != REG))
+ || !REG_P (SET_SRC (new_body))))
/* If this was a load from or store to memory, compare
the MEM in recog_data.operand to the one in the insn.
If they are not equal, then rerecognize the insn. */
|| (old_set != 0
- && ((GET_CODE (SET_SRC (old_set)) == MEM
+ && ((MEM_P (SET_SRC (old_set))
&& SET_SRC (old_set) != recog_data.operand[1])
- || (GET_CODE (SET_DEST (old_set)) == MEM
+ || (MEM_P (SET_DEST (old_set))
&& SET_DEST (old_set) != recog_data.operand[0])))
/* If this was an add insn before, rerecognize. */
|| GET_CODE (SET_SRC (old_set)) == PLUS))
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
- if (t != ep->initial_offset)
- abort ();
+ gcc_assert (t == ep->initial_offset);
}
#else
INITIAL_FRAME_POINTER_OFFSET (t);
- if (t != reg_eliminate[0].initial_offset)
- abort ();
+ gcc_assert (t == reg_eliminate[0].initial_offset);
#endif
}
/* Does this function require a frame pointer? */
frame_pointer_needed = (! flag_omit_frame_pointer
-#ifdef EXIT_IGNORE_STACK
/* ?? If EXIT_IGNORE_STACK is set, we will not save
and restore sp for alloca. So we can't eliminate
the frame pointer in that case. At some point,
sp-adjusting insns for this case. */
|| (current_function_calls_alloca
&& EXIT_IGNORE_STACK)
-#endif
|| FRAME_POINTER_REQUIRED);
num_eliminable = 0;
#endif
/* Count the number of eliminable registers and build the FROM and TO
- REG rtx's. Note that code in gen_rtx will cause, e.g.,
- gen_rtx (REG, Pmode, STACK_POINTER_REGNUM) to equal stack_pointer_rtx.
+ REG rtx's. Note that code in gen_rtx_REG will cause, e.g.,
+ gen_rtx_REG (Pmode, STACK_POINTER_REGNUM) to equal stack_pointer_rtx.
We depend on this. */
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
if (reg_renumber[i] >= 0
&& (unsigned int) reg_renumber[i] <= regno
&& ((unsigned int) reg_renumber[i]
- + HARD_REGNO_NREGS ((unsigned int) reg_renumber[i],
- PSEUDO_REGNO_MODE (i))
+ + hard_regno_nregs[(unsigned int) reg_renumber[i]]
+ [PSEUDO_REGNO_MODE (i)]
> regno))
SET_REGNO_REG_SET (&spilled_pseudos, i);
}
-/* I'm getting weird preprocessor errors if I use IOR_HARD_REG_SET
- from within EXECUTE_IF_SET_IN_REG_SET. Hence this awkwardness. */
-
-static void
-ior_hard_reg_set (HARD_REG_SET *set1, HARD_REG_SET *set2)
-{
- IOR_HARD_REG_SET (*set1, *set2);
-}
-
/* After find_reload_regs has been run for all insn that need reloads,
and/or spill_hard_regs was called, this function is used to actually
spill pseudo registers and try to reallocate them. It also sets up the
{
struct insn_chain *chain;
int something_changed = 0;
- int i;
+ unsigned i;
+ reg_set_iterator rsi;
/* Build the spill_regs array for the function. */
/* If there are some registers still to eliminate and one of the spill regs
else
spill_reg_order[i] = -1;
- EXECUTE_IF_SET_IN_REG_SET
- (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i,
- {
- /* Record the current hard register the pseudo is allocated to in
- pseudo_previous_regs so we avoid reallocating it to the same
- hard reg in a later pass. */
- if (reg_renumber[i] < 0)
- abort ();
-
- SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
- /* Mark it as no longer having a hard register home. */
- reg_renumber[i] = -1;
- /* We will need to scan everything again. */
- something_changed = 1;
- });
+ EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi)
+ {
+ /* Record the current hard register the pseudo is allocated to in
+ pseudo_previous_regs so we avoid reallocating it to the same
+ hard reg in a later pass. */
+ gcc_assert (reg_renumber[i] >= 0);
+
+ SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
+ /* Mark it as no longer having a hard register home. */
+ reg_renumber[i] = -1;
+ /* We will need to scan everything again. */
+ something_changed = 1;
+ }
/* Retry global register allocation if possible. */
if (global)
for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
{
EXECUTE_IF_SET_IN_REG_SET
- (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
- {
- ior_hard_reg_set (pseudo_forbidden_regs + i,
- &chain->used_spill_regs);
- });
+ (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi)
+ {
+ IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
+ chain->used_spill_regs);
+ }
EXECUTE_IF_SET_IN_REG_SET
- (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
- {
- ior_hard_reg_set (pseudo_forbidden_regs + i,
- &chain->used_spill_regs);
- });
+ (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi)
+ {
+ IOR_HARD_REG_SET (pseudo_forbidden_regs[i],
+ chain->used_spill_regs);
+ }
}
/* Retry allocating the spilled pseudos. For each reg, merge the
and call retry_global_alloc.
We change spill_pseudos here to only contain pseudos that did not
get a new hard register. */
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
if (reg_old_renumber[i] != reg_renumber[i])
{
HARD_REG_SET forbidden;
/* Make sure we only enlarge the set. */
GO_IF_HARD_REG_SUBSET (used_by_pseudos2, chain->used_spill_regs, ok);
- abort ();
+ gcc_unreachable ();
ok:;
}
}
/* Let alter_reg modify the reg rtx's for the modified pseudos. */
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+ for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++)
{
int regno = reg_renumber[i];
if (reg_old_renumber[i] == regno)
alter_reg (i, reg_old_renumber[i]);
reg_old_renumber[i] = regno;
- if (rtl_dump_file)
+ if (dump_file)
{
if (regno == -1)
- fprintf (rtl_dump_file, " Register %d now on stack.\n\n", i);
+ fprintf (dump_file, " Register %d now on stack.\n\n", i);
else
- fprintf (rtl_dump_file, " Register %d now in %d.\n\n",
+ fprintf (dump_file, " Register %d now in %d.\n\n",
i, reg_renumber[i]);
}
}
return something_changed;
}
\f
-/* Find all paradoxical subregs within X and update reg_max_ref_width.
- Also mark any hard registers used to store user variables as
- forbidden from being used for spill registers. */
+/* Find all paradoxical subregs within X and update reg_max_ref_width. */
static void
scan_paradoxical_subregs (rtx x)
switch (code)
{
case REG:
-#if 0
- if (SMALL_REGISTER_CLASSES && REGNO (x) < FIRST_PSEUDO_REGISTER
- && REG_USERVAR_P (x))
- SET_HARD_REG_BIT (bad_spill_regs_global, REGNO (x));
-#endif
- return;
-
case CONST_INT:
case CONST:
case SYMBOL_REF:
return;
case SUBREG:
- if (GET_CODE (SUBREG_REG (x)) == REG
+ if (REG_P (SUBREG_REG (x))
&& GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
reg_max_ref_width[REGNO (SUBREG_REG (x))]
= GET_MODE_SIZE (GET_MODE (x));
reg_last_reload_reg = xcalloc (max_regno, sizeof (rtx));
reg_has_output_reload = xmalloc (max_regno);
CLEAR_HARD_REG_SET (reg_reloaded_valid);
+ CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered);
set_initial_elim_offsets ();
/* If we pass a label, copy the offsets from the label information
into the current offsets of each elimination. */
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
set_offsets_for_label (insn);
else if (INSN_P (insn))
if ((GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER)
- && GET_CODE (XEXP (PATTERN (insn), 0)) == MEM)
+ && MEM_P (XEXP (PATTERN (insn), 0)))
XEXP (XEXP (PATTERN (insn), 0), 0)
= eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0),
GET_MODE (XEXP (PATTERN (insn), 0)),
if ((num_eliminable || num_eliminable_invariants) && chain->need_elim)
{
eliminate_regs_in_insn (insn, 1);
- if (GET_CODE (insn) == NOTE)
+ if (NOTE_P (insn))
{
update_eliminable_offsets ();
continue;
|| (extract_insn (p), ! constrain_operands (1))))
{
error_for_asm (insn,
- "`asm' operand requires impossible reload");
+ "%<asm%> operand requires "
+ "impossible reload");
delete_insn (p);
}
}
/* 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))
- if (GET_CODE (x) == INSN && GET_CODE (PATTERN (x)) == CLOBBER)
+ if (NONJUMP_INSN_P (x) && GET_CODE (PATTERN (x)) == CLOBBER)
note_stores (PATTERN (x), forget_old_reloads_1, NULL);
#ifdef AUTO_INC_DEC
if (n == 1)
{
n = validate_replace_rtx (reload_reg,
- gen_rtx (code, mode,
- reload_reg),
+ gen_rtx_fmt_e (code,
+ mode,
+ reload_reg),
p);
/* We must also verify that the constraints
undo the replacement. */
if (!n)
{
- validate_replace_rtx (gen_rtx (code, mode,
- reload_reg),
+ validate_replace_rtx (gen_rtx_fmt_e (code,
+ mode,
+ reload_reg),
reload_reg, p);
break;
}
#endif
}
/* A reload reg's contents are unknown after a label. */
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
CLEAR_HARD_REG_SET (reg_reloaded_valid);
/* Don't assume a reload reg is still good after a call insn
- if it is a call-used reg. */
- else if (GET_CODE (insn) == CALL_INSN)
+ if it is a call-used reg, or if it contains a value that will
+ be partially clobbered by the call. */
+ else if (CALL_P (insn))
+ {
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
+ AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+ }
}
/* Clean up. */
x = SUBREG_REG (x);
}
- if (GET_CODE (x) != REG)
+ if (!REG_P (x))
return;
regno = REGNO (x);
{
unsigned int i;
- nr = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ nr = hard_regno_nregs[regno][GET_MODE (x)];
/* Storing into a spilled-reg invalidates its contents.
This can happen if a block-local pseudo is allocated to that reg
and it wasn't spilled because this block's total need is 0.
|| ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
{
CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
+ CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i);
spill_reg_store[regno + i] = 0;
}
}
mark_reload_reg_in_use (unsigned int regno, int opnum, enum reload_type type,
enum machine_mode mode)
{
- unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
+ unsigned int nregs = hard_regno_nregs[regno][mode];
unsigned int i;
for (i = regno; i < nregs + regno; i++)
clear_reload_reg_in_use (unsigned int regno, int opnum,
enum reload_type type, enum machine_mode mode)
{
- unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
+ unsigned int nregs = hard_regno_nregs[regno][mode];
unsigned int start_regno, end_regno, r;
int i;
/* A complication is that for some reload types, inheritance might
used_in_set = &reload_reg_used_in_insn;
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* We resolve conflicts with remaining reloads of the same type by
excluding the intervals of reload registers by them from the
unsigned int conflict_start = true_regnum (rld[i].reg_rtx);
unsigned int conflict_end
= (conflict_start
- + HARD_REGNO_NREGS (conflict_start, rld[i].mode));
+ + hard_regno_nregs[conflict_start][rld[i].mode]);
/* If there is an overlap with the first to-be-freed register,
adjust the interval start. */
/* In use for anything means we can't use it for RELOAD_OTHER. */
if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
return 0;
case RELOAD_FOR_OTHER_ADDRESS:
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+
+ default:
+ gcc_unreachable ();
}
- abort ();
}
/* Return 1 if the value in reload reg REGNO, as used by a reload
return 0;
return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+ && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used, regno));
return 0;
return 1;
- }
- abort ();
+ default:
+ gcc_unreachable ();
+ }
}
\f
/* Return 1 if the reloads denoted by R1 and R2 cannot share a register.
This function uses the same algorithm as reload_reg_free_p above. */
-int
+static int
reloads_conflict (int r1, int r2)
{
enum reload_type r1_type = rld[r1].when_needed;
return 1;
default:
- abort ();
+ gcc_unreachable ();
}
}
\f
for (i = 0; i < n_reloads; i++)
{
rtx reg = rld[i].reg_rtx;
- if (reg && GET_CODE (reg) == REG
+ if (reg && REG_P (reg)
&& ((unsigned) regno - true_regnum (reg)
- <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned) 1)
+ <= hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] - (unsigned) 1)
&& i != reloadnum)
{
rtx other_input = rld[i].in;
enum reload_type type, rtx value, rtx out, int reloadnum,
int ignore_address_reloads)
{
- int nregs = HARD_REGNO_NREGS (regno, mode);
+ int nregs = hard_regno_nregs[regno][mode];
while (nregs-- > 0)
if (! reload_reg_free_for_value_p (regno, regno + nregs, opnum, type,
value, out, reloadnum,
return 1;
}
+/* Return nonzero if the rtx X is invariant over the current function. */
+/* ??? Actually, the places where we use this expect exactly what
+ * is tested here, and not everything that is function invariant. In
+ * particular, the frame pointer and arg pointer are special cased;
+ * pic_offset_table_rtx is not, and this will cause aborts when we
+ * go to spill these things to memory. */
+
+static int
+function_invariant_p (rtx x)
+{
+ if (CONSTANT_P (x))
+ return 1;
+ if (x == frame_pointer_rtx || x == arg_pointer_rtx)
+ return 1;
+ if (GET_CODE (x) == PLUS
+ && (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx)
+ && CONSTANT_P (XEXP (x, 1)))
+ return 1;
+ return 0;
+}
+
/* Determine whether the reload reg X overlaps any rtx'es used for
overriding inheritance. Return nonzero if so. */
/* It's the user's fault; the operand's mode and constraint
don't match. Disable this reload so we don't crash in final. */
error_for_asm (insn,
- "`asm' operand constraint incompatible with operand size");
+ "%<asm%> operand constraint incompatible with operand size");
rld[r].in = 0;
rld[r].out = 0;
rld[r].reg_rtx = 0;
&& ! TEST_HARD_REG_BIT (reload_reg_used_for_inherit,
regnum))))
{
- int nr = HARD_REGNO_NREGS (regnum, rld[r].mode);
+ int nr = hard_regno_nregs[regnum][rld[r].mode];
/* Avoid the problem where spilling a GENERAL_OR_FP_REG
(on 68000) got us two FP regs. If NR is 1,
we would reject both of them. */
if (rld[r].in != 0 && rld[r].reg_rtx != 0
&& (rtx_equal_p (rld[r].in, rld[r].reg_rtx)
|| (rtx_equal_p (rld[r].out, rld[r].reg_rtx)
- && GET_CODE (rld[r].in) != MEM
+ && !MEM_P (rld[r].in)
&& true_regnum (rld[r].in) < FIRST_PSEUDO_REGISTER)))
continue;
if (rld[r].in == 0)
;
- else if (GET_CODE (rld[r].in) == REG)
+ else if (REG_P (rld[r].in))
{
regno = REGNO (rld[r].in);
mode = GET_MODE (rld[r].in);
}
- else if (GET_CODE (rld[r].in_reg) == REG)
+ else if (REG_P (rld[r].in_reg))
{
regno = REGNO (rld[r].in_reg);
mode = GET_MODE (rld[r].in_reg);
}
else if (GET_CODE (rld[r].in_reg) == SUBREG
- && GET_CODE (SUBREG_REG (rld[r].in_reg)) == REG)
+ && REG_P (SUBREG_REG (rld[r].in_reg)))
{
byte = SUBREG_BYTE (rld[r].in_reg);
regno = REGNO (SUBREG_REG (rld[r].in_reg));
|| GET_CODE (rld[r].in_reg) == PRE_DEC
|| GET_CODE (rld[r].in_reg) == POST_INC
|| GET_CODE (rld[r].in_reg) == POST_DEC)
- && GET_CODE (XEXP (rld[r].in_reg, 0)) == REG)
+ && REG_P (XEXP (rld[r].in_reg, 0)))
{
regno = REGNO (XEXP (rld[r].in_reg, 0));
mode = GET_MODE (XEXP (rld[r].in_reg, 0));
Also, it takes much more hair to keep track of all the things
that can invalidate an inherited reload of part of a pseudoreg. */
else if (GET_CODE (rld[r].in) == SUBREG
- && GET_CODE (SUBREG_REG (rld[r].in)) == REG)
+ && REG_P (SUBREG_REG (rld[r].in)))
regno = subreg_regno (rld[r].in);
#endif
{
/* If a group is needed, verify that all the subsequent
registers still have their values intact. */
- int nr = HARD_REGNO_NREGS (i, rld[r].mode);
+ int nr = hard_regno_nregs[i][rld[r].mode];
int k;
for (k = 1; k < nr; k++)
&& rld[r].out == 0
&& (CONSTANT_P (rld[r].in)
|| GET_CODE (rld[r].in) == PLUS
- || GET_CODE (rld[r].in) == REG
- || GET_CODE (rld[r].in) == MEM)
+ || REG_P (rld[r].in)
+ || MEM_P (rld[r].in))
&& (rld[r].nregs == max_group_size
|| ! reg_classes_intersect_p (rld[r].class, group_class)))
search_equiv = rld[r].in;
if (equiv != 0)
{
- if (GET_CODE (equiv) == REG)
+ if (REG_P (equiv))
regno = REGNO (equiv);
- else if (GET_CODE (equiv) == SUBREG)
+ else
{
/* This must be a SUBREG of a hard register.
Make a new REG since this might be used in an
address and not all machines support SUBREGs
there. */
+ gcc_assert (GET_CODE (equiv) == SUBREG);
regno = subreg_regno (equiv);
equiv = gen_rtx_REG (rld[r].mode, regno);
}
- else
- abort ();
}
/* If we found a spill reg, reject it unless it is free
&& (regno != HARD_FRAME_POINTER_REGNUM
|| !frame_pointer_needed))
{
- int nr = HARD_REGNO_NREGS (regno, rld[r].mode);
+ int nr = hard_regno_nregs[regno][rld[r].mode];
int k;
rld[r].reg_rtx = equiv;
reload_inherited[r] = 1;
/* Some sanity tests to verify that the reloads found in the first
pass are identical to the ones we have now. */
- if (chain->n_reloads != n_reloads)
- abort ();
+ gcc_assert (chain->n_reloads == n_reloads);
for (i = 0; i < n_reloads; i++)
{
if (chain->rld[i].regno < 0 || chain->rld[i].reg_rtx != 0)
continue;
- if (chain->rld[i].when_needed != rld[i].when_needed)
- abort ();
+ gcc_assert (chain->rld[i].when_needed == rld[i].when_needed);
for (j = 0; j < n_spills; j++)
if (spill_regs[j] == chain->rld[i].regno)
if (! set_reload_reg (j, i))
if (reload_inherited[r] && rld[r].reg_rtx)
check_reg = rld[r].reg_rtx;
else if (reload_override_in[r]
- && (GET_CODE (reload_override_in[r]) == REG
+ && (REG_P (reload_override_in[r])
|| GET_CODE (reload_override_in[r]) == SUBREG))
check_reg = reload_override_in[r];
else
/* I is nonneg if this reload uses a register.
If rld[r].reg_rtx is 0, this is an optional reload
that we opted to ignore. */
- if (rld[r].out_reg != 0 && GET_CODE (rld[r].out_reg) == REG
+ if (rld[r].out_reg != 0 && REG_P (rld[r].out_reg)
&& rld[r].reg_rtx != 0)
{
int nregno = REGNO (rld[r].out_reg);
int nr = 1;
if (nregno < FIRST_PSEUDO_REGISTER)
- nr = HARD_REGNO_NREGS (nregno, rld[r].mode);
+ nr = hard_regno_nregs[nregno][rld[r].mode];
while (--nr >= 0)
reg_has_output_reload[nregno + nr] = 1;
if (i >= 0)
{
- nr = HARD_REGNO_NREGS (i, rld[r].mode);
+ nr = hard_regno_nregs[i][rld[r].mode];
while (--nr >= 0)
SET_HARD_REG_BIT (reg_is_output_reload, i + nr);
}
- if (rld[r].when_needed != RELOAD_OTHER
- && rld[r].when_needed != RELOAD_FOR_OUTPUT
- && rld[r].when_needed != RELOAD_FOR_INSN)
- abort ();
+ gcc_assert (rld[r].when_needed == RELOAD_OTHER
+ || rld[r].when_needed == RELOAD_FOR_OUTPUT
+ || rld[r].when_needed == RELOAD_FOR_INSN);
}
}
}
so abort. */
if (rld[j].reg_rtx)
for (k = 0; k < j; k++)
- if (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))
- abort ();
+ 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));
}
}
}
because we will use this equiv reg right away. */
if (oldequiv == 0 && optimize
- && (GET_CODE (old) == MEM
- || (GET_CODE (old) == REG
+ && (MEM_P (old)
+ || (REG_P (old)
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (old)] < 0)))
oldequiv = find_equiv_reg (old, insn, ALL_REGS, -1, NULL, 0, mode);
find the pseudo in RELOAD_IN_REG. */
if (oldequiv == 0
&& reload_override_in[j]
- && GET_CODE (rl->in_reg) == REG)
+ && REG_P (rl->in_reg))
{
oldequiv = old;
old = rl->in_reg;
}
if (oldequiv == 0)
oldequiv = old;
- else if (GET_CODE (oldequiv) == REG)
+ else if (REG_P (oldequiv))
oldequiv_reg = oldequiv;
else if (GET_CODE (oldequiv) == SUBREG)
oldequiv_reg = SUBREG_REG (oldequiv);
with an output-reload, see if we can prove there was
actually no need to store the old value in it. */
- if (optimize && GET_CODE (oldequiv) == REG
+ if (optimize && REG_P (oldequiv)
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
- && GET_CODE (old) == REG
+ && REG_P (old)
&& (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
rl->out_reg)))
where = &other_input_address_reload_insns;
break;
default:
- abort ();
+ gcc_unreachable ();
}
push_to_sequence (*where);
/* We are not going to bother supporting the case where a
incremented register can't be copied directly from
OLDEQUIV since this seems highly unlikely. */
- if (rl->secondary_in_reload >= 0)
- abort ();
+ gcc_assert (rl->secondary_in_reload < 0);
if (reload_inherited[j])
oldequiv = reloadreg;
old = XEXP (rl->in_reg, 0);
- if (optimize && GET_CODE (oldequiv) == REG
+ if (optimize && REG_P (oldequiv)
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
&& spill_reg_store[REGNO (oldequiv)]
- && GET_CODE (old) == REG
+ && REG_P (old)
&& (dead_or_set_p (insn,
spill_reg_stored_to[REGNO (oldequiv)])
|| rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
insn, see if we can get rid of that pseudo-register entirely
by redirecting the previous insn into our reload register. */
- else if (optimize && GET_CODE (old) == REG
+ else if (optimize && REG_P (old)
&& REGNO (old) >= FIRST_PSEUDO_REGISTER
&& dead_or_set_p (insn, old)
/* This is unsafe if some other reload
rl->when_needed, old, rl->out, j, 0))
{
rtx temp = PREV_INSN (insn);
- while (temp && GET_CODE (temp) == NOTE)
+ while (temp && NOTE_P (temp))
temp = PREV_INSN (temp);
if (temp
- && GET_CODE (temp) == INSN
+ && NONJUMP_INSN_P (temp)
&& GET_CODE (PATTERN (temp)) == SET
&& SET_DEST (PATTERN (temp)) == old
/* Make sure we can access insn_operand_constraint. */
a reload register, and its spill_reg_store entry will
contain the previous destination. This is now
invalid. */
- if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
+ if (REG_P (SET_SRC (PATTERN (temp)))
&& REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
{
spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
tmp = oldequiv;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
- if (GET_CODE (tmp) == REG
+ if (REG_P (tmp)
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (tmp)] != 0
|| reg_equiv_constant[REGNO (tmp)] != 0))
tmp = old;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
- if (GET_CODE (tmp) == REG
+ if (REG_P (tmp)
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (tmp)] != 0
|| reg_equiv_constant[REGNO (tmp)] != 0))
{
rtx real_oldequiv = oldequiv;
- if ((GET_CODE (oldequiv) == REG
+ if ((REG_P (oldequiv)
&& REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
&& (reg_equiv_memory_loc[REGNO (oldequiv)] != 0
|| reg_equiv_constant[REGNO (oldequiv)] != 0))
|| (GET_CODE (oldequiv) == SUBREG
- && GET_CODE (SUBREG_REG (oldequiv)) == REG
+ && REG_P (SUBREG_REG (oldequiv))
&& (REGNO (SUBREG_REG (oldequiv))
>= FIRST_PSEUDO_REGISTER)
&& ((reg_equiv_memory_loc
if (asm_noperands (PATTERN (insn)) < 0)
/* It's the compiler's fault. */
fatal_insn ("VOIDmode on an output", insn);
- error_for_asm (insn, "output operand is constant in `asm'");
+ error_for_asm (insn, "output operand is constant in %<asm%>");
/* Prevent crash--use something we know is valid. */
mode = word_mode;
old = gen_rtx_REG (mode, REGNO (reloadreg));
{
rtx real_old = old;
- if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
+ if (REG_P (old) && REGNO (old) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[REGNO (old)] != 0)
real_old = reg_equiv_mem[REGNO (old)];
/* Don't output the last reload if OLD is not the dest of
INSN and is in the src and is clobbered by INSN. */
if (! flag_expensive_optimizations
- || GET_CODE (old) != REG
+ || !REG_P (old)
|| !(set = single_set (insn))
|| rtx_equal_p (old, SET_DEST (set))
|| !reg_mentioned_p (old, SET_SRC (set))
do_input_reload (struct insn_chain *chain, struct reload *rl, int j)
{
rtx insn = chain->insn;
- rtx old = (rl->in && GET_CODE (rl->in) == MEM
+ rtx old = (rl->in && MEM_P (rl->in)
? rl->in_reg : rl->in);
if (old != 0
e.g. inheriting a SImode output reload for
(mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */
if (optimize && reload_inherited[j] && rl->in
- && GET_CODE (rl->in) == MEM
- && GET_CODE (rl->in_reg) == MEM
+ && MEM_P (rl->in)
+ && MEM_P (rl->in_reg)
&& reload_spill_index[j] >= 0
&& TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
if (optimize
&& (reload_inherited[j] || reload_override_in[j])
&& rl->reg_rtx
- && GET_CODE (rl->reg_rtx) == REG
+ && REG_P (rl->reg_rtx)
&& spill_reg_store[REGNO (rl->reg_rtx)] != 0
#if 0
/* There doesn't seem to be any reason to restrict this to pseudos
if (pseudo
&& optimize
- && GET_CODE (pseudo) == REG
+ && REG_P (pseudo)
&& ! rtx_equal_p (rl->in_reg, pseudo)
&& REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
&& reg_last_reload_reg[REGNO (pseudo)])
/* An output operand that dies right away does need a reload,
but need not be copied from it. Show the new location in the
REG_UNUSED note. */
- if ((GET_CODE (old) == REG || GET_CODE (old) == SCRATCH)
+ if ((REG_P (old) || GET_CODE (old) == SCRATCH)
&& (note = find_reg_note (insn, REG_UNUSED, old)) != 0)
{
XEXP (note, 0) = rl->reg_rtx;
}
/* Likewise for a SUBREG of an operand that dies. */
else if (GET_CODE (old) == SUBREG
- && GET_CODE (SUBREG_REG (old)) == REG
+ && REG_P (SUBREG_REG (old))
&& 0 != (note = find_reg_note (insn, REG_UNUSED,
SUBREG_REG (old))))
{
return;
/* If is a JUMP_INSN, we can't support output reloads yet. */
- if (GET_CODE (insn) == JUMP_INSN)
- abort ();
+ gcc_assert (!JUMP_P (insn));
emit_output_reload_insns (chain, rld + j, j);
}
+/* Reload number R reloads from or to a group of hard registers starting at
+ register REGNO. Return true if it can be treated for inheritance purposes
+ like a group of reloads, each one reloading a single hard register.
+ The caller has already checked that the spill register and REGNO use
+ the same number of registers to store the reload value. */
+
+static bool
+inherit_piecemeal_p (int r ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED)
+{
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ return (!REG_CANNOT_CHANGE_MODE_P (reload_spill_index[r],
+ GET_MODE (rld[r].reg_rtx),
+ reg_raw_mode[reload_spill_index[r]])
+ && !REG_CANNOT_CHANGE_MODE_P (regno,
+ GET_MODE (rld[r].reg_rtx),
+ reg_raw_mode[regno]));
+#else
+ return true;
+#endif
+}
+
/* Output insns to reload values in and out of the chosen reload regs. */
static void
other_operand_reload_insns = 0;
/* Dump reloads into the dump file. */
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "\nReloads for insn # %d\n", INSN_UID (insn));
- debug_reload_to_stream (rtl_dump_file);
+ fprintf (dump_file, "\nReloads for insn # %d\n", INSN_UID (insn));
+ debug_reload_to_stream (dump_file);
}
/* Now output the instructions to copy the data into and out of the
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
- if (GET_CODE (reg) == REG
+ if (REG_P (reg)
&& REGNO (reg) >= FIRST_PSEUDO_REGISTER
&& ! reg_has_output_reload[REGNO (reg)])
{
if (i >= 0 && rld[r].reg_rtx != 0)
{
- int nr = HARD_REGNO_NREGS (i, GET_MODE (rld[r].reg_rtx));
+ int nr = hard_regno_nregs[i][GET_MODE (rld[r].reg_rtx)];
int k;
int part_reaches_end = 0;
int all_reaches_end = 1;
If consecutive registers are used, clear them all. */
for (k = 0; k < nr; k++)
+ {
CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k);
+ }
/* Maybe the spill reg contains a copy of reload_out. */
if (rld[r].out != 0
- && (GET_CODE (rld[r].out) == REG
+ && (REG_P (rld[r].out)
#ifdef AUTO_INC_DEC
|| ! rld[r].out_reg
#endif
- || GET_CODE (rld[r].out_reg) == REG))
+ || REG_P (rld[r].out_reg)))
{
- rtx out = (GET_CODE (rld[r].out) == REG
+ rtx out = (REG_P (rld[r].out)
? rld[r].out
: rld[r].out_reg
? rld[r].out_reg
/* AUTO_INC */ : XEXP (rld[r].in_reg, 0));
int nregno = REGNO (out);
int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (rld[r].reg_rtx)));
+ : hard_regno_nregs[nregno]
+ [GET_MODE (rld[r].reg_rtx)]);
+ bool piecemeal;
spill_reg_store[i] = new_spill_reg_store[i];
spill_reg_stored_to[i] = out;
reg_last_reload_reg[nregno] = rld[r].reg_rtx;
+ piecemeal = (nregno < FIRST_PSEUDO_REGISTER
+ && nr == nnr
+ && inherit_piecemeal_p (r, nregno));
+
/* If NREGNO is a hard register, it may occupy more than
one register. If it does, say what is in the
rest of the registers assuming that both registers
if (nregno < FIRST_PSEUDO_REGISTER)
for (k = 1; k < nnr; k++)
reg_last_reload_reg[nregno + k]
- = (nr == nnr
+ = (piecemeal
? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
: 0);
{
CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
reg_reloaded_contents[i + k]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ = (nregno >= FIRST_PSEUDO_REGISTER || !piecemeal
? nregno
: nregno + k);
reg_reloaded_insn[i + k] = insn;
SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i + k, GET_MODE (out)))
+ SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k);
}
}
the register being reloaded. */
else if (rld[r].out_reg == 0
&& rld[r].in != 0
- && ((GET_CODE (rld[r].in) == REG
+ && ((REG_P (rld[r].in)
&& REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER
&& ! reg_has_output_reload[REGNO (rld[r].in)])
- || (GET_CODE (rld[r].in_reg) == REG
+ || (REG_P (rld[r].in_reg)
&& ! reg_has_output_reload[REGNO (rld[r].in_reg)]))
&& ! reg_set_p (rld[r].reg_rtx, PATTERN (insn)))
{
int nregno;
int nnr;
+ rtx in;
+ bool piecemeal;
- if (GET_CODE (rld[r].in) == REG
+ if (REG_P (rld[r].in)
&& REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER)
- nregno = REGNO (rld[r].in);
- else if (GET_CODE (rld[r].in_reg) == REG)
- nregno = REGNO (rld[r].in_reg);
+ in = rld[r].in;
+ else if (REG_P (rld[r].in_reg))
+ in = rld[r].in_reg;
else
- nregno = REGNO (XEXP (rld[r].in_reg, 0));
+ in = XEXP (rld[r].in_reg, 0);
+ nregno = REGNO (in);
nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (rld[r].reg_rtx)));
+ : hard_regno_nregs[nregno]
+ [GET_MODE (rld[r].reg_rtx)]);
reg_last_reload_reg[nregno] = rld[r].reg_rtx;
+ piecemeal = (nregno < FIRST_PSEUDO_REGISTER
+ && nr == nnr
+ && inherit_piecemeal_p (r, nregno));
+
if (nregno < FIRST_PSEUDO_REGISTER)
for (k = 1; k < nnr; k++)
reg_last_reload_reg[nregno + k]
- = (nr == nnr
+ = (piecemeal
? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
: 0);
{
CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
reg_reloaded_contents[i + k]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ = (nregno >= FIRST_PSEUDO_REGISTER || !piecemeal
? nregno
: nregno + k);
reg_reloaded_insn[i + k] = insn;
SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ if (HARD_REGNO_CALL_PART_CLOBBERED (i + k, GET_MODE (in)))
+ SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered, i + k);
}
}
}
But forget_old_reloads_1 won't get to see it, because
it thinks only about the original insn. So invalidate it here. */
if (i < 0 && rld[r].out != 0
- && (GET_CODE (rld[r].out) == REG
- || (GET_CODE (rld[r].out) == MEM
- && GET_CODE (rld[r].out_reg) == REG)))
+ && (REG_P (rld[r].out)
+ || (MEM_P (rld[r].out)
+ && REG_P (rld[r].out_reg))))
{
- rtx out = (GET_CODE (rld[r].out) == REG
+ rtx out = (REG_P (rld[r].out)
? rld[r].out : rld[r].out_reg);
int nregno = REGNO (out);
if (nregno >= FIRST_PSEUDO_REGISTER)
}
else
store_insn = new_spill_reg_store[REGNO (src_reg)];
- if (src_reg && GET_CODE (src_reg) == REG
+ if (src_reg && REG_P (src_reg)
&& REGNO (src_reg) < FIRST_PSEUDO_REGISTER)
{
int src_regno = REGNO (src_reg);
- int nr = HARD_REGNO_NREGS (src_regno, rld[r].mode);
+ int nr = hard_regno_nregs[src_regno][rld[r].mode];
/* The place where to find a death note varies with
PRESERVE_DEATH_INFO_REGNO_P . The condition is not
necessarily checked exactly in the code that moves
reg_reloaded_insn[src_regno + nr] = store_insn;
CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + nr);
SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr);
+ if (HARD_REGNO_CALL_PART_CLOBBERED (src_regno + nr,
+ GET_MODE (src_reg)))
+ SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
+ src_regno + nr);
SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
if (note)
SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
}
reg_last_reload_reg[nregno] = src_reg;
+ /* We have to set reg_has_output_reload here, or else
+ forget_old_reloads_1 will clear reg_last_reload_reg
+ right away. */
+ reg_has_output_reload[nregno] = 1;
}
}
else
{
- int num_regs = HARD_REGNO_NREGS (nregno, GET_MODE (rld[r].out));
+ int num_regs = hard_regno_nregs[nregno][GET_MODE (rld[r].out)];
while (num_regs-- > 0)
reg_last_reload_reg[nregno + num_regs] = 0;
Returns first insn emitted. */
-rtx
+static rtx
gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
{
rtx last = get_last_insn ();
??? At some point, this whole thing needs to be rethought. */
if (GET_CODE (in) == PLUS
- && (GET_CODE (XEXP (in, 0)) == REG
+ && (REG_P (XEXP (in, 0))
|| GET_CODE (XEXP (in, 0)) == SUBREG
- || GET_CODE (XEXP (in, 0)) == MEM)
- && (GET_CODE (XEXP (in, 1)) == REG
+ || MEM_P (XEXP (in, 0)))
+ && (REG_P (XEXP (in, 1))
|| GET_CODE (XEXP (in, 1)) == SUBREG
|| CONSTANT_P (XEXP (in, 1))
- || GET_CODE (XEXP (in, 1)) == MEM))
+ || MEM_P (XEXP (in, 1))))
{
/* We need to compute the sum of a register or a MEM and another
register, constant, or MEM, and put it into the reload
the case. If the insn would be A = B + A, rearrange it so
it will be A = A + B as constrain_operands expects. */
- if (GET_CODE (XEXP (in, 1)) == REG
+ if (REG_P (XEXP (in, 1))
&& REGNO (out) == REGNO (XEXP (in, 1)))
tem = op0, op0 = op1, op1 = tem;
code = (int) add_optab->handlers[(int) GET_MODE (out)].insn_code;
- if (CONSTANT_P (op1) || GET_CODE (op1) == MEM || GET_CODE (op1) == SUBREG
- || (GET_CODE (op1) == REG
+ if (CONSTANT_P (op1) || MEM_P (op1) || GET_CODE (op1) == SUBREG
+ || (REG_P (op1)
&& REGNO (op1) >= FIRST_PSEUDO_REGISTER)
|| (code != CODE_FOR_nothing
&& ! ((*insn_data[code].operand[2].predicate)
#ifdef SECONDARY_MEMORY_NEEDED
/* If we need a memory location to do the move, do it that way. */
- else if ((GET_CODE (in) == REG || GET_CODE (in) == SUBREG)
+ else if ((REG_P (in) || GET_CODE (in) == SUBREG)
&& reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
- && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG)
+ && (REG_P (out) || GET_CODE (out) == SUBREG)
&& reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
REGNO_REG_CLASS (reg_or_subregno (out)),
#endif
/* If IN is a simple operand, use gen_move_insn. */
- else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
+ else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
emit_insn (gen_move_insn (out, in));
#ifdef HAVE_reload_load_address
rtx reg2 = rld[k].in;
if (! reg2)
continue;
- if (GET_CODE (reg2) == MEM || reload_override_in[k])
+ if (MEM_P (reg2) || reload_override_in[k])
reg2 = rld[k].in_reg;
#ifdef AUTO_INC_DEC
if (rld[k].out && ! rld[k].out_reg)
for (i1 = NEXT_INSN (output_reload_insn);
i1 != insn; i1 = NEXT_INSN (i1))
{
- if (GET_CODE (i1) == CODE_LABEL || GET_CODE (i1) == JUMP_INSN)
+ if (LABEL_P (i1) || JUMP_P (i1))
return;
- if ((GET_CODE (i1) == INSN || GET_CODE (i1) == CALL_INSN)
+ if ((NONJUMP_INSN_P (i1) || CALL_P (i1))
&& reg_mentioned_p (reg, PATTERN (i1)))
{
/* If this is USE in front of INSN, we only have to check that
there are no more references than accounted for by inheritance. */
- while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE)
+ while (NONJUMP_INSN_P (i1) && GET_CODE (PATTERN (i1)) == USE)
{
n_occurrences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
i1 = NEXT_INSN (i1);
}
/* We will be deleting the insn. Remove the spill reg information. */
- for (k = HARD_REGNO_NREGS (last_reload_reg, GET_MODE (reg)); k-- > 0; )
+ for (k = hard_regno_nregs[last_reload_reg][GET_MODE (reg)]; k-- > 0; )
{
spill_reg_store[last_reload_reg + k] = 0;
spill_reg_stored_to[last_reload_reg + k] = 0;
since if they are the only uses, they are dead. */
if (set != 0 && SET_DEST (set) == reg)
continue;
- if (GET_CODE (i2) == CODE_LABEL
- || GET_CODE (i2) == JUMP_INSN)
+ if (LABEL_P (i2)
+ || JUMP_P (i2))
break;
- if ((GET_CODE (i2) == INSN || GET_CODE (i2) == CALL_INSN)
+ if ((NONJUMP_INSN_P (i2) || CALL_P (i2))
&& reg_mentioned_p (reg, PATTERN (i2)))
{
/* Some other ref remains; just delete the output reload we
delete_address_reloads (i2, insn);
delete_insn (i2);
}
- if (GET_CODE (i2) == CODE_LABEL
- || GET_CODE (i2) == JUMP_INSN)
+ if (LABEL_P (i2)
+ || JUMP_P (i2))
break;
}
if (set)
{
rtx dst = SET_DEST (set);
- if (GET_CODE (dst) == MEM)
+ if (MEM_P (dst))
delete_address_reloads_1 (dead_insn, XEXP (dst, 0), current_insn);
}
/* If we deleted the store from a reloaded post_{in,de}c expression,
code = GET_CODE (prev);
if (code == CODE_LABEL || code == JUMP_INSN)
return;
- if (GET_RTX_CLASS (code) != 'i')
+ if (!INSN_P (prev))
continue;
if (reg_set_p (x, PATTERN (prev)))
break;
if (! set)
return;
dst = SET_DEST (set);
- if (GET_CODE (dst) != REG
+ if (!REG_P (dst)
|| ! rtx_equal_p (dst, x))
return;
if (! reg_set_p (dst, PATTERN (dead_insn)))
it might have been inherited. */
for (i2 = NEXT_INSN (dead_insn); i2; i2 = NEXT_INSN (i2))
{
- if (GET_CODE (i2) == CODE_LABEL)
+ if (LABEL_P (i2))
break;
if (! INSN_P (i2))
continue;
}
return;
}
- if (GET_CODE (i2) == JUMP_INSN)
+ if (JUMP_P (i2))
break;
/* If DST is still live at CURRENT_INSN, check if it is used for
any reload. Note that even if CURRENT_INSN sets DST, we still
inc/dec operation. If REG_LAST_RELOAD_REG were nonzero,
we could inc/dec that register as well (maybe even using it for
the source), but I'm not sure it's worth worrying about. */
- if (GET_CODE (incloc) == REG)
+ if (REG_P (incloc))
reg_last_reload_reg[REGNO (incloc)] = 0;
if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC)
FOR_EACH_BB (bb)
{
edge e;
+ edge_iterator ei;
/* Look for cases we are interested in - calls or instructions causing
exceptions. */
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
{
if (e->flags & EDGE_ABNORMAL_CALL)
break;
== (EDGE_ABNORMAL | EDGE_EH))
break;
}
- if (e && GET_CODE (bb->end) != CALL_INSN && !can_throw_internal (bb->end))
+ if (e && !CALL_P (BB_END (bb))
+ && !can_throw_internal (BB_END (bb)))
{
- rtx insn = bb->end, stop = NEXT_INSN (bb->end);
+ rtx insn = BB_END (bb), stop = NEXT_INSN (BB_END (bb));
rtx next;
- for (e = bb->succ; e; e = e->succ_next)
+ FOR_EACH_EDGE (e, ei, bb->succs)
if (e->flags & EDGE_FALLTHRU)
break;
/* Get past the new insns generated. Allow notes, as the insns may
be already deleted. */
- while ((GET_CODE (insn) == INSN || GET_CODE (insn) == NOTE)
+ while ((NONJUMP_INSN_P (insn) || NOTE_P (insn))
&& !can_throw_internal (insn)
- && insn != bb->head)
+ && insn != BB_HEAD (bb))
insn = PREV_INSN (insn);
- if (GET_CODE (insn) != CALL_INSN && !can_throw_internal (insn))
- abort ();
- bb->end = insn;
+ gcc_assert (CALL_P (insn) || can_throw_internal (insn));
+ BB_END (bb) = insn;
inserted = true;
insn = NEXT_INSN (insn);
while (insn && insn != stop)