static int refers_to_mem_for_reload_p (rtx);
static int refers_to_regno_for_reload_p (unsigned int, unsigned int,
rtx, rtx *);
+
+/* Add NEW to reg_equiv_alt_mem_list[REGNO] if it's not present in the
+ list yet. */
+
+static void
+push_reg_equiv_alt_mem (int regno, rtx mem)
+{
+ rtx it;
+
+ for (it = reg_equiv_alt_mem_list [regno]; it; it = XEXP (it, 1))
+ if (rtx_equal_p (XEXP (it, 0), mem))
+ return;
+
+ reg_equiv_alt_mem_list [regno]
+ = alloc_EXPR_LIST (REG_EQUIV, mem,
+ reg_equiv_alt_mem_list [regno]);
+}
\f
/* Determine if any secondary reloads are needed for loading (if IN_P is
nonzero) or storing (if IN_P is zero) X to or from a reload register of
{
error_for_asm (this_insn, "impossible register constraint "
"in %<asm%>");
- class = ALL_REGS;
+ /* Avoid further trouble with this insn. */
+ PATTERN (this_insn) = gen_rtx_USE (VOIDmode, const0_rtx);
+ /* We used to continue here setting class to ALL_REGS, but it triggers
+ sanity check on i386 for:
+ void foo(long double d)
+ {
+ asm("" :: "a" (d));
+ }
+ Returning zero here ought to be safe as we take care in
+ find_reloads to not process the reloads when instruction was
+ replaced by USE. */
+
+ return 0;
}
}
}
#endif
+ /* If we detected error and replaced asm instruction by USE, forget about the
+ reloads. */
+ if (GET_CODE (PATTERN (insn)) == USE
+ && GET_CODE (XEXP (PATTERN (insn), 0)) == CONST_INT)
+ n_reloads = 0;
+
/* Perhaps an output reload can be combined with another
to reduce needs by one. */
if (!goal_earlyclobber)
x = mem;
i = find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, insn);
+ if (x != mem)
+ push_reg_equiv_alt_mem (regno, x);
if (address_reloaded)
*address_reloaded = i;
}
tem = make_memloc (ad, regno);
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
{
+ rtx orig = tem;
+
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum,
ADDR_TYPE (type), ind_levels, insn);
+ if (tem != orig)
+ push_reg_equiv_alt_mem (regno, tem);
}
/* We can avoid a reload if the register's equivalent memory
expression is valid as an indirect memory address.
/* Require index register (or constant). Let's just handle the
register case in the meantime... If the target allows
auto-modify by a constant then we could try replacing a pseudo
- register with its equivalent constant where applicable. */
+ register with its equivalent constant where applicable.
+
+ If we later decide to reload the whole PRE_MODIFY or
+ POST_MODIFY, inc_for_reload might clobber the reload register
+ before reading the index. The index register might therefore
+ need to live longer than a TYPE reload normally would, so be
+ conservative and class it as RELOAD_OTHER. */
if (REG_P (XEXP (op1, 1)))
if (!REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
- &XEXP (op1, 1), opnum, type, ind_levels,
- insn);
+ &XEXP (op1, 1), opnum, RELOAD_OTHER,
+ ind_levels, insn);
gcc_assert (REG_P (XEXP (op1, 0)));
if (reg_equiv_address[regno]
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
+ rtx orig = tem;
+
/* First reload the memory location's address.
We can't use ADDR_TYPE (type) here, because we need to
write back the value after reading it, hence we actually
RELOAD_OTHER,
ind_levels, insn);
+ if (tem != orig)
+ push_reg_equiv_alt_mem (regno, tem);
+
/* Then reload the memory location into a base
register. */
reloadnum = push_reload (tem, tem, &XEXP (x, 0),
if (reg_equiv_address[regno]
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
+ rtx orig = tem;
+
/* First reload the memory location's address.
We can't use ADDR_TYPE (type) here, because we need to
write back the value after reading it, hence we actually
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
+ if (tem != orig)
+ push_reg_equiv_alt_mem (regno, tem);
/* Put this inside a new increment-expression. */
x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
/* Proceed to reload that, as if it contained a register. */
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
&XEXP (x, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
+ if (x != tem)
+ push_reg_equiv_alt_mem (regno, x);
}
}
unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
int offset;
+ rtx orig = tem;
/* For big-endian paradoxical subregs, SUBREG_BYTE does not
hold the correct (negative) byte offset. */
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
+ /* ??? Do we need to handle nonzero offsets somehow? */
+ if (!offset && tem != orig)
+ push_reg_equiv_alt_mem (regno, tem);
/* If this is not a toplevel operand, find_reloads doesn't see
this substitution. We have to emit a USE of the pseudo so