/* 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 Free Software Foundation,
- Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "toplev.h"
#include "except.h"
#include "tree.h"
+#include "df.h"
#include "target.h"
+#include "dse.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
static void elimination_effects (rtx, enum machine_mode);
static int eliminate_regs_in_insn (rtx, int);
static void update_eliminable_offsets (void);
-static void mark_not_eliminable (rtx, rtx, void *);
+static void mark_not_eliminable (rtx, const_rtx, void *);
static void set_initial_elim_offsets (void);
static bool verify_initial_elim_offsets (void);
static void set_initial_label_offsets (void);
static void count_pseudo (int);
static void order_regs_for_reload (struct insn_chain *);
static void reload_as_needed (int);
-static void forget_old_reloads_1 (rtx, rtx, void *);
+static void forget_old_reloads_1 (rtx, const_rtx, void *);
static void forget_marked_reloads (regset);
static int reload_reg_class_lower (const void *, const void *);
static void mark_reload_reg_in_use (unsigned int, int, enum reload_type,
static rtx gen_reload (rtx, rtx, int, enum reload_type);
static rtx emit_insn_if_valid_for_reload (rtx);
\f
-/* Initialize the reload pass once per compilation. */
+/* Initialize the reload pass. This is called at the beginning of compilation
+ and may be called again if the target is reinitialized. */
void
init_reload (void)
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
+ DF_LIVE_IN (BASIC_BLOCK), 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);
- }
+ add_to_hard_reg_set (to, PSEUDO_REGNO_MODE (regno), r);
}
}
replace_pseudos_in (& XVECEXP (x, i, j), mem_mode, usage);
}
+/* Determine if the current function has an exception receiver block
+ that reaches the exit block via non-exceptional edges */
+
+static bool
+has_nonexceptional_receiver (void)
+{
+ edge e;
+ edge_iterator ei;
+ basic_block *tos, *worklist, bb;
+
+ /* If we're not optimizing, then just err on the safe side. */
+ if (!optimize)
+ return true;
+
+ /* First determine which blocks can reach exit via normal paths. */
+ tos = worklist = xmalloc (sizeof (basic_block) * (n_basic_blocks + 1));
+
+ FOR_EACH_BB (bb)
+ bb->flags &= ~BB_REACHABLE;
+
+ /* Place the exit block on our worklist. */
+ EXIT_BLOCK_PTR->flags |= BB_REACHABLE;
+ *tos++ = EXIT_BLOCK_PTR;
+
+ /* Iterate: find everything reachable from what we've already seen. */
+ while (tos != worklist)
+ {
+ bb = *--tos;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if (!(e->flags & EDGE_ABNORMAL))
+ {
+ basic_block src = e->src;
+
+ if (!(src->flags & BB_REACHABLE))
+ {
+ src->flags |= BB_REACHABLE;
+ *tos++ = src;
+ }
+ }
+ }
+ free (worklist);
+
+ /* 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;
+
+ /* No exceptional block reached exit unexceptionally. */
+ return false;
+}
+
\f
/* Global variables used by reload and its subroutines. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
mark_home_live (i);
- /* A function that receives a nonlocal goto must save all call-saved
+ /* A function that has a nonlocal label that can reach the exit
+ block via non-exceptional paths must save all call-saved
registers. */
- if (current_function_has_nonlocal_label)
+ if (current_function_has_nonlocal_label
+ && has_nonexceptional_receiver ())
+ current_function_saves_all_registers = 1;
+
+ if (current_function_saves_all_registers)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
- regs_ever_live[i] = 1;
+ 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.
{
int something_changed;
int did_spill;
-
HOST_WIDE_INT starting_frame_size;
- /* Round size of stack frame to stack_alignment_needed. This must be done
- here because the stack size may be a part of the offset computation
- for register elimination, and there might have been new stack slots
- created in the last iteration of this loop. */
- if (cfun->stack_alignment_needed)
- assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed);
-
starting_frame_size = get_frame_size ();
set_initial_elim_offsets ();
/* If we allocated another stack slot, redo elimination bookkeeping. */
if (starting_frame_size != get_frame_size ())
continue;
+ if (starting_frame_size && cfun->stack_alignment_needed)
+ {
+ /* If we have a stack frame, we must align it now. The
+ stack size may be a part of the offset computation for
+ register elimination. So if this changes the stack size,
+ then repeat the elimination bookkeeping. We don't
+ realign when there is no stack, as that will cause a
+ stack frame when none is needed should
+ STARTING_FRAME_OFFSET not be already aligned to
+ STACK_BOUNDARY. */
+ assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed);
+ if (starting_frame_size != get_frame_size ())
+ continue;
+ }
if (caller_save_needed)
{
if (! frame_pointer_needed)
FOR_EACH_BB (bb)
- CLEAR_REGNO_REG_SET (bb->il.rtl->global_live_at_start,
- HARD_FRAME_POINTER_REGNUM);
-
+ bitmap_clear_bit (df_get_live_in (bb), HARD_FRAME_POINTER_REGNUM);
+
/* Come here (with failure set nonzero) if we can't get enough spill
regs. */
failed:
{
rtx *pnote;
- /* Clean up invalid ASMs so that they don't confuse later passes.
- See PR 21299. */
- if (asm_noperands (PATTERN (insn)) >= 0)
- {
- extract_insn (insn);
- if (!constrain_operands (1))
- {
- error_for_asm (insn,
- "%<asm%> operand has impossible constraints");
- delete_insn (insn);
- continue;
- }
- }
-
if (CALL_P (insn))
replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn),
VOIDmode, CALL_INSN_FUNCTION_USAGE (insn));
|| REG_NOTE_KIND (*pnote) == REG_UNUSED
|| REG_NOTE_KIND (*pnote) == REG_INC
|| REG_NOTE_KIND (*pnote) == REG_RETVAL
+ || REG_NOTE_KIND (*pnote) == REG_LIBCALL_ID
|| REG_NOTE_KIND (*pnote) == REG_LIBCALL)
*pnote = XEXP (*pnote, 1);
else
add_auto_inc_notes (insn, PATTERN (insn));
#endif
- /* And simplify (subreg (reg)) if it appears as an operand. */
+ /* Simplify (subreg (reg)) if it appears as an operand. */
cleanup_subreg_operands (insn);
+
+ /* Clean up invalid ASMs so that they don't confuse later passes.
+ See PR 21299. */
+ if (asm_noperands (PATTERN (insn)) >= 0)
+ {
+ extract_insn (insn);
+ if (!constrain_operands (1))
+ {
+ error_for_asm (insn,
+ "%<asm%> operand has impossible constraints");
+ delete_insn (insn);
+ continue;
+ }
+ }
}
/* If we are doing stack checking, give a warning if this function's
static int verbose_warned = 0;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (regs_ever_live[i] && ! fixed_regs[i] && call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ! fixed_regs[i] && call_used_regs[i])
size += UNITS_PER_WORD;
if (size > STACK_CHECK_MAX_FRAME_SIZE)
/* Get the operand values and constraints out of the insn. */
decode_asm_operands (pat, recog_data.operand, recog_data.operand_loc,
- constraints, operand_mode);
+ constraints, operand_mode, NULL);
/* For every operand, see what registers are allowed. */
for (i = 0; i < noperands; i++)
chain->need_operand_change = 0;
/* If this is a label, a JUMP_INSN, or has REG_NOTES (which might
- include REG_LABEL), we need to see what effects this has on the
- known offsets at labels. */
+ include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see
+ what effects this has on the known offsets at labels. */
if (LABEL_P (insn) || JUMP_P (insn)
|| (INSN_P (insn) && REG_NOTES (insn) != 0))
/* Modify the reg-rtx to contain the new hard reg
number or else to contain its pseudo reg number. */
- REGNO (regno_reg_rtx[i])
- = reg_renumber[i] >= 0 ? reg_renumber[i] : i;
+ SET_REGNO (regno_reg_rtx[i],
+ reg_renumber[i] >= 0 ? reg_renumber[i] : i);
/* If we have a pseudo that is needed but has no hard reg or equivalent,
allocate a stack slot for it. */
inherent space, and no less total space, then the previous slot. */
if (from_reg == -1)
{
+ alias_set_type alias_set = new_alias_set ();
+
/* No known place to spill from => no slot to reuse. */
x = assign_stack_local (mode, total_size,
min_align > inherent_align
adjust = inherent_size - total_size;
/* Nothing can alias this slot except this pseudo. */
- set_mem_alias_set (x, new_alias_set ());
+ set_mem_alias_set (x, alias_set);
+ dse_record_singleton_alias_set (alias_set, mode);
}
/* Reuse a stack slot if possible. */
>= inherent_size)
&& MEM_ALIGN (spill_stack_slot[from_reg]) >= min_align)
x = spill_stack_slot[from_reg];
-
/* Allocate a bigger slot. */
else
{
/* All pseudos mapped to this slot can alias each other. */
if (spill_stack_slot[from_reg])
- set_mem_alias_set (x, MEM_ALIAS_SET (spill_stack_slot[from_reg]));
+ {
+ alias_set_type alias_set
+ = MEM_ALIAS_SET (spill_stack_slot[from_reg]);
+ set_mem_alias_set (x, alias_set);
+ dse_invalidate_singleton_alias_set (alias_set);
+ }
else
- set_mem_alias_set (x, new_alias_set ());
+ {
+ alias_set_type alias_set = new_alias_set ();
+ set_mem_alias_set (x, alias_set);
+ dse_record_singleton_alias_set (alias_set, mode);
+ }
if (BYTES_BIG_ENDIAN)
{
}
}
-/* Mark the slots in regs_ever_live for the hard regs
- used by pseudo-reg number REGNO. */
+/* Mark the slots in regs_ever_live for the hard regs used by
+ pseudo-reg number REGNO, accessed in MODE. */
-void
-mark_home_live (int regno)
+static void
+mark_home_live_1 (int regno, enum machine_mode mode)
{
int i, lim;
i = reg_renumber[regno];
if (i < 0)
return;
- lim = i + hard_regno_nregs[i][PSEUDO_REGNO_MODE (regno)];
+ lim = end_hard_regno (mode, i);
while (i < lim)
- regs_ever_live[i++] = 1;
+ df_set_regs_ever_live(i++, true);
+}
+
+/* Mark the slots in regs_ever_live for the hard regs
+ used by pseudo-reg number REGNO. */
+
+void
+mark_home_live (int regno)
+{
+ if (reg_renumber[regno] >= 0)
+ mark_home_live_1 (regno, PSEUDO_REGNO_MODE (regno));
}
\f
/* This function handles the tracking of elimination offsets around branches.
case INSN:
case CALL_INSN:
- /* Any labels mentioned in REG_LABEL notes can be branched to indirectly
- and hence must have all eliminations at their initial offsets. */
+ /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched
+ to indirectly and hence must have all eliminations at their
+ initial offsets. */
for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1))
- if (REG_NOTE_KIND (tem) == REG_LABEL)
+ if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND)
set_label_offsets (XEXP (tem, 0), insn, 1);
return;
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case CONST:
case SYMBOL_REF:
case POST_INC:
case PRE_DEC:
case POST_DEC:
+ /* We do not support elimination of a register that is modified.
+ elimination_effects has already make sure that this does not
+ happen. */
+ return x;
+
+ case PRE_MODIFY:
+ case POST_MODIFY:
+ /* We do not support elimination of a register that is modified.
+ elimination_effects has already make sure that this does not
+ happen. The only remaining case we need to consider here is
+ that the increment value may be an eliminable register. */
+ if (GET_CODE (XEXP (x, 1)) == PLUS
+ && XEXP (XEXP (x, 1), 0) == XEXP (x, 0))
+ {
+ rtx new = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode,
+ insn, true);
+
+ if (new != XEXP (XEXP (x, 1), 1))
+ return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0),
+ gen_rtx_PLUS (GET_MODE (x),
+ XEXP (x, 0), new));
+ }
+ return x;
+
case STRICT_LOW_PART:
case NEG: case NOT:
case SIGN_EXTEND: case ZERO_EXTEND:
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case CONST:
case SYMBOL_REF:
case POST_DEC:
case POST_MODIFY:
case PRE_MODIFY:
+ /* If we modify the source of an elimination rule, disable it. */
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ if (ep->from_rtx == XEXP (x, 0))
+ ep->can_eliminate = 0;
+
+ /* If we modify the target of an elimination rule by adding a constant,
+ update its offset. If we modify the target in any other way, we'll
+ have to disable the rule as well. */
for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
if (ep->to_rtx == XEXP (x, 0))
{
ep->offset += size;
else if (code == PRE_INC || code == POST_INC)
ep->offset -= size;
- else if ((code == PRE_MODIFY || code == POST_MODIFY)
- && GET_CODE (XEXP (x, 1)) == PLUS
- && XEXP (x, 0) == XEXP (XEXP (x, 1), 0)
- && CONSTANT_P (XEXP (XEXP (x, 1), 1)))
- ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1));
+ else if (code == PRE_MODIFY || code == POST_MODIFY)
+ {
+ if (GET_CODE (XEXP (x, 1)) == PLUS
+ && XEXP (x, 0) == XEXP (XEXP (x, 1), 0)
+ && CONST_INT_P (XEXP (XEXP (x, 1), 1)))
+ ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1));
+ else
+ ep->can_eliminate = 0;
+ }
}
/* These two aren't unary operators. */
rtx links;
for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
{
- if (REG_NOTE_KIND (links) == REG_EQUAL
+ if ((REG_NOTE_KIND (links) == REG_EQUAL
+ || REG_NOTE_KIND (links) == REG_EQUIV)
&& GET_CODE (XEXP (links, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT)
{
{
rtx to_rtx = ep->to_rtx;
offset += ep->offset;
+ offset = trunc_int_for_mode (offset, GET_MODE (reg));
if (GET_CODE (XEXP (plus_cst_src, 0)) == SUBREG)
to_rtx = gen_lowpart (GET_MODE (XEXP (plus_cst_src, 0)),
to_rtx);
- if (offset == 0)
- {
- int num_clobbers;
- /* We assume here that if we need a PARALLEL with
- CLOBBERs for this assignment, we can do with the
- MATCH_SCRATCHes that add_clobbers allocates.
- There's not much we can do if that doesn't work. */
- PATTERN (insn) = gen_rtx_SET (VOIDmode,
- SET_DEST (old_set),
- to_rtx);
- num_clobbers = 0;
- INSN_CODE (insn) = recog (PATTERN (insn), insn, &num_clobbers);
- if (num_clobbers)
- {
- rtvec vec = rtvec_alloc (num_clobbers + 1);
-
- vec->elem[0] = PATTERN (insn);
- PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec);
- add_clobbers (PATTERN (insn), INSN_CODE (insn));
- }
- gcc_assert (INSN_CODE (insn) >= 0);
- }
/* 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 we already
had a PLUS before. */
- else if (plus_src)
+ if (offset == 0 || plus_src)
{
+ rtx new_src = plus_constant (to_rtx, offset);
+
new_body = old_body;
if (! replace)
{
PATTERN (insn) = new_body;
old_set = single_set (insn);
- XEXP (SET_SRC (old_set), 0) = to_rtx;
- XEXP (SET_SRC (old_set), 1) = GEN_INT (offset);
+ /* First see if this insn remains valid when we make the
+ change. If not, try to replace the whole pattern with
+ a simple set (this may help if the original insn was a
+ PARALLEL that was only recognized as single_set due to
+ REG_UNUSED notes). If this isn't valid either, keep
+ the INSN_CODE the same and let reload fix it up. */
+ if (!validate_change (insn, &SET_SRC (old_set), new_src, 0))
+ {
+ rtx new_pat = gen_rtx_SET (VOIDmode,
+ SET_DEST (old_set), new_src);
+
+ if (!validate_change (insn, &PATTERN (insn), new_pat, 0))
+ SET_SRC (old_set) = new_src;
+ }
}
else
break;
the insns of the function. */
static void
-mark_not_eliminable (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
+mark_not_eliminable (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED)
{
unsigned int i;
SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM);
}
+/* Return true if X is used as the target register of an elimination. */
+
+bool
+elimination_target_reg_p (rtx x)
+{
+ struct elim_table *ep;
+
+ for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ if (ep->to_rtx == x && ep->can_eliminate)
+ return true;
+
+ return false;
+}
+
/* Initialize the table of registers to eliminate. */
static void
if (cant_eliminate)
{
SET_HARD_REG_BIT (bad_spill_regs_global, regno);
- regs_ever_live[regno] = 1;
+ df_set_regs_ever_live (regno, true);
}
/* Spill every pseudo reg that was allocated to this reg
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
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)]
- > regno))
+ && end_hard_regno (PSEUDO_REGNO_MODE (i), reg_renumber[i]) > regno)
SET_REGNO_REG_SET (&spilled_pseudos, i);
}
{
spill_reg_order[i] = n_spills;
spill_regs[n_spills++] = i;
- if (num_eliminable && ! regs_ever_live[i])
+ if (num_eliminable && ! df_regs_ever_live_p (i))
something_changed = 1;
- regs_ever_live[i] = 1;
+ df_set_regs_ever_live (i, true);
}
else
spill_reg_order[i] = -1;
AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
/* Make sure we only enlarge the set. */
- GO_IF_HARD_REG_SUBSET (used_by_pseudos2, chain->used_spill_regs, ok);
- gcc_unreachable ();
- ok:;
+ gcc_assert (hard_reg_set_subset_p (used_by_pseudos2,
+ chain->used_spill_regs));
}
}
case SYMBOL_REF:
case LABEL_REF:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR: /* shouldn't happen, but just in case. */
case CC0:
case PC:
if (REG_P (SUBREG_REG (x))
&& (GET_MODE_SIZE (GET_MODE (x))
> reg_max_ref_width[REGNO (SUBREG_REG (x))]))
- reg_max_ref_width[REGNO (SUBREG_REG (x))]
- = GET_MODE_SIZE (GET_MODE (x));
+ {
+ reg_max_ref_width[REGNO (SUBREG_REG (x))]
+ = GET_MODE_SIZE (GET_MODE (x));
+ mark_home_live_1 (REGNO (SUBREG_REG (x)), GET_MODE (x));
+ }
return;
default:
to be forgotten later. */
static void
-forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
+forget_old_reloads_1 (rtx x, const_rtx ignored ATTRIBUTE_UNUSED,
void *data)
{
unsigned int regno;
{
unsigned int conflict_start = true_regnum (rld[i].reg_rtx);
unsigned int conflict_end
- = (conflict_start
- + hard_regno_nregs[conflict_start][rld[i].mode]);
+ = end_hard_regno (rld[i].mode, conflict_start);
/* If there is an overlap with the first to-be-freed register,
adjust the interval start. */
memory. */
int
-function_invariant_p (rtx x)
+function_invariant_p (const_rtx x)
{
if (CONSTANT_P (x))
return 1;
for (j = 0; j < n_reloads; j++)
{
reload_order[j] = j;
- reload_spill_index[j] = -1;
+ if (rld[j].reg_rtx != NULL_RTX)
+ {
+ gcc_assert (REG_P (rld[j].reg_rtx)
+ && HARD_REGISTER_P (rld[j].reg_rtx));
+ reload_spill_index[j] = REGNO (rld[j].reg_rtx);
+ }
+ else
+ reload_spill_index[j] = -1;
if (rld[j].nregs > 1)
{
regno = subreg_regno (rld[r].in);
#endif
- if (regno >= 0 && reg_last_reload_reg[regno] != 0)
+ if (regno >= 0
+ && reg_last_reload_reg[regno] != 0
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ /* Verify that the register it's in can be used in
+ mode MODE. */
+ && !REG_CANNOT_CHANGE_MODE_P (REGNO (reg_last_reload_reg[regno]),
+ GET_MODE (reg_last_reload_reg[regno]),
+ mode)
+#endif
+ )
{
enum reg_class class = rld[r].class, last_class;
rtx last_reg = reg_last_reload_reg[regno];
if ((GET_MODE_SIZE (GET_MODE (last_reg))
>= GET_MODE_SIZE (need_mode))
-#ifdef CANNOT_CHANGE_MODE_CLASS
- /* Verify that the register in "i" can be obtained
- from LAST_REG. */
- && !REG_CANNOT_CHANGE_MODE_P (REGNO (last_reg),
- GET_MODE (last_reg),
- mode)
-#endif
&& reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
&& HARD_REGNO_MODE_OK (i, rld[r].mode)
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. */
+ /* 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++)
&& 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)
actually no need to store the old value in it. */
if (optimize
- /* Only attempt this for input reloads; for RELOAD_OTHER we miss
- that there may be multiple uses of the previous output reload.
- Restricting to RELOAD_FOR_INPUT is mostly paranoia. */
- && rl->when_needed == RELOAD_FOR_INPUT
&& (reload_inherited[j] || reload_override_in[j])
&& rl->reg_rtx
&& REG_P (rl->reg_rtx)
rtx out = ((rld[r].out && REG_P (rld[r].out))
? rld[r].out : rld[r].out_reg);
int nregno = REGNO (out);
+
+ /* REG_RTX is now set or clobbered by the main instruction.
+ As the comment above explains, forget_old_reloads_1 only
+ sees the original instruction, and there is no guarantee
+ that the original instruction also clobbered REG_RTX.
+ For example, if find_reloads sees that the input side of
+ a matched operand pair dies in this instruction, it may
+ use the input register as the reload register.
+
+ Calling forget_old_reloads_1 is a waste of effort if
+ REG_RTX is also the output register.
+
+ If we know that REG_RTX holds the value of a pseudo
+ register, the code after the call will record that fact. */
+ if (rld[r].reg_rtx && rld[r].reg_rtx != out)
+ forget_old_reloads_1 (rld[r].reg_rtx, NULL_RTX, NULL);
+
if (nregno >= FIRST_PSEUDO_REGISTER)
{
rtx src_reg, store_insn = NULL_RTX;
DEFINE_PEEPHOLE should be specified that recognizes the sequence
we emit below. */
- code = (int) add_optab->handlers[(int) GET_MODE (out)].insn_code;
+ code = (int) optab_handler (add_optab, GET_MODE (out))->insn_code;
if (CONSTANT_P (op1) || MEM_P (op1) || GET_CODE (op1) == SUBREG
|| (REG_P (op1)
if (insn)
{
/* Add a REG_EQUIV note so that find_equiv_reg can find it. */
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+ set_unique_reg_note (insn, REG_EQUIV, in);
return insn;
}
/* If that failed, copy the address register to the reload register.
Then add the constant to the reload register. */
+ gcc_assert (!reg_overlap_mentioned_p (out, op0));
gen_reload (out, op1, opnum, type);
insn = emit_insn (gen_add2_insn (out, op0));
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+ set_unique_reg_note (insn, REG_EQUIV, in);
}
#ifdef SECONDARY_MEMORY_NEEDED
insn = emit_insn_if_valid_for_reload (insn);
if (insn)
{
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+ set_unique_reg_note (insn, REG_EQUIV, in);
return insn;
}
else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
{
tem = emit_insn (gen_move_insn (out, in));
- /* IN may contain a LABEL_REF, if so add a REG_LABEL note. */
+ /* IN may contain a LABEL_REF, if so add a REG_LABEL_OPERAND note. */
mark_jump_label (in, tem, 0);
}
if (rtx_equal_p (reg2, reg))
{
if (reload_inherited[k] || reload_override_in[k] || k == j)
- {
- n_inherited++;
- reg2 = rld[k].out_reg;
- if (! reg2)
- continue;
- while (GET_CODE (reg2) == SUBREG)
- reg2 = XEXP (reg2, 0);
- if (rtx_equal_p (reg2, reg))
- n_inherited++;
- }
+ n_inherited++;
else
return;
}
if (rld[j].out != rld[j].in
&& REG_N_DEATHS (REGNO (reg)) == 1
&& REG_N_SETS (REGNO (reg)) == 1
- && REG_BASIC_BLOCK (REGNO (reg)) >= 0
+ && REG_BASIC_BLOCK (REGNO (reg)) >= NUM_FIXED_BLOCKS
&& find_regno_note (insn, REG_DEAD, REGNO (reg)))
{
rtx i2;
next = NEXT_INSN (insn);
if (INSN_P (insn))
{
- delete_insn (insn);
+ delete_insn (insn);
/* Sometimes there's still the return value USE.
If it's placed after a trapping call (i.e. that
inserted = true;
}
}
+ else if (!BARRIER_P (insn))
+ set_block_for_insn (insn, NULL);
insn = next;
}
}
blocks = sbitmap_alloc (last_basic_block);
sbitmap_ones (blocks);
find_many_sub_basic_blocks (blocks);
+ sbitmap_free (blocks);
}
if (inserted)