/* Search an insn for pseudo regs that must be in hard regs and are not.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
static int hard_reg_set_here_p (unsigned int, unsigned int, rtx);
static struct decomposition decompose (rtx);
static int immune_p (rtx, rtx, struct decomposition);
-static int alternative_allows_memconst (const char *, int);
+static bool alternative_allows_const_pool_ref (rtx, const char *, int);
static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, rtx,
int *);
static rtx make_memloc (rtx, int);
if (MERGE_TO_OTHER (secondary_type, rld[s_reload].when_needed,
opnum, rld[s_reload].opnum))
rld[s_reload].when_needed = RELOAD_OTHER;
+
+ break;
}
if (s_reload == n_reloads)
if (outmode == VOIDmode && out != 0)
outmode = GET_MODE (out);
- /* If IN is a pseudo register everywhere-equivalent to a constant, and
- it is not in a hard register, reload straight from the constant,
- since we want to get rid of such pseudo registers.
- Often this is done earlier, but not always in find_reloads_address. */
+ /* If find_reloads and friends until now missed to replace a pseudo
+ with a constant of reg_equiv_constant something went wrong
+ beforehand.
+ Note that it can't simply be done here if we missed it earlier
+ since the constant might need to be pushed into the literal pool
+ and the resulting memref would probably need further
+ reloading. */
if (in != 0 && REG_P (in))
{
int regno = REGNO (in);
- if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
- && reg_equiv_constant[regno] != 0)
- in = reg_equiv_constant[regno];
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER
+ || reg_renumber[regno] >= 0
+ || reg_equiv_constant[regno] == NULL_RTX);
}
- /* Likewise for OUT. Of course, OUT will never be equivalent to
- an actual constant, but it might be equivalent to a memory location
- (in the case of a parameter). */
+ /* reg_equiv_constant only contains constants which are obviously
+ not appropriate as destination. So if we would need to replace
+ the destination pseudo with a constant we are in real
+ trouble. */
if (out != 0 && REG_P (out))
{
int regno = REGNO (out);
- if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
- && reg_equiv_constant[regno] != 0)
- out = reg_equiv_constant[regno];
+ gcc_assert (regno < FIRST_PSEUDO_REGISTER
+ || reg_renumber[regno] >= 0
+ || reg_equiv_constant[regno] == NULL_RTX);
}
/* If we have a read-write operand with an address side-effect,
we can't handle it here because CONST_INT does not indicate a mode.
Similarly, we must reload the inside expression if we have a
- STRICT_LOW_PART (presumably, in == out in the cas).
+ STRICT_LOW_PART (presumably, in == out in this case).
Also reload the inner expression if it does not require a secondary
reload but the SUBREG does.
&& REG_P (XEXP (note, 0))
&& (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER
&& reg_mentioned_p (XEXP (note, 0), in)
- /* Check that we don't use a hardreg for an uninitialized
- pseudo. See also find_dummy_reload(). */
+ /* Check that a former pseudo is valid; see find_dummy_reload. */
&& (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- || ! bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
- ORIGINAL_REGNO (XEXP (note, 0))))
+ || (!bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
+ ORIGINAL_REGNO (XEXP (note, 0)))
+ && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1))
&& ! refers_to_regno_for_reload_p (regno,
end_hard_regno (rel_mode,
regno),
static void
combine_reloads (void)
{
- int i;
+ int i, regno;
int output_reload = -1;
int secondary_out = -1;
rtx note;
for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD
&& REG_P (XEXP (note, 0))
- && ! reg_overlap_mentioned_for_reload_p (XEXP (note, 0),
- rld[output_reload].out)
- && REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), rld[output_reload].outmode)
+ && !reg_overlap_mentioned_for_reload_p (XEXP (note, 0),
+ rld[output_reload].out)
+ && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_MODE_OK (regno, rld[output_reload].outmode)
&& TEST_HARD_REG_BIT (reg_class_contents[(int) rld[output_reload].class],
- REGNO (XEXP (note, 0)))
- && (hard_regno_nregs[REGNO (XEXP (note, 0))][rld[output_reload].outmode]
- <= hard_regno_nregs[REGNO (XEXP (note, 0))][GET_MODE (XEXP (note, 0))])
+ regno)
+ && (hard_regno_nregs[regno][rld[output_reload].outmode]
+ <= hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))])
/* Ensure that a secondary or tertiary reload for this output
won't want this register. */
&& ((secondary_out = rld[output_reload].secondary_out_reload) == -1
- || (! (TEST_HARD_REG_BIT
- (reg_class_contents[(int) rld[secondary_out].class],
- REGNO (XEXP (note, 0))))
+ || (!(TEST_HARD_REG_BIT
+ (reg_class_contents[(int) rld[secondary_out].class], regno))
&& ((secondary_out = rld[secondary_out].secondary_out_reload) == -1
- || ! (TEST_HARD_REG_BIT
- (reg_class_contents[(int) rld[secondary_out].class],
- REGNO (XEXP (note, 0)))))))
- && ! fixed_regs[REGNO (XEXP (note, 0))]
- /* Check that we don't use a hardreg for an uninitialized
- pseudo. See also find_dummy_reload(). */
+ || !(TEST_HARD_REG_BIT
+ (reg_class_contents[(int) rld[secondary_out].class],
+ regno)))))
+ && !fixed_regs[regno]
+ /* Check that a former pseudo is valid; see find_dummy_reload. */
&& (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
- || ! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
- ORIGINAL_REGNO (XEXP (note, 0)))))
+ || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+ ORIGINAL_REGNO (XEXP (note, 0)))
+ && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1)))
{
rld[output_reload].reg_rtx
- = gen_rtx_REG (rld[output_reload].outmode,
- REGNO (XEXP (note, 0)));
+ = gen_rtx_REG (rld[output_reload].outmode, regno);
return;
}
}
has a real mode. */
(GET_MODE (out) != VOIDmode
? GET_MODE (out) : outmode))
- /* But only do all this if we can be sure, that this input
- operand doesn't correspond with an uninitialized pseudoreg.
- global can assign some hardreg to it, which is the same as
- a different pseudo also currently live (as it can ignore the
- conflict). So we never must introduce writes to such hardregs,
- as they would clobber the other live pseudo using the same.
- See also PR20973. */
&& (ORIGINAL_REGNO (in) < FIRST_PSEUDO_REGISTER
- || ! bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
- ORIGINAL_REGNO (in))))
+ /* However only do this if we can be sure that this input
+ operand doesn't correspond with an uninitialized pseudo.
+ global can assign some hardreg to it that is the same as
+ the one assigned to a different, also live pseudo (as it
+ can ignore the conflict). We must never introduce writes
+ to such hardregs, as they would clobber the other live
+ pseudo. See PR 20973. */
+ || (!bitmap_bit_p (DF_LIVE_OUT (ENTRY_BLOCK_PTR),
+ ORIGINAL_REGNO (in))
+ /* Similarly, only do this if we can be sure that the death
+ note is still valid. global can assign some hardreg to
+ the pseudo referenced in the note and simultaneously a
+ subword of this hardreg to a different, also live pseudo,
+ because only another subword of the hardreg is actually
+ used in the insn. This cannot happen if the pseudo has
+ been assigned exactly one hardreg. See PR 33732. */
+ && hard_regno_nregs[REGNO (in)][GET_MODE (in)] == 1)))
{
unsigned int regno = REGNO (in) + in_offset;
unsigned int nwords = hard_regno_nregs[regno][inmode];
int noperands;
/* These start out as the constraints for the insn
and they are chewed up as we consider alternatives. */
- char *constraints[MAX_RECOG_OPERANDS];
+ const char *constraints[MAX_RECOG_OPERANDS];
/* These are the preferred classes for an operand, or NO_REGS if it isn't
a register. */
enum reg_class preferred_class[MAX_RECOG_OPERANDS];
memcpy (operand_mode, recog_data.operand_mode,
noperands * sizeof (enum machine_mode));
- memcpy (constraints, recog_data.constraints, noperands * sizeof (char *));
+ memcpy (constraints, recog_data.constraints,
+ noperands * sizeof (const char *));
commutative = -1;
for (i = 0; i < noperands; i++)
{
- char *p;
+ const char *p;
int c;
+ char *end;
substed_operand[i] = recog_data.operand[i];
p = constraints[i];
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
- c = strtoul (p - 1, &p, 10);
+ c = strtoul (p - 1, &end, 10);
+ p = end;
operands_match[c][i]
= operands_match_p (recog_data.operand[c],
a bad register class to only count 1/3 as much. */
int reject = 0;
+ if (!recog_data.alternative_enabled_p[this_alternative_number])
+ {
+ int i;
+
+ for (i = 0; i < recog_data.n_operands; i++)
+ constraints[i] = skip_alternative (constraints[i]);
+
+ continue;
+ }
+
this_earlyclobber = 0;
for (i = 0; i < noperands; i++)
{
- char *p = constraints[i];
+ const char *p = constraints[i];
char *end;
int len;
int win = 0;
badop = 0;
break;
- case 'm':
+ case TARGET_MEM_CONSTRAINT:
if (force_reload)
break;
if (MEM_P (operand)
address_reloaded[commutative + 1] = t;
memcpy (constraints, recog_data.constraints,
- noperands * sizeof (char *));
+ noperands * sizeof (const char *));
goto try_swapped;
}
else
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
+ int this_address_reloaded;
+
+ this_address_reloaded = 0;
substed_operand[i] = recog_data.operand[i]
= find_reloads_toplev (force_const_mem (operand_mode[i],
recog_data.operand[i]),
i, address_type[i], ind_levels, 0, insn,
- NULL);
- if (alternative_allows_memconst (recog_data.constraints[i],
- goal_alternative_number))
+ &this_address_reloaded);
+ if (alternative_allows_const_pool_ref (this_address_reloaded == 0
+ ? substed_operand[i]
+ : NULL,
+ recog_data.constraints[i],
+ goal_alternative_number))
goal_alternative_win[i] = 1;
}
PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, operand),
insn), QImode);
if (modified[i] != RELOAD_READ)
- emit_insn_after (gen_rtx_CLOBBER (VOIDmode, operand), insn);
+ emit_insn_after (gen_clobber (operand), insn);
}
}
}
if (rld[i].when_needed == RELOAD_FOR_INPUT
&& GET_CODE (PATTERN (insn)) == SET
&& REG_P (SET_DEST (PATTERN (insn)))
- && SET_SRC (PATTERN (insn)) == rld[i].in
+ && (SET_SRC (PATTERN (insn)) == rld[i].in
+ || SET_SRC (PATTERN (insn)) == rld[i].in_reg)
&& !elimination_target_reg_p (SET_DEST (PATTERN (insn))))
{
rtx dest = SET_DEST (PATTERN (insn));
return retval;
}
-/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
- accepts a memory operand with constant address. */
+/* Return true if alternative number ALTNUM in constraint-string
+ CONSTRAINT is guaranteed to accept a reloaded constant-pool reference.
+ MEM gives the reference if it didn't need any reloads, otherwise it
+ is null. */
-static int
-alternative_allows_memconst (const char *constraint, int altnum)
+static bool
+alternative_allows_const_pool_ref (rtx mem, const char *constraint, int altnum)
{
int c;
+
/* Skip alternatives before the one requested. */
while (altnum > 0)
{
while (*constraint++ != ',');
altnum--;
}
- /* Scan the requested alternative for 'm' or 'o'.
- If one of them is present, this alternative accepts memory constants. */
+ /* Scan the requested alternative for TARGET_MEM_CONSTRAINT or 'o'.
+ If one of them is present, this alternative accepts the result of
+ passing a constant-pool reference through find_reloads_toplev.
+
+ The same is true of extra memory constraints if the address
+ was reloaded into a register. However, the target may elect
+ to disallow the original constant address, forcing it to be
+ reloaded into a register instead. */
for (; (c = *constraint) && c != ',' && c != '#';
constraint += CONSTRAINT_LEN (c, constraint))
- if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint))
- return 1;
- return 0;
+ {
+ if (c == TARGET_MEM_CONSTRAINT || c == 'o')
+ return true;
+#ifdef EXTRA_CONSTRAINT_STR
+ if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
+ && (mem == NULL || EXTRA_CONSTRAINT_STR (mem, c, constraint)))
+ return true;
+#endif
+ }
+ return false;
}
\f
/* Scan X for memory references and scan the addresses for reloading.
{
regno = REGNO (ad);
- /* If the register is equivalent to an invariant expression, substitute
- the invariant, and eliminate any eliminable register references. */
- tem = reg_equiv_constant[regno];
- if (tem != 0
- && (tem = eliminate_regs (tem, mode, insn))
- && strict_memory_address_p (mode, tem))
+ if (reg_equiv_constant[regno] != 0)
{
- *loc = ad = tem;
- return 0;
+ find_reloads_address_part (reg_equiv_constant[regno], loc,
+ base_reg_class (mode, MEM, SCRATCH),
+ GET_MODE (ad), opnum, type, ind_levels);
+ return 1;
}
tem = reg_equiv_memory_loc[regno];
}
}
- /* If we have a hard register that is ok as an index,
- don't make a reload. If an autoincrement of a nice register
+ /* If we have a hard register that is ok in this incdec context,
+ don't make a reload. If the register isn't nice enough for
+ autoincdec, we can reload it. But, if an autoincrement of a
+ register that we here verified as playing nice, still outside
isn't "valid", it must be that no autoincrement is "valid".
If that is true and something made an autoincrement anyway,
this must be a special context where one is allowed.
if (reg_renumber[regno] >= 0)
regno = reg_renumber[regno];
if (regno >= FIRST_PSEUDO_REGISTER
- || !REG_OK_FOR_CONTEXT (context, regno, mode, outer_code,
+ || !REG_OK_FOR_CONTEXT (context, regno, mode, code,
index_code))
{
int reloadnum;
else
{
reloadnum
- = push_reload (x, NULL_RTX, loc, (rtx*) 0,
+ = push_reload (x, x, loc, (rtx*) 0,
context_reg_class,
GET_MODE (x), GET_MODE (x), 0, 0,
opnum, type);
XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
PUT_MODE (tem, GET_MODE (x));
+ if (MEM_OFFSET (tem))
+ set_mem_offset (tem, plus_constant (MEM_OFFSET (tem), offset));
/* If this was a paradoxical subreg that we replaced, the
resulting memory must be sufficiently aligned to allow