/* Reload pseudo regs into hard regs for insns that require hard regs.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
This file is part of GCC.
#include "machmode.h"
#include "hard-reg-set.h"
-#include "rtl.h"
+#include "rtl-error.h"
#include "tm_p.h"
#include "obstack.h"
#include "insn-config.h"
+#include "ggc.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
#include "reload.h"
#include "recog.h"
#include "output.h"
-#include "toplev.h"
#include "except.h"
#include "tree.h"
#include "ira.h"
fixing up each insn, and generating the new insns to copy values
into the reload registers. */
\f
+struct target_reload default_target_reload;
+#if SWITCHABLE_TARGET
+struct target_reload *this_target_reload = &default_target_reload;
+#endif
+
+#define spill_indirect_levels \
+ (this_target_reload->x_spill_indirect_levels)
+
/* During reload_as_needed, element N contains a REG rtx for the hard reg
into which reg N has been reloaded (perhaps for a previous insn). */
static rtx *reg_last_reload_reg;
in the current insn. */
static HARD_REG_SET reg_is_output_reload;
-/* Element N is the constant value to which pseudo reg N is equivalent,
- or zero if pseudo reg N is not equivalent to a constant.
- find_reloads looks at this in order to replace pseudo reg N
- with the constant it stands for. */
-rtx *reg_equiv_constant;
-
-/* Element N is an invariant value to which pseudo reg N is equivalent.
- eliminate_regs_in_insn uses this to replace pseudos in particular
- contexts. */
-rtx *reg_equiv_invariant;
-
-/* Element N is a memory location to which pseudo reg N is equivalent,
- prior to any register elimination (such as frame pointer to stack
- pointer). Depending on whether or not it is a valid address, this value
- 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. */
-VEC(rtx,gc) *reg_equiv_memory_loc_vec;
-
-/* 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.) */
-rtx *reg_equiv_address;
-
-/* Element N is the memory slot to which pseudo reg N is equivalent,
- or zero if pseudo reg N is not equivalent to a memory slot. */
-rtx *reg_equiv_mem;
-
-/* Element N is an EXPR_LIST of REG_EQUIVs containing MEMs with
- alternate representations of the location of pseudo reg N. */
-rtx *reg_equiv_alt_mem_list;
-
/* Widest width in which each pseudo reg is referred to (via subreg). */
static unsigned int *reg_max_ref_width;
-/* Element N is the list of insns that initialized reg N from its equivalent
- constant or memory slot. */
-rtx *reg_equiv_init;
-int reg_equiv_init_size;
-
/* Vector to remember old contents of reg_renumber before spilling. */
static short *reg_old_renumber;
a round-robin fashion. */
static int last_spill_reg;
-/* Nonzero if indirect addressing is supported on the machine; this means
- that spilling (REG n) does not require reloading it into a register in
- order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The
- value indicates the level of indirect addressing supported, e.g., two
- means that (MEM (MEM (REG n))) is also valid if (REG n) does not get
- a hard register. */
-static char spill_indirect_levels;
-
-/* Nonzero if indirect addressing is supported when the innermost MEM is
- of the form (MEM (SYMBOL_REF sym)). It is assumed that the level to
- which these are valid is the same as spill_indirect_levels, above. */
-char indirect_symref_ok;
-
-/* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid. */
-char double_reg_address_ok;
-
/* Record the stack slot for each spilled hard register. */
static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER];
Required by some machines to handle any generated moves differently. */
int reload_in_progress = 0;
-/* These arrays record the insn_code of insns that may be needed to
- perform input and output reloads of special objects. They provide a
- place to pass a scratch register. */
-enum insn_code reload_in_optab[NUM_MACHINE_MODES];
-enum insn_code reload_out_optab[NUM_MACHINE_MODES];
-
/* This obstack is used for allocation of rtl during register elimination.
The allocated storage can be freed once find_reloads has processed the
insn. */
examine. */
struct insn_chain *reload_insn_chain;
+/* TRUE if we potentially left dead insns in the insn stream and want to
+ run DCE immediately after reload, FALSE otherwise. */
+static bool need_dce;
+
/* List of all insns needing reloads. */
static struct insn_chain *insns_need_reload;
\f
static char *offsets_known_at;
static HOST_WIDE_INT (*offsets_at)[NUM_ELIMINABLE_REGS];
+VEC(reg_equivs_t,gc) *reg_equivs;
+
/* Stack of addresses where an rtx has been changed. We can undo the
changes by popping items off the stack and restoring the original
value at each location.
static int set_reload_reg (int, int);
static void choose_reload_regs_init (struct insn_chain *, rtx *);
static void choose_reload_regs (struct insn_chain *);
-static void merge_assigned_reloads (rtx);
static void emit_input_reload_insns (struct insn_chain *, struct reload *,
rtx, int);
static void emit_output_reload_insns (struct insn_chain *, struct reload *,
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 rtx inc_for_reload (rtx, rtx, rtx, int);
+static void inc_for_reload (rtx, rtx, rtx, int);
#ifdef AUTO_INC_DEC
static void add_auto_inc_notes (rtx, rtx);
#endif
if (regno < FIRST_PSEUDO_REGISTER)
return;
- x = eliminate_regs (x, mem_mode, usage);
+ x = eliminate_regs_1 (x, mem_mode, usage, true, false);
if (x != *loc)
{
*loc = x;
return;
}
- if (reg_equiv_constant[regno])
- *loc = reg_equiv_constant[regno];
- else if (reg_equiv_mem[regno])
- *loc = reg_equiv_mem[regno];
- else if (reg_equiv_address[regno])
- *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]);
+ if (reg_equiv_constant (regno))
+ *loc = reg_equiv_constant (regno);
+ else if (reg_equiv_invariant (regno))
+ *loc = reg_equiv_invariant (regno);
+ else if (reg_equiv_mem (regno))
+ *loc = reg_equiv_mem (regno);
+ else if (reg_equiv_address (regno))
+ *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address (regno));
else
{
gcc_assert (!REG_P (regno_reg_rtx[regno])
/* Now see if there's a reachable block with an exceptional incoming
edge. */
FOR_EACH_BB (bb)
- if (bb->flags & BB_REACHABLE)
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (e->flags & EDGE_ABNORMAL)
- return true;
+ if (bb->flags & BB_REACHABLE && bb_has_abnormal_pred (bb))
+ return true;
/* No exceptional block reached exit unexceptionally. */
return false;
}
+/* Grow (or allocate) the REG_EQUIVS array from its current size (which may be
+ zero elements) to MAX_REG_NUM elements.
+
+ Initialize all new fields to NULL and update REG_EQUIVS_SIZE. */
+void
+grow_reg_equivs (void)
+{
+ int old_size = VEC_length (reg_equivs_t, reg_equivs);
+ int max_regno = max_reg_num ();
+ int i;
+
+ VEC_reserve (reg_equivs_t, gc, reg_equivs, max_regno);
+ for (i = old_size; i < max_regno; i++)
+ {
+ VEC_quick_insert (reg_equivs_t, reg_equivs, i, 0);
+ memset (VEC_index (reg_equivs_t, reg_equivs, i), 0, sizeof (reg_equivs_t));
+ }
+
+}
+
\f
/* Global variables used by reload and its subroutines. */
If GLOBAL is zero, we do not have enough information to do that,
so any pseudo reg that is spilled must go to the stack.
- Return value is nonzero if reload failed
- and we must not do any more for this function. */
+ Return value is TRUE if reload likely left dead insns in the
+ stream and a DCE pass should be run to elimiante them. Else the
+ return value is FALSE. */
-int
+bool
reload (rtx first, int global)
{
int i, n;
rtx insn;
struct elim_table *ep;
basic_block bb;
+ bool inserted;
/* Make sure even insns with volatile mem refs are recognizable. */
init_recog ();
if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
df_set_regs_ever_live (i, true);
+ /* Find all the pseudo registers that didn't get hard regs
+ but do have known equivalent constants or memory slots.
+ These include parameters (known equivalent to parameter slots)
+ and cse'd or loop-moved constant memory addresses.
+
+ Record constant equivalents in reg_equiv_constant
+ so they will be substituted by find_reloads.
+ Record memory equivalents in reg_mem_equiv so they can
+ be substituted eventually by altering the REG-rtx's. */
+
+ grow_reg_equivs ();
+ reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
reg_old_renumber = XCNEWVEC (short, max_regno);
memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short));
pseudo_forbidden_regs = XNEWVEC (HARD_REG_SET, max_regno);
spill_hard_reg (from, 1);
}
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
if (frame_pointer_needed)
spill_hard_reg (HARD_FRAME_POINTER_REGNUM, 1);
#endif
so this problem goes away. But that's very hairy. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i])
+ if (reg_renumber[i] < 0 && reg_equiv_memory_loc (i))
{
- rtx x = eliminate_regs (reg_equiv_memory_loc[i], VOIDmode,
+ rtx x = eliminate_regs (reg_equiv_memory_loc (i), VOIDmode,
NULL_RTX);
if (strict_memory_address_addr_space_p
(GET_MODE (regno_reg_rtx[i]), XEXP (x, 0),
MEM_ADDR_SPACE (x)))
- reg_equiv_mem[i] = x, reg_equiv_address[i] = 0;
+ reg_equiv_mem (i) = x, reg_equiv_address (i) = 0;
else if (CONSTANT_P (XEXP (x, 0))
|| (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
&& (REGNO (XEXP (XEXP (x, 0), 0))
< FIRST_PSEUDO_REGISTER)
&& CONSTANT_P (XEXP (XEXP (x, 0), 1))))
- reg_equiv_address[i] = XEXP (x, 0), reg_equiv_mem[i] = 0;
+ reg_equiv_address (i) = XEXP (x, 0), reg_equiv_mem (i) = 0;
else
{
/* Make a new stack slot. Then indicate that something
below might change some offset. reg_equiv_{mem,address}
will be set up for this pseudo on the next pass around
the loop. */
- reg_equiv_memory_loc[i] = 0;
- reg_equiv_init[i] = 0;
+ reg_equiv_memory_loc (i) = 0;
+ reg_equiv_init (i) = 0;
alter_reg (i, -1, true);
}
}
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
{
- if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0)
+ if (reg_renumber[i] < 0 && reg_equiv_init (i) != 0)
{
rtx list;
- for (list = reg_equiv_init[i]; list; list = XEXP (list, 1))
+ for (list = reg_equiv_init (i); list; list = XEXP (list, 1))
{
rtx equiv_insn = XEXP (list, 0);
{
rtx addr = 0;
- if (reg_equiv_mem[i])
- addr = XEXP (reg_equiv_mem[i], 0);
+ if (reg_equiv_mem (i))
+ addr = XEXP (reg_equiv_mem (i), 0);
- if (reg_equiv_address[i])
- addr = reg_equiv_address[i];
+ if (reg_equiv_address (i))
+ addr = reg_equiv_address (i);
if (addr)
{
REG_USERVAR_P (reg) = 0;
PUT_CODE (reg, MEM);
XEXP (reg, 0) = addr;
- if (reg_equiv_memory_loc[i])
- MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc[i]);
+ if (reg_equiv_memory_loc (i))
+ MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc (i));
else
{
MEM_IN_STRUCT_P (reg) = MEM_SCALAR_P (reg) = 0;
}
MEM_NOTRAP_P (reg) = 1;
}
- else if (reg_equiv_mem[i])
- XEXP (reg_equiv_mem[i], 0) = addr;
+ else if (reg_equiv_mem (i))
+ XEXP (reg_equiv_mem (i), 0) = addr;
}
/* We don't want complex addressing modes in debug insns
rtx equiv = 0;
df_ref use, next;
- if (reg_equiv_constant[i])
- equiv = reg_equiv_constant[i];
- else if (reg_equiv_invariant[i])
- equiv = reg_equiv_invariant[i];
+ if (reg_equiv_constant (i))
+ equiv = reg_equiv_constant (i);
+ else if (reg_equiv_invariant (i))
+ equiv = reg_equiv_invariant (i);
else if (reg && MEM_P (reg))
equiv = targetm.delegitimize_address (reg);
else if (reg && REG_P (reg) && (int)REGNO (reg) != i)
/* Indicate that we no longer have known memory locations or constants. */
free_reg_equiv ();
- reg_equiv_init = 0;
+
free (reg_max_ref_width);
free (reg_old_renumber);
free (pseudo_previous_regs);
/* Free all the insn_chain structures at once. */
obstack_free (&reload_obstack, reload_startobj);
unused_insn_chains = 0;
- fixup_abnormal_edges ();
+
+ inserted = fixup_abnormal_edges ();
+
+ /* We've possibly turned single trapping insn into multiple ones. */
+ if (cfun->can_throw_non_call_exceptions)
+ {
+ sbitmap blocks;
+ blocks = sbitmap_alloc (last_basic_block);
+ sbitmap_ones (blocks);
+ find_many_sub_basic_blocks (blocks);
+ sbitmap_free (blocks);
+ }
+
+ if (inserted)
+ commit_edge_insertions ();
/* Replacing pseudos with their memory equivalents might have
created shared rtx. Subsequent passes would get confused
VEC_free (rtx_p, heap, substitute_stack);
- return failure;
+ gcc_assert (bitmap_empty_p (&spilled_pseudos));
+
+ reload_completed = !failure;
+
+ return need_dce;
}
/* Yet another special case. Unfortunately, reg-stack forces people to
/* 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))])
+ && (reg_equiv_constant (REGNO (SET_DEST (set)))
+ || (reg_equiv_invariant (REGNO (SET_DEST (set)))))
+ && reg_equiv_init (REGNO (SET_DEST (set))))
continue;
/* If needed, eliminate any eliminable registers. */
|| (REG_P (SET_SRC (set)) && REG_P (SET_DEST (set))
&& reg_renumber[REGNO (SET_SRC (set))] < 0
&& reg_renumber[REGNO (SET_DEST (set))] < 0
- && reg_equiv_memory_loc[REGNO (SET_SRC (set))] != NULL
- && reg_equiv_memory_loc[REGNO (SET_DEST (set))] != NULL
- && rtx_equal_p (reg_equiv_memory_loc
- [REGNO (SET_SRC (set))],
- reg_equiv_memory_loc
- [REGNO (SET_DEST (set))]))))
+ && reg_equiv_memory_loc (REGNO (SET_SRC (set))) != NULL
+ && reg_equiv_memory_loc (REGNO (SET_DEST (set))) != NULL
+ && rtx_equal_p (reg_equiv_memory_loc (REGNO (SET_SRC (set))),
+ reg_equiv_memory_loc (REGNO (SET_DEST (set)))))))
{
if (ira_conflicts_p)
/* Inform IRA about the insn deletion. */
/* 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_constant (REGNO (SET_DEST (set)))
+ || reg_equiv_invariant (REGNO (SET_DEST (set)))))
{
unsigned regno = REGNO (SET_DEST (set));
- rtx init = reg_equiv_init[regno];
+ rtx init = reg_equiv_init (regno);
if (init)
{
rtx t = eliminate_regs_1 (SET_SRC (set), VOIDmode, insn,
}
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
{
- if (reg_equiv_invariant[i])
+ if (reg_equiv_invariant (i))
{
- if (reg_equiv_init[i])
+ if (reg_equiv_init (i))
{
int cost = reg_equiv_init_cost[i];
if (dump_file)
}
}
- free_reg_equiv ();
free (reg_equiv_init_cost);
}
\f
spill_failure (rtx insn, enum reg_class rclass)
{
if (asm_noperands (PATTERN (insn)) >= 0)
- error_for_asm (insn, "can't find a register in class %qs while "
+ error_for_asm (insn, "can%'t find a register in class %qs while "
"reloading %<asm%>",
reg_class_names[rclass]);
else
static void
delete_dead_insn (rtx insn)
{
- rtx prev = prev_real_insn (insn);
+ rtx prev = prev_active_insn (insn);
rtx prev_dest;
- /* If the previous insn sets a register that dies in our insn, delete it
- too. */
+ /* If the previous insn sets a register that dies in our insn make
+ a note that we want to run DCE immediately after reload.
+
+ We used to delete the previous insn & recurse, but that's wrong for
+ block local equivalences. Instead of trying to figure out the exact
+ circumstances where we can delete the potentially dead insns, just
+ let DCE do the job. */
if (prev && GET_CODE (PATTERN (prev)) == SET
&& (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);
+ need_dce = 1;
SET_INSN_DELETED (insn);
}
if (reg_renumber[i] < 0
&& REG_N_REFS (i) > 0
- && reg_equiv_constant[i] == 0
- && (reg_equiv_invariant[i] == 0 || reg_equiv_init[i] == 0)
- && reg_equiv_memory_loc[i] == 0)
+ && reg_equiv_constant (i) == 0
+ && (reg_equiv_invariant (i) == 0
+ || reg_equiv_init (i) == 0)
+ && reg_equiv_memory_loc (i) == 0)
{
rtx x = NULL_RTX;
enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
set_mem_attrs_for_spill (x);
/* Save the stack slot for later. */
- reg_equiv_memory_loc[i] = x;
+ reg_equiv_memory_loc (i) = x;
}
}
if (REG_P (x)
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
- && reg_equiv_init[REGNO (x)]
- && reg_equiv_invariant[REGNO (x)])
+ && reg_equiv_init (REGNO (x))
+ && reg_equiv_invariant (REGNO (x)))
{
- rtx t = reg_equiv_invariant[REGNO (x)];
+ rtx t = reg_equiv_invariant (REGNO (x));
rtx new_rtx = eliminate_regs_1 (t, Pmode, insn, true, true);
int cost = rtx_cost (new_rtx, SET, optimize_bb_for_speed_p (elim_bb));
int freq = REG_FREQ_FROM_BB (elim_bb);
}
else if (reg_renumber && reg_renumber[regno] < 0
- && reg_equiv_invariant && reg_equiv_invariant[regno])
+ && reg_equivs
+ && reg_equiv_invariant (regno))
{
if (may_use_invariant || (insn && DEBUG_INSN_P (insn)))
- return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]),
+ return eliminate_regs_1 (copy_rtx (reg_equiv_invariant (regno)),
mem_mode, insn, true, for_costs);
/* There exists at least one use of REGNO that cannot be
eliminated. Prevent the defining insn from being deleted. */
- reg_equiv_init[regno] = NULL_RTX;
+ reg_equiv_init (regno) = NULL_RTX;
if (!for_costs)
alter_reg (regno, -1, true);
}
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)];
+ && reg_equivs
+ && reg_equiv_constant (REGNO (new1)) != 0)
+ new1 = reg_equiv_constant (REGNO (new1));
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)
- new0 = reg_equiv_constant[REGNO (new0)];
+ && reg_equiv_constant (REGNO (new0)) != 0)
+ new0 = reg_equiv_constant (REGNO (new0));
new_rtx = form_sum (GET_MODE (x), new0, new1);
eliminated version of the memory location because push_reload
may do the replacement in certain circumstances. */
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
- && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
+ && !paradoxical_subreg_p (x)
+ && reg_equivs
+ && reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0)
{
new_rtx = SUBREG_REG (x);
}
else
- new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false,
- for_costs);
+ new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false, for_costs);
if (new_rtx != SUBREG_REG (x))
{
return x;
case CLOBBER:
+ case ASM_OPERANDS:
gcc_assert (insn && DEBUG_INSN_P (insn));
break;
- case ASM_OPERANDS:
case SET:
gcc_unreachable ();
}
}
- else if (reg_renumber[regno] < 0 && reg_equiv_constant
- && reg_equiv_constant[regno]
- && ! function_invariant_p (reg_equiv_constant[regno]))
- elimination_effects (reg_equiv_constant[regno], mem_mode);
+ else if (reg_renumber[regno] < 0
+ && reg_equivs != 0
+ && reg_equiv_constant (regno)
+ && ! function_invariant_p (reg_equiv_constant (regno)))
+ elimination_effects (reg_equiv_constant (regno), mem_mode);
return;
case PRE_INC:
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
- && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
+ && reg_equivs != 0
+ && reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0)
return;
elimination_effects (SUBREG_REG (x), mem_mode);
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate)
{
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
/* If this is setting the frame pointer register to the
hardware frame pointer register and this is an elimination
that will be done (tested above), this insn is really
int i;
rtx insn;
- reg_equiv_constant = XCNEWVEC (rtx, max_regno);
- reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
- reg_equiv_mem = XCNEWVEC (rtx, max_regno);
- reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
- reg_equiv_address = XCNEWVEC (rtx, max_regno);
+ grow_reg_equivs ();
if (do_subregs)
reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
else
if (i <= LAST_VIRTUAL_REGISTER)
continue;
- if (! function_invariant_p (x)
- || ! flag_pic
- /* A function invariant is often CONSTANT_P but may
- include a register. We promise to only pass
- CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P. */
- || (CONSTANT_P (x)
- && LEGITIMATE_PIC_OPERAND_P (x)))
+ /* If flag_pic and we have constant, verify it's legitimate. */
+ if (!CONSTANT_P (x)
+ || !flag_pic || LEGITIMATE_PIC_OPERAND_P (x))
{
/* It can happen that a REG_EQUIV note contains a MEM
that is not a legitimate memory operand. As later
/* Always unshare the equivalence, so we can
substitute into this insn without touching the
equivalence. */
- reg_equiv_memory_loc[i] = copy_rtx (x);
+ reg_equiv_memory_loc (i) = copy_rtx (x);
}
else if (function_invariant_p (x))
{
+ enum machine_mode mode;
+
+ mode = GET_MODE (SET_DEST (set));
if (GET_CODE (x) == PLUS)
{
/* This is PLUS of frame pointer and a constant,
and might be shared. Unshare it. */
- reg_equiv_invariant[i] = copy_rtx (x);
+ reg_equiv_invariant (i) = copy_rtx (x);
num_eliminable_invariants++;
}
else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
{
- reg_equiv_invariant[i] = x;
+ reg_equiv_invariant (i) = x;
num_eliminable_invariants++;
}
- else if (LEGITIMATE_CONSTANT_P (x))
- reg_equiv_constant[i] = x;
+ else if (targetm.legitimate_constant_p (mode, x))
+ reg_equiv_constant (i) = x;
else
{
- reg_equiv_memory_loc[i]
- = force_const_mem (GET_MODE (SET_DEST (set)), x);
- if (! reg_equiv_memory_loc[i])
- reg_equiv_init[i] = NULL_RTX;
+ reg_equiv_memory_loc (i) = force_const_mem (mode, x);
+ if (! reg_equiv_memory_loc (i))
+ reg_equiv_init (i) = NULL_RTX;
}
}
else
{
- reg_equiv_init[i] = NULL_RTX;
+ reg_equiv_init (i) = NULL_RTX;
continue;
}
}
else
- reg_equiv_init[i] = NULL_RTX;
+ reg_equiv_init (i) = NULL_RTX;
}
}
if (dump_file)
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_equiv_init[i])
+ if (reg_equiv_init (i))
{
fprintf (dump_file, "init_insns for %u: ", i);
- print_inline_rtx (dump_file, reg_equiv_init[i], 20);
+ print_inline_rtx (dump_file, reg_equiv_init (i), 20);
fprintf (dump_file, "\n");
}
}
{
int i;
- if (reg_equiv_constant)
- free (reg_equiv_constant);
- if (reg_equiv_invariant)
- free (reg_equiv_invariant);
- reg_equiv_constant = 0;
- reg_equiv_invariant = 0;
- VEC_free (rtx, gc, reg_equiv_memory_loc_vec);
- reg_equiv_memory_loc = 0;
-
- if (offsets_known_at)
- free (offsets_known_at);
- if (offsets_at)
- free (offsets_at);
+
+ free (offsets_known_at);
+ free (offsets_at);
offsets_at = 0;
offsets_known_at = 0;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (reg_equiv_alt_mem_list[i])
- free_EXPR_LIST_list (®_equiv_alt_mem_list[i]);
- free (reg_equiv_alt_mem_list);
+ if (reg_equiv_alt_mem_list (i))
+ free_EXPR_LIST_list (®_equiv_alt_mem_list (i));
+ VEC_free (reg_equivs_t, gc, reg_equivs);
+ reg_equivs = NULL;
- free (reg_equiv_mem);
- free (reg_equiv_address);
}
\f
/* Kick all pseudos out of hard register REGNO.
}
}
}
+
+/* *OP_PTR and *OTHER_PTR are two operands to a conceptual reload.
+ If *OP_PTR is a paradoxical subreg, try to remove that subreg
+ and apply the corresponding narrowing subreg to *OTHER_PTR.
+ Return true if the operands were changed, false otherwise. */
+
+static bool
+strip_paradoxical_subreg (rtx *op_ptr, rtx *other_ptr)
+{
+ rtx op, inner, other, tem;
+
+ op = *op_ptr;
+ if (!paradoxical_subreg_p (op))
+ return false;
+ inner = SUBREG_REG (op);
+
+ other = *other_ptr;
+ tem = gen_lowpart_common (GET_MODE (inner), other);
+ if (!tem)
+ return false;
+
+ /* If the lowpart operation turned a hard register into a subreg,
+ rather than simplifying it to another hard register, then the
+ mode change cannot be properly represented. For example, OTHER
+ might be valid in its current mode, but not in the new one. */
+ if (GET_CODE (tem) == SUBREG
+ && REG_P (other)
+ && HARD_REGISTER_P (other))
+ return false;
+
+ *op_ptr = inner;
+ *other_ptr = tem;
+ return true;
+}
\f
/* A subroutine of reload_as_needed. If INSN has a REG_EH_REGION note,
examine all of the reload insns between PREV and NEXT exclusive, and
Record the choices of reload reg in reload_reg_rtx. */
choose_reload_regs (chain);
- /* Merge any reloads that we didn't combine for fear of
- increasing the number of spill registers needed but now
- discover can be safely merged. */
- if (targetm.small_register_classes_for_mode_p (VOIDmode))
- merge_assigned_reloads (insn);
-
/* Generate the insns to reload operands into or out of
their reload regs. */
emit_reload_insns (chain);
{
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);
+
+ /* If this is a call to a setjmp-type function, we must not
+ reuse any reload reg contents across the call; that will
+ just be clobbered by other uses of the register in later
+ code, before the longjmp. */
+ if (find_reg_note (insn, REG_SETJMP, NULL_RTX))
+ CLEAR_HARD_REG_SET (reg_reloaded_valid);
}
}
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 i;
-
- for (i = regno; i < nregs + regno; i++)
+ switch (type)
{
- switch (type)
- {
- case RELOAD_OTHER:
- SET_HARD_REG_BIT (reload_reg_used, i);
- break;
-
- case RELOAD_FOR_INPUT_ADDRESS:
- SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
- break;
+ case RELOAD_OTHER:
+ add_to_hard_reg_set (&reload_reg_used, mode, regno);
+ break;
- case RELOAD_FOR_INPADDR_ADDRESS:
- SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
- break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ add_to_hard_reg_set (&reload_reg_used_in_input_addr[opnum], mode, regno);
+ break;
- case RELOAD_FOR_OUTPUT_ADDRESS:
- SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
- break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ add_to_hard_reg_set (&reload_reg_used_in_inpaddr_addr[opnum], mode, regno);
+ break;
- case RELOAD_FOR_OUTADDR_ADDRESS:
- SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
- break;
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ add_to_hard_reg_set (&reload_reg_used_in_output_addr[opnum], mode, regno);
+ break;
- case RELOAD_FOR_OPERAND_ADDRESS:
- SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
- break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ add_to_hard_reg_set (&reload_reg_used_in_outaddr_addr[opnum], mode, regno);
+ break;
- case RELOAD_FOR_OPADDR_ADDR:
- SET_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, i);
- break;
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ add_to_hard_reg_set (&reload_reg_used_in_op_addr, mode, regno);
+ break;
- case RELOAD_FOR_OTHER_ADDRESS:
- SET_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
- break;
+ case RELOAD_FOR_OPADDR_ADDR:
+ add_to_hard_reg_set (&reload_reg_used_in_op_addr_reload, mode, regno);
+ break;
- case RELOAD_FOR_INPUT:
- SET_HARD_REG_BIT (reload_reg_used_in_input[opnum], i);
- break;
+ case RELOAD_FOR_OTHER_ADDRESS:
+ add_to_hard_reg_set (&reload_reg_used_in_other_addr, mode, regno);
+ break;
- case RELOAD_FOR_OUTPUT:
- SET_HARD_REG_BIT (reload_reg_used_in_output[opnum], i);
- break;
+ case RELOAD_FOR_INPUT:
+ add_to_hard_reg_set (&reload_reg_used_in_input[opnum], mode, regno);
+ break;
- case RELOAD_FOR_INSN:
- SET_HARD_REG_BIT (reload_reg_used_in_insn, i);
- break;
- }
+ case RELOAD_FOR_OUTPUT:
+ add_to_hard_reg_set (&reload_reg_used_in_output[opnum], mode, regno);
+ break;
- SET_HARD_REG_BIT (reload_reg_used_at_all, i);
+ case RELOAD_FOR_INSN:
+ add_to_hard_reg_set (&reload_reg_used_in_insn, mode, regno);
+ break;
}
+
+ add_to_hard_reg_set (&reload_reg_used_at_all, mode, regno);
}
/* Similarly, but show REGNO is no longer in use for a reload. */
chain reloads or do need an intermediate hard registers. */
bool result = true;
int regno, n, code;
- rtx out, in, tem, insn;
+ rtx out, in, insn;
rtx last = get_last_insn ();
/* Make r2 a component of r1. */
/* If IN is a paradoxical SUBREG, remove it and try to put the
opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */
- if (GET_CODE (in) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (in))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
- && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
- in = SUBREG_REG (in), out = tem;
+ strip_paradoxical_subreg (&in, &out);
if (GET_CODE (in) == PLUS
&& (REG_P (XEXP (in, 0))
return 1;
if (GET_CODE (x) == PLUS
&& (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx)
- && CONSTANT_P (XEXP (x, 1)))
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
return 1;
return 0;
}
static int
set_reload_reg (int i, int r)
{
- int regno;
+ /* regno is 'set but not used' if HARD_REGNO_MODE_OK doesn't use its first
+ parameter. */
+ int regno ATTRIBUTE_UNUSED;
rtx reg = spill_reg_rtx[i];
if (reg == 0 || GET_MODE (reg) != rld[r].mode)
if (regno >= 0
&& reg_last_reload_reg[regno] != 0
+ && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
+ >= GET_MODE_SIZE (mode) + byte)
#ifdef CANNOT_CHANGE_MODE_CLASS
/* Verify that the register it's in can be used in
mode MODE. */
{
enum reg_class rclass = rld[r].rclass, last_class;
rtx last_reg = reg_last_reload_reg[regno];
- enum machine_mode need_mode;
i = REGNO (last_reg);
i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
last_class = REGNO_REG_CLASS (i);
- if (byte == 0)
- need_mode = mode;
- else
- need_mode
- = smallest_mode_for_size
- (GET_MODE_BITSIZE (mode) + byte * BITS_PER_UNIT,
- GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
- ? MODE_INT : GET_MODE_CLASS (mode));
-
- if ((GET_MODE_SIZE (GET_MODE (last_reg))
- >= GET_MODE_SIZE (need_mode))
- && reg_reloaded_contents[i] == regno
+ if (reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
&& HARD_REGNO_MODE_OK (i, rld[r].mode)
&& (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], i)
register, we might use it for reload_override_in,
if copying it to the desired class is cheap
enough. */
- || ((REGISTER_MOVE_COST (mode, last_class, rclass)
+ || ((register_move_cost (mode, last_class, rclass)
< memory_move_cost (mode, rclass, true))
&& (secondary_reload_class (1, rclass, mode,
last_reg)
&& (rld[r].nregs == max_group_size
|| ! reg_classes_intersect_p (rld[r].rclass, group_class)))
search_equiv = rld[r].in;
- /* If this is an output reload from a simple move insn, look
- if an equivalence for the input is available. */
- else if (inheritance && rld[r].in == 0 && rld[r].out != 0)
- {
- rtx set = single_set (insn);
-
- if (set
- && rtx_equal_p (rld[r].out, SET_DEST (set))
- && CONSTANT_P (SET_SRC (set)))
- search_equiv = SET_SRC (set);
- }
if (search_equiv)
{
nregno + nr);
if (i >= 0)
- {
- nr = hard_regno_nregs[i][rld[r].mode];
- while (--nr >= 0)
- SET_HARD_REG_BIT (reg_is_output_reload, i + nr);
- }
+ add_to_hard_reg_set (®_is_output_reload, rld[r].mode, i);
gcc_assert (rld[r].when_needed == RELOAD_OTHER
|| rld[r].when_needed == RELOAD_FOR_OUTPUT
reload_spill_index[r] = -1;
}
\f
-/* If the small_register_classes_for_mode_p target hook returns true for
- some machine modes, we may not have merged two reloads of the same item
- for fear that we might not have enough reload registers. However,
- normally they will get the same reload register and hence actually need
- not be loaded twice.
-
- Here we check for the most common case of this phenomenon: when we have
- a number of reloads for the same object, each of which were allocated
- the same reload_reg_rtx, that reload_reg_rtx is not used for any other
- reload, and is not modified in the insn itself. If we find such,
- merge all the reloads and set the resulting reload to RELOAD_OTHER.
- This will not increase the number of spill registers needed and will
- prevent redundant code. */
-
-static void
-merge_assigned_reloads (rtx insn)
-{
- int i, j;
-
- /* Scan all the reloads looking for ones that only load values and
- are not already RELOAD_OTHER and ones whose reload_reg_rtx are
- assigned and not modified by INSN. */
-
- for (i = 0; i < n_reloads; i++)
- {
- int conflicting_input = 0;
- int max_input_address_opnum = -1;
- int min_conflicting_input_opnum = MAX_RECOG_OPERANDS;
-
- if (rld[i].in == 0 || rld[i].when_needed == RELOAD_OTHER
- || rld[i].out != 0 || rld[i].reg_rtx == 0
- || reg_set_p (rld[i].reg_rtx, insn))
- continue;
-
- /* Look at all other reloads. Ensure that the only use of this
- reload_reg_rtx is in a reload that just loads the same value
- as we do. Note that any secondary reloads must be of the identical
- class since the values, modes, and result registers are the
- same, so we need not do anything with any secondary reloads. */
-
- for (j = 0; j < n_reloads; j++)
- {
- if (i == j || rld[j].reg_rtx == 0
- || ! reg_overlap_mentioned_p (rld[j].reg_rtx,
- rld[i].reg_rtx))
- continue;
-
- if (rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- && rld[j].opnum > max_input_address_opnum)
- max_input_address_opnum = rld[j].opnum;
-
- /* If the reload regs aren't exactly the same (e.g, different modes)
- or if the values are different, we can't merge this reload.
- But if it is an input reload, we might still merge
- RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS reloads. */
-
- if (! rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx)
- || rld[j].out != 0 || rld[j].in == 0
- || ! rtx_equal_p (rld[i].in, rld[j].in))
- {
- if (rld[j].when_needed != RELOAD_FOR_INPUT
- || ((rld[i].when_needed != RELOAD_FOR_INPUT_ADDRESS
- || rld[i].opnum > rld[j].opnum)
- && rld[i].when_needed != RELOAD_FOR_OTHER_ADDRESS))
- break;
- conflicting_input = 1;
- if (min_conflicting_input_opnum > rld[j].opnum)
- min_conflicting_input_opnum = rld[j].opnum;
- }
- }
-
- /* If all is OK, merge the reloads. Only set this to RELOAD_OTHER if
- we, in fact, found any matching reloads. */
-
- if (j == n_reloads
- && max_input_address_opnum <= min_conflicting_input_opnum)
- {
- gcc_assert (rld[i].when_needed != RELOAD_FOR_OUTPUT);
-
- for (j = 0; j < n_reloads; j++)
- if (i != j && rld[j].reg_rtx != 0
- && rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx)
- && (! conflicting_input
- || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- || rld[j].when_needed == RELOAD_FOR_OTHER_ADDRESS))
- {
- rld[i].when_needed = RELOAD_OTHER;
- rld[j].in = 0;
- reload_spill_index[j] = -1;
- transfer_replacements (i, j);
- }
-
- /* If this is now RELOAD_OTHER, look for any reloads that
- load parts of this operand and set them to
- RELOAD_FOR_OTHER_ADDRESS if they were for inputs,
- RELOAD_OTHER for outputs. Note that this test is
- equivalent to looking for reloads for this operand
- number.
-
- We must take special care with RELOAD_FOR_OUTPUT_ADDRESS;
- it may share registers with a RELOAD_FOR_INPUT, so we can
- not change it to RELOAD_FOR_OTHER_ADDRESS. We should
- never need to, since we do not modify RELOAD_FOR_OUTPUT.
-
- It is possible that the RELOAD_FOR_OPERAND_ADDRESS
- instruction is assigned the same register as the earlier
- RELOAD_FOR_OTHER_ADDRESS instruction. Merging these two
- instructions will cause the RELOAD_FOR_OTHER_ADDRESS
- instruction to be deleted later on. */
-
- if (rld[i].when_needed == RELOAD_OTHER)
- for (j = 0; j < n_reloads; j++)
- if (rld[j].in != 0
- && rld[j].when_needed != RELOAD_OTHER
- && rld[j].when_needed != RELOAD_FOR_OTHER_ADDRESS
- && rld[j].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
- && rld[j].when_needed != RELOAD_FOR_OPERAND_ADDRESS
- && (! conflicting_input
- || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
- && reg_overlap_mentioned_for_reload_p (rld[j].in,
- rld[i].in))
- {
- int k;
-
- rld[j].when_needed
- = ((rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
- || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
- ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
-
- /* Check to see if we accidentally converted two
- reloads that use the same reload register with
- different inputs to the same type. If so, the
- resulting code won't work. */
- if (rld[j].reg_rtx)
- for (k = 0; k < j; k++)
- gcc_assert (rld[k].in == 0 || rld[k].reg_rtx == 0
- || rld[k].when_needed != rld[j].when_needed
- || !rtx_equal_p (rld[k].reg_rtx,
- rld[j].reg_rtx)
- || rtx_equal_p (rld[k].in,
- rld[j].in));
- }
- }
- }
-}
-\f
/* These arrays are filled by emit_reload_insns and its subroutines. */
static rtx input_reload_insns[MAX_RECOG_OPERANDS];
static rtx other_input_address_reload_insns = 0;
old = XEXP (rl->in_reg, 0);
- if (optimize && REG_P (oldequiv)
- && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
- && spill_reg_store[REGNO (oldequiv)]
- && REG_P (old)
- && (dead_or_set_p (insn,
- spill_reg_stored_to[REGNO (oldequiv)])
- || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
- old)))
- delete_output_reload (insn, j, REGNO (oldequiv), reloadreg);
-
/* Prevent normal processing of this reload. */
special = 1;
- /* Output a special code sequence for this case. */
- new_spill_reg_store[REGNO (reloadreg)]
- = inc_for_reload (reloadreg, oldequiv, rl->out,
- rl->inc);
+ /* Output a special code sequence for this case, and forget about
+ spill reg information. */
+ new_spill_reg_store[REGNO (reloadreg)] = NULL;
+ inc_for_reload (reloadreg, oldequiv, rl->out, rl->inc);
}
/* If we are reloading a pseudo-register that was set by the previous
tmp = SUBREG_REG (tmp);
if (REG_P (tmp)
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
- && (reg_equiv_memory_loc[REGNO (tmp)] != 0
- || reg_equiv_constant[REGNO (tmp)] != 0))
+ && (reg_equiv_memory_loc (REGNO (tmp)) != 0
+ || reg_equiv_constant (REGNO (tmp)) != 0))
{
- if (! reg_equiv_mem[REGNO (tmp)]
+ if (! reg_equiv_mem (REGNO (tmp))
|| num_not_at_initial_offset
|| GET_CODE (oldequiv) == SUBREG)
real_oldequiv = rl->in;
else
- real_oldequiv = reg_equiv_mem[REGNO (tmp)];
+ real_oldequiv = reg_equiv_mem (REGNO (tmp));
}
tmp = old;
tmp = SUBREG_REG (tmp);
if (REG_P (tmp)
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER
- && (reg_equiv_memory_loc[REGNO (tmp)] != 0
- || reg_equiv_constant[REGNO (tmp)] != 0))
+ && (reg_equiv_memory_loc (REGNO (tmp)) != 0
+ || reg_equiv_constant (REGNO (tmp)) != 0))
{
- if (! reg_equiv_mem[REGNO (tmp)]
+ if (! reg_equiv_mem (REGNO (tmp))
|| num_not_at_initial_offset
|| GET_CODE (old) == SUBREG)
real_old = rl->in;
else
- real_old = reg_equiv_mem[REGNO (tmp)];
+ real_old = reg_equiv_mem (REGNO (tmp));
}
second_reload_reg = rld[secondary_reload].reg_rtx;
sri.icode = CODE_FOR_nothing;
sri.prev_sri = NULL;
- new_class = targetm.secondary_reload (1, real_oldequiv, rl->rclass,
- mode, &sri);
+ new_class
+ = (enum reg_class) targetm.secondary_reload (1, real_oldequiv,
+ rl->rclass, mode,
+ &sri);
if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing)
second_reload_reg = 0;
{
sri2.icode = CODE_FOR_nothing;
sri2.prev_sri = &sri;
- new_t_class = targetm.secondary_reload (1, real_oldequiv,
- new_class, mode, &sri);
+ new_t_class
+ = (enum reg_class) targetm.secondary_reload (1, real_oldequiv,
+ new_class, mode,
+ &sri);
if (new_t_class == NO_REGS && sri2.icode == CODE_FOR_nothing)
{
if (reload_adjust_reg_for_temp (&second_reload_reg,
if ((REG_P (oldequiv)
&& REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
- && (reg_equiv_memory_loc[REGNO (oldequiv)] != 0
- || reg_equiv_constant[REGNO (oldequiv)] != 0))
+ && (reg_equiv_memory_loc (REGNO (oldequiv)) != 0
+ || reg_equiv_constant (REGNO (oldequiv)) != 0))
|| (GET_CODE (oldequiv) == SUBREG
&& REG_P (SUBREG_REG (oldequiv))
&& (REGNO (SUBREG_REG (oldequiv))
>= FIRST_PSEUDO_REGISTER)
- && ((reg_equiv_memory_loc
- [REGNO (SUBREG_REG (oldequiv))] != 0)
- || (reg_equiv_constant
- [REGNO (SUBREG_REG (oldequiv))] != 0)))
+ && ((reg_equiv_memory_loc (REGNO (SUBREG_REG (oldequiv))) != 0)
+ || (reg_equiv_constant (REGNO (SUBREG_REG (oldequiv))) != 0)))
|| (CONSTANT_P (oldequiv)
- && (PREFERRED_RELOAD_CLASS (oldequiv,
- REGNO_REG_CLASS (REGNO (reloadreg)))
+ && (targetm.preferred_reload_class (oldequiv,
+ REGNO_REG_CLASS (REGNO (reloadreg)))
== NO_REGS)))
real_oldequiv = rl->in;
gen_reload (reloadreg, real_oldequiv, rl->opnum,
int tertiary_reload = rld[secondary_reload].secondary_out_reload;
if (REG_P (old) && REGNO (old) >= FIRST_PSEUDO_REGISTER
- && reg_equiv_mem[REGNO (old)] != 0)
- real_old = reg_equiv_mem[REGNO (old)];
+ && reg_equiv_mem (REGNO (old)) != 0)
+ real_old = reg_equiv_mem (REGNO (old));
if (secondary_reload_class (0, rl->rclass, mode, real_old) != NO_REGS)
{
if (tertiary_icode != CODE_FOR_nothing)
{
rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
- rtx tem;
/* Copy primary reload reg to secondary reload reg.
(Note that these have been swapped above, then
/* If REAL_OLD is a paradoxical SUBREG, remove it
and try to put the opposite SUBREG on
RELOADREG. */
- if (GET_CODE (real_old) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (real_old))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old))))
- && 0 != (tem = gen_lowpart_common
- (GET_MODE (SUBREG_REG (real_old)),
- reloadreg)))
- real_old = SUBREG_REG (real_old), reloadreg = tem;
+ strip_paradoxical_subreg (&real_old, &reloadreg);
gen_reload (reloadreg, second_reloadreg,
rl->opnum, rl->when_needed);
/* Maybe the spill reg contains a copy of reload_out. */
if (rld[r].out != 0
&& (REG_P (rld[r].out)
-#ifdef AUTO_INC_DEC
- || ! rld[r].out_reg
-#endif
- || REG_P (rld[r].out_reg)))
+ || (rld[r].out_reg
+ ? REG_P (rld[r].out_reg)
+ /* The reload value is an auto-modification of
+ some kind. For PRE_INC, POST_INC, PRE_DEC
+ and POST_DEC, we record an equivalence
+ between the reload register and the operand
+ on the optimistic assumption that we can make
+ the equivalence hold. reload_as_needed must
+ then either make it hold or invalidate the
+ equivalence.
+
+ PRE_MODIFY and POST_MODIFY addresses are reloaded
+ somewhat differently, and allowing them here leads
+ to problems. */
+ : (GET_CODE (rld[r].out) != POST_MODIFY
+ && GET_CODE (rld[r].out) != PRE_MODIFY))))
{
rtx reg;
enum machine_mode mode;
/* If IN is a paradoxical SUBREG, remove it and try to put the
opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */
- if (GET_CODE (in) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (in))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
- && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
- in = SUBREG_REG (in), out = tem;
- else if (GET_CODE (out) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (out))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
- && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0)
- out = SUBREG_REG (out), in = tem;
+ if (!strip_paradoxical_subreg (&in, &out))
+ strip_paradoxical_subreg (&out, &in);
/* How to do this reload can get quite tricky. Normally, we are being
asked to reload a simple operand, such as a MEM, a constant, or a pseudo
not valid than to dummy things up. */
rtx op0, op1, tem, insn;
- int code;
+ enum insn_code code;
op0 = find_replacement (&XEXP (in, 0));
op1 = find_replacement (&XEXP (in, 1));
DEFINE_PEEPHOLE should be specified that recognizes the sequence
we emit below. */
- code = (int) optab_handler (add_optab, GET_MODE (out))->insn_code;
+ code = optab_handler (add_optab, GET_MODE (out));
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)
- (op1, insn_data[code].operand[2].mode))))
+ && !insn_operand_matches (code, 2, op1)))
tem = op0, op0 = op1, op1 = tem;
gen_reload (out, op0, opnum, type);
return insn;
}
- fatal_insn ("Failure trying to reload:", set);
+ fatal_insn ("failure trying to reload:", set);
}
/* If IN is a simple operand, use gen_move_insn. */
else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
int n_inherited = 0;
rtx i1;
rtx substed;
+ unsigned regno;
+ int nregs;
/* It is possible that this reload has been only used to set another reload
we eliminated earlier and thus deleted this instruction too. */
while (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
- substed = reg_equiv_memory_loc[REGNO (reg)];
+ substed = reg_equiv_memory_loc (REGNO (reg));
/* This is unsafe if the operand occurs more often in the current
insn than it is inherited. */
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 (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);
if (n_occurrences > n_inherited)
return;
+ regno = REGNO (reg);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ nregs = 1;
+ else
+ nregs = hard_regno_nregs[regno][GET_MODE (reg)];
+
/* If the pseudo-reg we are reloading is no longer referenced
anywhere between the store into it and here,
and we're within the same basic block, then the value can only
if (NOTE_INSN_BASIC_BLOCK_P (i1))
return;
if ((NONJUMP_INSN_P (i1) || CALL_P (i1))
- && reg_mentioned_p (reg, PATTERN (i1)))
+ && refers_to_regno_p (regno, regno + nregs, PATTERN (i1), NULL))
{
/* If this is USE in front of INSN, we only have to check that
there are no more references than accounted for by inheritance. */
IN is either identical to VALUE, or some cheaper place to reload from.
INC_AMOUNT is the number to increment or decrement by (always positive).
- This cannot be deduced from VALUE.
+ This cannot be deduced from VALUE. */
- Return the instruction that stores into RELOADREG. */
-
-static rtx
+static void
inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
{
/* REG or MEM to be copied and incremented. */
rtx inc;
rtx add_insn;
int code;
- rtx store;
rtx real_in = in == value ? incloc : in;
/* No hard register is equivalent to this register after
if (! post)
emit_insn (gen_move_insn (reloadreg, incloc));
-
- return add_insn;
+ return;
}
}
delete_insns_since (last);
if (in != reloadreg)
emit_insn (gen_move_insn (reloadreg, real_in));
emit_insn (gen_add2_insn (reloadreg, inc));
- store = emit_insn (gen_move_insn (incloc, reloadreg));
+ emit_insn (gen_move_insn (incloc, reloadreg));
}
else
{
the original value. */
emit_insn (gen_add2_insn (reloadreg, inc));
- store = emit_insn (gen_move_insn (incloc, reloadreg));
+ emit_insn (gen_move_insn (incloc, reloadreg));
if (CONST_INT_P (inc))
emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL (inc))));
else
emit_insn (gen_sub2_insn (reloadreg, inc));
}
-
- return store;
}
\f
#ifdef AUTO_INC_DEC
}
}
#endif
-
-/* This is used by reload pass, that does emit some instructions after
- abnormal calls moving basic block end, but in fact it wants to emit
- them on the edge. Looks for abnormal call edges, find backward the
- proper call and fix the damage.
-
- Similar handle instructions throwing exceptions internally. */
-void
-fixup_abnormal_edges (void)
-{
- bool inserted = false;
- basic_block bb;
-
- FOR_EACH_BB (bb)
- {
- edge e;
- edge_iterator ei;
-
- /* Look for cases we are interested in - calls or instructions causing
- exceptions. */
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (e->flags & EDGE_ABNORMAL_CALL)
- break;
- if ((e->flags & (EDGE_ABNORMAL | EDGE_EH))
- == (EDGE_ABNORMAL | EDGE_EH))
- break;
- }
- if (e && !CALL_P (BB_END (bb))
- && !can_throw_internal (BB_END (bb)))
- {
- rtx insn;
-
- /* Get past the new insns generated. Allow notes, as the insns
- may be already deleted. */
- insn = BB_END (bb);
- while ((NONJUMP_INSN_P (insn) || NOTE_P (insn))
- && !can_throw_internal (insn)
- && insn != BB_HEAD (bb))
- insn = PREV_INSN (insn);
-
- if (CALL_P (insn) || can_throw_internal (insn))
- {
- rtx stop, next;
-
- stop = NEXT_INSN (BB_END (bb));
- BB_END (bb) = insn;
- insn = NEXT_INSN (insn);
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_FALLTHRU)
- break;
-
- while (insn && insn != stop)
- {
- next = NEXT_INSN (insn);
- if (INSN_P (insn))
- {
- delete_insn (insn);
-
- /* Sometimes there's still the return value USE.
- If it's placed after a trapping call (i.e. that
- call is the last insn anyway), we have no fallthru
- edge. Simply delete this use and don't try to insert
- on the non-existent edge. */
- if (GET_CODE (PATTERN (insn)) != USE)
- {
- /* We're not deleting it, we're moving it. */
- INSN_DELETED_P (insn) = 0;
- PREV_INSN (insn) = NULL_RTX;
- NEXT_INSN (insn) = NULL_RTX;
-
- insert_insn_on_edge (insn, e);
- inserted = true;
- }
- }
- else if (!BARRIER_P (insn))
- set_block_for_insn (insn, NULL);
- insn = next;
- }
- }
-
- /* It may be that we don't find any such trapping insn. In this
- case we discovered quite late that the insn that had been
- marked as can_throw_internal in fact couldn't trap at all.
- So we should in fact delete the EH edges out of the block. */
- else
- purge_dead_edges (bb);
- }
- }
-
- /* We've possibly turned single trapping insn into multiple ones. */
- if (cfun->can_throw_non_call_exceptions)
- {
- sbitmap blocks;
- blocks = sbitmap_alloc (last_basic_block);
- sbitmap_ones (blocks);
- find_many_sub_basic_blocks (blocks);
- sbitmap_free (blocks);
- }
-
- if (inserted)
- commit_edge_insertions ();
-
-#ifdef ENABLE_CHECKING
- /* Verify that we didn't turn one trapping insn into many, and that
- we found and corrected all of the problems wrt fixups on the
- fallthru edge. */
- verify_flow_info ();
-#endif
-}