/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
really reload just the inside expression in its own mode.
If we have (SUBREG:M1 (REG:M2 ...) ...) with M1 wider than M2 and the
register is a pseudo, this will become the same as the above case.
- Do the same for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
+ Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
either M1 is not valid for R or M2 is wider than a word but we only
need one word to store an M2-sized quantity in R.
+ (However, if OUT is nonzero, we need to reload the reg *and*
+ the subreg, so do nothing here, and let following statement handle it.)
+
Note that the case of (SUBREG (CONST_INT...)...) is handled elsewhere;
we can't handle it here because CONST_INT does not indicate a mode.
&& REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (inmode)
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))))
- || (GET_CODE (SUBREG_REG (in)) == REG
- && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+ || (REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+ /* The case where out is nonzero
+ is handled differently in the following statement. */
+ && (out == 0 || SUBREG_WORD (in) == 0)
&& (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)
|| (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
in_subreg_loc = inloc;
inloc = &SUBREG_REG (in);
in = *inloc;
+#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
if (GET_CODE (in) == MEM)
/* This is supposed to happen only for paradoxical subregs made by
combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */
if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode))
abort ();
+#endif
inmode = GET_MODE (in);
}
+ /* Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
+ either M1 is not valid for R or M2 is wider than a word but we only
+ need one word to store an M2-sized quantity in R.
+
+ However, we must reload the inner reg *as well as* the subreg in
+ that case. */
+
+ if (in != 0 && GET_CODE (in) == SUBREG
+ && GET_CODE (SUBREG_REG (in)) == REG
+ && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+ && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)
+ || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ > UNITS_PER_WORD)
+ && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ / UNITS_PER_WORD)
+ != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
+ GET_MODE (SUBREG_REG (in)))))))
+ {
+ push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
+ GENERAL_REGS, VOIDmode, VOIDmode, 0, 0, opnum, type);
+ }
+
+
/* Similarly for paradoxical and problematical SUBREGs on the output.
Note that there is no reason we need worry about the previous value
of SUBREG_REG (out); even if wider than out,
{
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
- out = *outloc;
- if (GET_CODE (out) == MEM
+ out = *outloc;
+#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+ if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
abort ();
+#endif
outmode = GET_MODE (out);
}
+ HARD_REGNO_NREGS (regno,
inmode)),
PATTERN (this_insn), inloc)
+ /* If this is also an output reload, IN cannot be used as
+ the reload register if it is set in this insn unless IN
+ is also OUT. */
+ && (out == 0 || in == out
+ || ! hard_reg_set_here_p (regno,
+ (regno
+ + HARD_REGNO_NREGS (regno,
+ inmode)),
+ PATTERN (this_insn)))
+ /* ??? Why is this code so different from the previous?
+ Is there any simple coherent way to describe the two together?
+ What's going on here. */
&& (in != out
|| (GET_CODE (in) == SUBREG
&& (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1))
for (j = 0; j < n_reloads; j++)
if (i != j && reload_in[j] != 0 && reload_out[j] == 0
&& reload_when_needed[j] == reload_when_needed[i]
- && MATCHES (reload_in[i], reload_in[j]))
+ && MATCHES (reload_in[i], reload_in[j])
+ && reload_reg_class[i] == reload_reg_class[j]
+ && !reload_nocombine[i] && !reload_nocombine[j])
{
reload_opnum[i] = MIN (reload_opnum[i], reload_opnum[j]);
transfer_replacements (i, j);
return x;
}
+/* Return a mem ref for the memory equivalent of reg REGNO.
+ This mem ref is not shared with anything. */
+
static rtx
make_memloc (ad, regno)
rtx ad;
{
register int i;
rtx tem = reg_equiv_address[regno];
+
+#if 0 /* We cannot safely reuse a memloc made here;
+ if the pseudo appears twice, and its mem needs a reload,
+ it gets two separate reloads assigned, but it only
+ gets substituted with the second of them;
+ then it can get used before that reload reg gets loaded up. */
for (i = 0; i < n_memlocs; i++)
if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
return memlocs[i];
+#endif
/* If TEM might contain a pseudo, we must copy it to avoid
modifying it when we do the substitution for the reload. */
}
/* We can avoid a reload if the register's equivalent memory expression
- is valid as an indirect memory address. */
+ is valid as an indirect memory address.
+ But not all addresses are valid in a mem used as an indirect address:
+ only reg or reg+constant. */
else if (reg_equiv_mem[regno] != 0 && ind_levels > 0
- && strict_memory_address_p (mode, reg_equiv_mem[regno]))
+ && strict_memory_address_p (mode, reg_equiv_mem[regno])
+ && (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == REG
+ || (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)) == REG
+ && CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)))))
return 0;
/* The only remaining case where we can avoid a reload is if this is a
rtx x, y;
{
rtx tem;
+ enum machine_mode mode = GET_MODE (x);
+
+ if (mode == VOIDmode)
+ mode = GET_MODE (y);
+
+ if (mode == VOIDmode)
+ mode = Pmode;
if (GET_CODE (x) == CONST_INT)
return plus_constant (y, INTVAL (x));
if (GET_CODE (y) == CONST)
y = XEXP (y, 0);
- return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, Pmode, x, y));
+ return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, mode, x, y));
}
- return gen_rtx (PLUS, Pmode, x, y);
+ return gen_rtx (PLUS, mode, x, y);
}
\f
/* If ADDR is a sum containing a pseudo register that should be
enum machine_mode mode;
{
register rtx p = insn;
- rtx valtry, value, where;
+ rtx goaltry, valtry, value, where;
register rtx pat;
register int regno = -1;
int valueno;
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
&& GET_CODE (goal) == CONST_INT
- && INTVAL (goal) == CONST_DOUBLE_LOW (XEXP (tem, 0))
+ && 0 != (goaltry = operand_subword (XEXP (tem, 0), 0, 0,
+ VOIDmode))
+ && rtx_equal_p (goal, goaltry)
&& (valtry = operand_subword (SET_DEST (pat), 0, 0,
VOIDmode))
&& (valueno = true_regnum (valtry)) >= 0)
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (XEXP (tem, 0))) == MODE_FLOAT
&& GET_CODE (goal) == CONST_INT
- && INTVAL (goal) == CONST_DOUBLE_HIGH (XEXP (tem, 0))
+ && 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
+ VOIDmode))
+ && rtx_equal_p (goal, goaltry)
&& (valtry
= operand_subword (SET_DEST (pat), 1, 0, VOIDmode))
&& (valueno = true_regnum (valtry)) >= 0)))
}
if (goal_mem)
- goal_mem_addr_varies = rtx_addr_varies_p (goal);
+ /* We must treat frame pointer as varying here,
+ since it can vary--in a nonlocal goto as generated by expand_goto. */
+ goal_mem_addr_varies = !CONSTANT_ADDRESS_P (XEXP (goal, 0));
/* Now verify that the values of GOAL and VALUE remain unaltered
until INSN is reached. */