/* 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 Free Software Foundation,
- Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 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/>. */
/* This file contains subroutines used only from the file reload1.c.
It knows how to scan one insn for operands and values
#define REG_OK_STRICT
+/* We do not enable this with ENABLE_CHECKING, since it is awfully slow. */
+#undef DEBUG_RELOAD
+
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "toplev.h"
#include "params.h"
#include "target.h"
+#include "df.h"
/* True if X is a constant that can be forced into the constant pool. */
#define CONST_POOL_OK_P(X) \
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);
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
enum machine_mode reload_mode, enum reload_type type,
enum insn_code *picode, secondary_reload_info *prev_sri)
{
- enum reg_class class = NO_REGS;
+ enum reg_class rclass = NO_REGS;
enum reg_class scratch_class;
enum machine_mode mode = reload_mode;
enum insn_code icode = CODE_FOR_nothing;
sri.icode = CODE_FOR_nothing;
sri.prev_sri = prev_sri;
- class = targetm.secondary_reload (in_p, x, reload_class, reload_mode, &sri);
+ rclass = targetm.secondary_reload (in_p, x, reload_class, reload_mode, &sri);
icode = sri.icode;
/* If we don't need any secondary registers, done. */
- if (class == NO_REGS && icode == CODE_FOR_nothing)
+ if (rclass == NO_REGS && icode == CODE_FOR_nothing)
return -1;
- if (class != NO_REGS)
- t_reload = push_secondary_reload (in_p, x, opnum, optional, class,
+ if (rclass != NO_REGS)
+ t_reload = push_secondary_reload (in_p, x, opnum, optional, rclass,
reload_mode, type, &t_icode, &sri);
/* If we will be using an insn, the secondary reload is for a
an icode to reload from an intermediate tertiary reload register.
We should probably have a new field in struct reload to tag a
chain of scratch operand reloads onto. */
- gcc_assert (class == NO_REGS);
+ gcc_assert (rclass == NO_REGS);
scratch_constraint = insn_data[(int) icode].operand[2].constraint;
gcc_assert (*scratch_constraint == '=');
: REG_CLASS_FROM_CONSTRAINT ((unsigned char) letter,
scratch_constraint));
- class = scratch_class;
+ rclass = scratch_class;
mode = insn_data[(int) icode].operand[2].mode;
}
Allow this when a reload_in/out pattern is being used. I.e. assume
that the generated code handles this case. */
- gcc_assert (!in_p || class != reload_class || icode != CODE_FOR_nothing
+ gcc_assert (!in_p || rclass != reload_class || icode != CODE_FOR_nothing
|| t_icode != CODE_FOR_nothing);
/* See if we can reuse an existing secondary reload. */
for (s_reload = 0; s_reload < n_reloads; s_reload++)
if (rld[s_reload].secondary_p
- && (reg_class_subset_p (class, rld[s_reload].class)
- || reg_class_subset_p (rld[s_reload].class, class))
+ && (reg_class_subset_p (rclass, rld[s_reload].rclass)
+ || reg_class_subset_p (rld[s_reload].rclass, rclass))
&& ((in_p && rld[s_reload].inmode == mode)
|| (! in_p && rld[s_reload].outmode == mode))
&& ((in_p && rld[s_reload].secondary_in_reload == t_reload)
|| (! in_p && rld[s_reload].secondary_out_reload == t_reload))
&& ((in_p && rld[s_reload].secondary_in_icode == t_icode)
|| (! in_p && rld[s_reload].secondary_out_icode == t_icode))
- && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES)
+ && (SMALL_REGISTER_CLASS_P (rclass) || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type, rld[s_reload].when_needed,
opnum, rld[s_reload].opnum))
{
if (! in_p)
rld[s_reload].outmode = mode;
- if (reg_class_subset_p (class, rld[s_reload].class))
- rld[s_reload].class = class;
+ if (reg_class_subset_p (rclass, rld[s_reload].rclass))
+ rld[s_reload].rclass = rclass;
rld[s_reload].opnum = MIN (rld[s_reload].opnum, opnum);
rld[s_reload].optional &= optional;
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)
way reloads are output. */
if (in_p && icode == CODE_FOR_nothing
- && SECONDARY_MEMORY_NEEDED (class, reload_class, mode))
+ && SECONDARY_MEMORY_NEEDED (rclass, reload_class, mode))
{
get_secondary_mem (x, reload_mode, opnum, type);
/* We need to make a new secondary reload for this register class. */
rld[s_reload].in = rld[s_reload].out = 0;
- rld[s_reload].class = class;
+ rld[s_reload].rclass = rclass;
rld[s_reload].inmode = in_p ? mode : VOIDmode;
rld[s_reload].outmode = ! in_p ? mode : VOIDmode;
#ifdef SECONDARY_MEMORY_NEEDED
if (! in_p && icode == CODE_FOR_nothing
- && SECONDARY_MEMORY_NEEDED (reload_class, class, mode))
+ && SECONDARY_MEMORY_NEEDED (reload_class, rclass, mode))
get_secondary_mem (x, mode, opnum, type);
#endif
}
register and a scratch register is needed, we return the class of the
intermediate register. */
enum reg_class
-secondary_reload_class (bool in_p, enum reg_class class,
+secondary_reload_class (bool in_p, enum reg_class rclass,
enum machine_mode mode, rtx x)
{
enum insn_code icode;
sri.icode = CODE_FOR_nothing;
sri.prev_sri = NULL;
- class = targetm.secondary_reload (in_p, x, class, mode, &sri);
+ rclass = targetm.secondary_reload (in_p, x, rclass, mode, &sri);
icode = sri.icode;
/* If there are no secondary reloads at all, we return NO_REGS.
If an intermediate register is needed, we return its class. */
- if (icode == CODE_FOR_nothing || class != NO_REGS)
- return class;
+ if (icode == CODE_FOR_nothing || rclass != NO_REGS)
+ return rclass;
/* No intermediate register is needed, but we have a special reload
pattern, which we assume for now needs a scratch register. */
{
const char *scratch_constraint;
char scratch_letter;
- enum reg_class class;
+ enum reg_class rclass;
gcc_assert (insn_data[(int) icode].n_operands == 3);
scratch_constraint = insn_data[(int) icode].operand[2].constraint;
scratch_letter = *scratch_constraint;
if (scratch_letter == 'r')
return GENERAL_REGS;
- class = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
+ rclass = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
scratch_constraint);
- gcc_assert (class != NO_REGS);
- return class;
+ gcc_assert (rclass != NO_REGS);
+ return rclass;
}
\f
#ifdef SECONDARY_MEMORY_NEEDED
unsigned int dest_regno ATTRIBUTE_UNUSED)
{
int best_cost = -1;
- int class;
+ int rclass;
int regno;
enum reg_class best_class = NO_REGS;
enum reg_class dest_class ATTRIBUTE_UNUSED = REGNO_REG_CLASS (dest_regno);
unsigned int best_size = 0;
int cost;
- for (class = 1; class < N_REG_CLASSES; class++)
+ for (rclass = 1; rclass < N_REG_CLASSES; rclass++)
{
int bad = 0;
int good = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER - n && ! bad; regno++)
- if (TEST_HARD_REG_BIT (reg_class_contents[class], regno))
+ if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno))
{
if (HARD_REGNO_MODE_OK (regno, inner))
{
good = 1;
- if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno + n)
+ if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n)
|| ! HARD_REGNO_MODE_OK (regno + n, outer))
bad = 1;
}
if (bad || !good)
continue;
- cost = REGISTER_MOVE_COST (outer, class, dest_class);
+ cost = REGISTER_MOVE_COST (outer, rclass, dest_class);
- if ((reg_class_size[class] > best_size
+ if ((reg_class_size[rclass] > best_size
&& (best_cost < 0 || best_cost >= cost))
|| best_cost > cost)
{
- best_class = class;
- best_size = reg_class_size[class];
- best_cost = REGISTER_MOVE_COST (outer, class, dest_class);
+ best_class = rclass;
+ best_size = reg_class_size[rclass];
+ best_cost = REGISTER_MOVE_COST (outer, rclass, dest_class);
}
}
\f
/* Return the number of a previously made reload that can be combined with
a new one, or n_reloads if none of the existing reloads can be used.
- OUT, CLASS, TYPE and OPNUM are the same arguments as passed to
+ OUT, RCLASS, TYPE and OPNUM are the same arguments as passed to
push_reload, they determine the kind of the new reload that we try to
combine. P_IN points to the corresponding value of IN, which can be
modified by this function.
DONT_SHARE is nonzero if we can't share any input-only reload for IN. */
static int
-find_reusable_reload (rtx *p_in, rtx out, enum reg_class class,
+find_reusable_reload (rtx *p_in, rtx out, enum reg_class rclass,
enum reload_type type, int opnum, int dont_share)
{
rtx in = *p_in;
than we otherwise would. */
for (i = 0; i < n_reloads; i++)
- if ((reg_class_subset_p (class, rld[i].class)
- || reg_class_subset_p (rld[i].class, class))
+ if ((reg_class_subset_p (rclass, rld[i].rclass)
+ || reg_class_subset_p (rld[i].rclass, rclass))
/* If the existing reload has a register, it must fit our class. */
&& (rld[i].reg_rtx == 0
- || TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ || TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
true_regnum (rld[i].reg_rtx)))
&& ((in != 0 && MATCHES (rld[i].in, in) && ! dont_share
&& (out == 0 || rld[i].out == 0 || MATCHES (rld[i].out, out)))
|| (out != 0 && MATCHES (rld[i].out, out)
&& (in == 0 || rld[i].in == 0 || MATCHES (rld[i].in, in))))
&& (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out))
- && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES)
+ && (SMALL_REGISTER_CLASS_P (rclass) || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, rld[i].when_needed, opnum, rld[i].opnum))
return i;
the preincrementation as happening before any ref in this insn
to that register. */
for (i = 0; i < n_reloads; i++)
- if ((reg_class_subset_p (class, rld[i].class)
- || reg_class_subset_p (rld[i].class, class))
+ if ((reg_class_subset_p (rclass, rld[i].rclass)
+ || reg_class_subset_p (rld[i].rclass, rclass))
/* If the existing reload has a register, it must fit our
class. */
&& (rld[i].reg_rtx == 0
- || TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ || TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
true_regnum (rld[i].reg_rtx)))
&& out == 0 && rld[i].out == 0 && rld[i].in != 0
&& ((REG_P (in)
&& GET_RTX_CLASS (GET_CODE (in)) == RTX_AUTOINC
&& MATCHES (XEXP (in, 0), rld[i].in)))
&& (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out))
- && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES)
+ && (SMALL_REGISTER_CLASS_P (rclass) || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, rld[i].when_needed,
opnum, rld[i].opnum))
{
If IN and OUT are both nonzero, it means the same register must be used
to reload both IN and OUT.
- CLASS is a register class required for the reloaded data.
+ RCLASS is a register class required for the reloaded data.
INMODE is the machine mode that the instruction requires
for the reg that replaces IN and OUTMODE is likewise for OUT.
int
push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
- enum reg_class class, enum machine_mode inmode,
+ enum reg_class rclass, enum machine_mode inmode,
enum machine_mode outmode, int strict_low, int optional,
int opnum, enum reload_type type)
{
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.
if (in != 0 && GET_CODE (in) == SUBREG
&& (subreg_lowpart_p (in) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class)
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, rclass)
#endif
&& (CONSTANT_P (SUBREG_REG (in))
|| GET_CODE (SUBREG_REG (in)) == PLUS
!= (int) hard_regno_nregs[REGNO (SUBREG_REG (in))]
[GET_MODE (SUBREG_REG (in))]))
|| ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode)))
- || (secondary_reload_class (1, class, inmode, in) != NO_REGS
- && (secondary_reload_class (1, class, GET_MODE (SUBREG_REG (in)),
+ || (secondary_reload_class (1, rclass, inmode, in) != NO_REGS
+ && (secondary_reload_class (1, rclass, GET_MODE (SUBREG_REG (in)),
SUBREG_REG (in))
== NO_REGS))
#ifdef CANNOT_CHANGE_MODE_CLASS
if (in != 0 && reload_inner_reg_of_subreg (in, inmode, 0))
{
- enum reg_class in_class = class;
+ enum reg_class in_class = rclass;
if (REG_P (SUBREG_REG (in)))
in_class
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class)
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, rclass)
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
!= (int) hard_regno_nregs[REGNO (SUBREG_REG (out))]
[GET_MODE (SUBREG_REG (out))]))
|| ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode)))
- || (secondary_reload_class (0, class, outmode, out) != NO_REGS
- && (secondary_reload_class (0, class, GET_MODE (SUBREG_REG (out)),
+ || (secondary_reload_class (0, rclass, outmode, out) != NO_REGS
+ && (secondary_reload_class (0, rclass, GET_MODE (SUBREG_REG (out)),
SUBREG_REG (out))
== NO_REGS))
#ifdef CANNOT_CHANGE_MODE_CLASS
/* If IN appears in OUT, we can't share any input-only reload for IN. */
if (in != 0 && out != 0 && MEM_P (out)
- && (REG_P (in) || MEM_P (in))
+ && (REG_P (in) || MEM_P (in) || GET_CODE (in) == PLUS)
&& reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0)))
dont_share = 1;
/* Narrow down the class of register wanted if that is
desirable on this machine for efficiency. */
{
- enum reg_class preferred_class = class;
+ enum reg_class preferred_class = rclass;
if (in != 0)
- preferred_class = PREFERRED_RELOAD_CLASS (in, class);
+ preferred_class = PREFERRED_RELOAD_CLASS (in, rclass);
/* Output reloads may need analogous treatment, different in detail. */
#ifdef PREFERRED_OUTPUT_RELOAD_CLASS
/* Discard what the target said if we cannot do it. */
if (preferred_class != NO_REGS
|| (optional && type == RELOAD_FOR_OUTPUT))
- class = preferred_class;
+ rclass = preferred_class;
}
/* Make sure we use a class that can handle the actual pseudo
can handle SImode, QImode needs a smaller class. */
#ifdef LIMIT_RELOAD_CLASS
if (in_subreg_loc)
- class = LIMIT_RELOAD_CLASS (inmode, class);
+ rclass = LIMIT_RELOAD_CLASS (inmode, rclass);
else if (in != 0 && GET_CODE (in) == SUBREG)
- class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), class);
+ rclass = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), rclass);
if (out_subreg_loc)
- class = LIMIT_RELOAD_CLASS (outmode, class);
+ rclass = LIMIT_RELOAD_CLASS (outmode, rclass);
if (out != 0 && GET_CODE (out) == SUBREG)
- class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), class);
+ rclass = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), rclass);
#endif
/* Verify that this class is at least possible for the mode that
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (HARD_REGNO_MODE_OK (i, mode)
- && TEST_HARD_REG_BIT (reg_class_contents[(int) class], i))
- {
- int nregs = hard_regno_nregs[i][mode];
-
- int j;
- for (j = 1; j < nregs; j++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j))
- break;
- if (j == nregs)
- break;
- }
+ && in_hard_reg_set_p (reg_class_contents[(int) rclass], mode, i))
+ break;
if (i == FIRST_PSEUDO_REGISTER)
{
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;
}
}
/* Optional output reloads are always OK even if we have no register class,
since the function of these reloads is only to have spill_reg_store etc.
set, so that the storing insn can be deleted later. */
- gcc_assert (class != NO_REGS
+ gcc_assert (rclass != NO_REGS
|| (optional != 0 && type == RELOAD_FOR_OUTPUT));
- i = find_reusable_reload (&in, out, class, type, opnum, dont_share);
+ i = find_reusable_reload (&in, out, rclass, type, opnum, dont_share);
if (i == n_reloads)
{
if (in != 0)
secondary_in_reload
- = push_secondary_reload (1, in, opnum, optional, class, inmode, type,
+ = push_secondary_reload (1, in, opnum, optional, rclass, inmode, type,
&secondary_in_icode, NULL);
if (out != 0 && GET_CODE (out) != SCRATCH)
secondary_out_reload
- = push_secondary_reload (0, out, opnum, optional, class, outmode,
+ = push_secondary_reload (0, out, opnum, optional, rclass, outmode,
type, &secondary_out_icode, NULL);
/* We found no existing reload suitable for re-use.
|| (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in))))
&& reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
- class, inmode))
+ rclass, inmode))
get_secondary_mem (in, inmode, opnum, type);
#endif
i = n_reloads;
rld[i].in = in;
rld[i].out = out;
- rld[i].class = class;
+ rld[i].rclass = rclass;
rld[i].inmode = inmode;
rld[i].outmode = outmode;
rld[i].reg_rtx = 0;
&& (REG_P (out)
|| (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out))))
&& reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (class,
+ && SECONDARY_MEMORY_NEEDED (rclass,
REGNO_REG_CLASS (reg_or_subregno (out)),
outmode))
get_secondary_mem (out, outmode, opnum, type);
rld[i].out = out;
rld[i].out_reg = outloc ? *outloc : 0;
}
- if (reg_class_subset_p (class, rld[i].class))
- rld[i].class = class;
+ if (reg_class_subset_p (rclass, rld[i].rclass))
+ rld[i].rclass = rclass;
rld[i].optional &= optional;
if (MERGE_TO_OTHER (type, rld[i].when_needed,
opnum, rld[i].opnum))
{
rld[i].reg_rtx = find_dummy_reload (in, out, inloc, outloc,
inmode, outmode,
- rld[i].class, i,
+ rld[i].rclass, i,
earlyclobber_operand_p (out));
/* If the outgoing register already contains the same value
&& 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 (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end,
- 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,
- (regno
- + hard_regno_nregs[regno]
- [rel_mode]),
+ end_hard_regno (rel_mode,
+ regno),
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]
- [rel_mode]),
+ end_hard_regno (rel_mode, regno),
PATTERN (this_insn)))
/* ??? Why is this code so different from the previous?
Is there any simple coherent way to describe the two together?
for (offs = 0; offs < nregs; offs++)
if (fixed_regs[regno + offs]
- || ! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
regno + offs))
break;
if (offs == nregs
&& (! (refers_to_regno_for_reload_p
- (regno, (regno + hard_regno_nregs[regno][inmode]),
- in, (rtx *)0))
+ (regno, end_hard_regno (inmode, regno), in, (rtx *) 0))
|| can_reload_into (in, regno, inmode)))
{
rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
static void
combine_reloads (void)
{
- int i;
+ int i, regno;
int output_reload = -1;
int secondary_out = -1;
rtx note;
return;
/* If there is a reload for part of the address of this operand, we would
- need to chnage it to RELOAD_FOR_OTHER_ADDRESS. But that would extend
+ need to change it to RELOAD_FOR_OTHER_ADDRESS. But that would extend
its life to the point where doing this combine would not lower the
number of spill registers needed. */
for (i = 0; i < n_reloads; i++)
&& rld[i].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
&& rld[i].when_needed != RELOAD_FOR_OUTADDR_ADDRESS
&& rld[i].when_needed != RELOAD_OTHER
- && (CLASS_MAX_NREGS (rld[i].class, rld[i].inmode)
- == CLASS_MAX_NREGS (rld[output_reload].class,
+ && (CLASS_MAX_NREGS (rld[i].rclass, rld[i].inmode)
+ == CLASS_MAX_NREGS (rld[output_reload].rclass,
rld[output_reload].outmode))
&& rld[i].inc == 0
&& rld[i].reg_rtx == 0
secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum]))
#endif
&& (SMALL_REGISTER_CLASSES
- ? (rld[i].class == rld[output_reload].class)
- : (reg_class_subset_p (rld[i].class,
- rld[output_reload].class)
- || reg_class_subset_p (rld[output_reload].class,
- rld[i].class)))
+ ? (rld[i].rclass == rld[output_reload].rclass)
+ : (reg_class_subset_p (rld[i].rclass,
+ rld[output_reload].rclass)
+ || reg_class_subset_p (rld[output_reload].rclass,
+ rld[i].rclass)))
&& (MATCHES (rld[i].in, rld[output_reload].out)
/* Args reversed because the first arg seems to be
the one that we imagine being modified
rld[output_reload].out))))
&& ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode,
rld[i].when_needed != RELOAD_FOR_INPUT)
- && (reg_class_size[(int) rld[i].class]
+ && (reg_class_size[(int) rld[i].rclass]
|| SMALL_REGISTER_CLASSES)
/* We will allow making things slightly worse by combining an
input and an output, but no worse than that. */
= secondary_memlocs_elim[(int) rld[output_reload].outmode][rld[output_reload].opnum];
#endif
/* If required, minimize the register class. */
- if (reg_class_subset_p (rld[output_reload].class,
- rld[i].class))
- rld[i].class = rld[output_reload].class;
+ if (reg_class_subset_p (rld[output_reload].rclass,
+ rld[i].rclass))
+ rld[i].rclass = rld[output_reload].rclass;
/* Transfer all replacements from the old reload to the combined. */
for (j = 0; j < n_replacements; j++)
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)
- && 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))])
+ && !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].rclass],
+ 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].rclass], 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))])
+ || !(TEST_HARD_REG_BIT
+ (reg_class_contents[(int) rld[secondary_out].rclass],
+ 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)))
+ && 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;
}
}
If so, return the register rtx that proves acceptable.
INLOC and OUTLOC are locations where IN and OUT appear in the insn.
- CLASS is the register class required for the reload.
+ RCLASS is the register class required for the reload.
If FOR_REAL is >= 0, it is the number of the reload,
and in some cases when it can be discovered that OUT doesn't need
static rtx
find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
enum machine_mode inmode, enum machine_mode outmode,
- enum reg_class class, int for_real, int earlyclobber)
+ enum reg_class rclass, int for_real, int earlyclobber)
{
rtx in = real_in;
rtx out = real_out;
/* Narrow down the reg class, the same way push_reload will;
otherwise we might find a dummy now, but push_reload won't. */
{
- enum reg_class preferred_class = PREFERRED_RELOAD_CLASS (in, class);
+ enum reg_class preferred_class = PREFERRED_RELOAD_CLASS (in, rclass);
if (preferred_class != NO_REGS)
- class = preferred_class;
+ rclass = preferred_class;
}
/* See if OUT will do. */
unsigned int i;
for (i = 0; i < nwords; i++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
regno + i))
break;
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 (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end,
- 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];
unsigned int i;
for (i = 0; i < nwords; i++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
regno + i))
break;
/* See if this reg overlaps range under consideration. */
if (r < end_regno
- && r + hard_regno_nregs[r][GET_MODE (op0)] > beg_regno)
+ && end_hard_regno (GET_MODE (op0), r) > beg_regno)
return 1;
}
}
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
return 0;
case LABEL_REF:
}
else
/* A hard reg. */
- val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)];
+ val.end = end_hard_regno (GET_MODE (x), val.start);
break;
case SUBREG:
return decompose (SUBREG_REG (x));
else
/* A hard reg. */
- val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)];
+ val.end = val.start + subreg_nregs (x);
break;
case SCRATCH:
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],
&& MEM_P (op)
&& REG_P (reg)
&& (GET_MODE_SIZE (GET_MODE (reg))
- >= GET_MODE_SIZE (GET_MODE (op))))
+ >= GET_MODE_SIZE (GET_MODE (op)))
+ && reg_equiv_constant[REGNO (reg)] == 0)
set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg),
insn),
REG_EQUAL, reg_equiv_memory_loc[REGNO (reg)]);
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);
}
}
}
*recog_data.operand_loc[i] = substitution;
- /* If we're replacing an operand with a LABEL_REF, we need
- to make sure that there's a REG_LABEL note attached to
+ /* If we're replacing an operand with a LABEL_REF, we need to
+ make sure that there's a REG_LABEL_OPERAND note attached to
this instruction. */
- if (!JUMP_P (insn)
- && GET_CODE (substitution) == LABEL_REF
- && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
- XEXP (substitution, 0),
- REG_NOTES (insn));
+ if (GET_CODE (substitution) == LABEL_REF
+ && !find_reg_note (insn, REG_LABEL_OPERAND,
+ XEXP (substitution, 0))
+ /* For a JUMP_P, if it was a branch target it must have
+ already been recorded as such. */
+ && (!JUMP_P (insn)
+ || !label_is_jump_target_p (XEXP (substitution, 0),
+ insn)))
+ add_reg_note (insn, REG_LABEL_OPERAND, XEXP (substitution, 0));
}
else
retval |= (substed_operand[i] != *recog_data.operand_loc[i]);
&& rld[i].out == 0)
{
rld[i].reg_rtx
- = find_equiv_reg (rld[i].in, insn, rld[i].class, -1,
+ = find_equiv_reg (rld[i].in, insn, rld[i].rclass, -1,
static_reload_reg_p, 0, rld[i].inmode);
/* Prevent generation of insn to load the value
because the one we found already has the value. */
}
#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)
if (i != j && rld[j].in != 0 && rld[j].out == 0
&& rld[j].when_needed == rld[i].when_needed
&& MATCHES (rld[i].in, rld[j].in)
- && rld[i].class == rld[j].class
+ && rld[i].rclass == rld[j].rclass
&& !rld[i].nocombine && !rld[j].nocombine
&& rld[i].reg_rtx == rld[j].reg_rtx)
{
> GET_MODE_SIZE (rld[i].inmode)))
? rld[i].outmode : rld[i].inmode;
- rld[i].nregs = CLASS_MAX_NREGS (rld[i].class, rld[i].mode);
+ rld[i].nregs = CLASS_MAX_NREGS (rld[i].rclass, rld[i].mode);
}
/* Special case a simple move with an input reload and a
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));
unsigned int regno = REGNO (dest);
if (regno < FIRST_PSEUDO_REGISTER
- && TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno)
+ && TEST_HARD_REG_BIT (reg_class_contents[rld[i].rclass], regno)
&& HARD_REGNO_MODE_OK (regno, rld[i].mode))
{
int nr = hard_regno_nregs[regno][rld[i].mode];
int ok = 1, nri;
for (nri = 1; nri < nr; nri ++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno + nri))
+ if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].rclass], regno + nri))
ok = 0;
if (ok)
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.
x = mem;
i = find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, insn);
+ if (!rtx_equal_p (x, mem))
+ push_reg_equiv_alt_mem (regno, x);
if (address_reloaded)
*address_reloaded = i;
}
int regno = REGNO (SUBREG_REG (x));
rtx tem;
- if (subreg_lowpart_p (x)
- && regno >= FIRST_PSEUDO_REGISTER
- && reg_renumber[regno] < 0
- && reg_equiv_constant[regno] != 0
- && (tem = gen_lowpart_common (GET_MODE (x),
- reg_equiv_constant[regno])) != 0
- && LEGITIMATE_CONSTANT_P (tem))
- return tem;
-
if (regno >= FIRST_PSEUDO_REGISTER
&& reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno],
GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
gcc_assert (tem);
- if (LEGITIMATE_CONSTANT_P (tem))
- return tem;
+ if (CONSTANT_P (tem) && !LEGITIMATE_CONSTANT_P (tem))
+ {
+ tem = force_const_mem (GET_MODE (x), tem);
+ i = find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
+ &XEXP (tem, 0), opnum, type,
+ ind_levels, insn);
+ if (address_reloaded)
+ *address_reloaded = i;
+ }
+ return tem;
}
/* If the subreg contains a reg that will be converted to a mem,
{
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];
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 (!rtx_equal_p (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.
case CONST_INT:
case CONST:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case LABEL_REF:
else if (code0 == REG && code1 == REG)
{
- if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
- && regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
+ if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
+ && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
return 0;
- else if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
- && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
+ else if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
+ && regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
return 0;
- else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
- find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
- &XEXP (x, 0), opnum, type, ind_levels,
- insn);
else if (regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
&XEXP (x, 1), opnum, type, ind_levels,
find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
&XEXP (x, 0), opnum, type, ind_levels,
insn);
+ else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
+ find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+ &XEXP (x, 0), opnum, type, ind_levels,
+ insn);
else if (REGNO_OK_FOR_INDEX_P (REGNO (op0)))
find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
&XEXP (x, 1), opnum, type, ind_levels,
insn);
else
{
- find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+ find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
&XEXP (x, 0), opnum, type, ind_levels,
insn);
- find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
+ find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
&XEXP (x, 1), opnum, type, ind_levels,
insn);
}
/* 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. */
- 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);
+ register with its equivalent constant where applicable.
+
+ We also handle the case where the register was eliminated
+ resulting in a PLUS subexpression.
+
+ 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))
+ && !REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
+ || GET_CODE (XEXP (op1, 1)) == PLUS)
+ find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
+ &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 (!rtx_equal_p (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 (!rtx_equal_p (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. */
}
}
- /* 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;
rtx equiv = (MEM_P (XEXP (x, 0))
? XEXP (x, 0)
: reg_equiv_mem[regno]);
- int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
+ int icode = (int) optab_handler (add_optab, Pmode)->insn_code;
if (insn && NONJUMP_INSN_P (insn) && equiv
&& memory_operand (equiv, GET_MODE (equiv))
#ifdef HAVE_cc0
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);
}
return value;
}
-
- else if (MEM_P (XEXP (x, 0)))
- {
- /* This is probably the result of a substitution, by eliminate_regs,
- of an equivalent address for a pseudo that was not allocated to a
- hard register. Verify that the specified address is valid and
- reload it into a register. */
- /* Variable `tem' might or might not be used in FIND_REG_INC_NOTE. */
- rtx tem ATTRIBUTE_UNUSED = XEXP (x, 0);
- rtx link;
- int reloadnum;
-
- /* Since we know we are going to reload this item, don't decrement
- for the indirection level.
-
- Note that this is actually conservative: it would be slightly
- more efficient to use the value of SPILL_INDIRECT_LEVELS from
- reload1.c here. */
- /* We can't use ADDR_TYPE (type) here, because we need to
- write back the value after reading it, hence we actually
- need two registers. */
- find_reloads_address (GET_MODE (x), &XEXP (x, 0),
- XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
- opnum, type, ind_levels, insn);
-
- reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0,
- context_reg_class,
- GET_MODE (x), VOIDmode, 0, 0, opnum, type);
- rld[reloadnum].inc
- = find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
-
- link = FIND_REG_INC_NOTE (this_insn, tem);
- if (link != 0)
- push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
-
- return 1;
- }
return 0;
case TRUNCATE:
find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
&XEXP (x, 0), opnum, ADDR_TYPE (type),
ind_levels, insn);
+ if (!rtx_equal_p (x, tem))
+ push_reg_equiv_alt_mem (regno, x);
}
}
is larger than the class size, then reload the whole SUBREG. */
else
{
- enum reg_class class = context_reg_class;
- if ((unsigned) CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x)))
- > reg_class_size[class])
+ enum reg_class rclass = context_reg_class;
+ if ((unsigned) CLASS_MAX_NREGS (rclass, GET_MODE (SUBREG_REG (x)))
+ > reg_class_size[rclass])
{
x = find_reloads_subreg_address (x, 0, opnum,
ADDR_TYPE (type),
ind_levels, insn);
- push_reload (x, NULL_RTX, loc, (rtx*) 0, class,
+ push_reload (x, NULL_RTX, loc, (rtx*) 0, rclass,
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
}
\f
/* X, which is found at *LOC, is a part of an address that needs to be
- reloaded into a register of class CLASS. If X is a constant, or if
+ reloaded into a register of class RCLASS. If X is a constant, or if
X is a PLUS that contains a constant, check that the constant is a
legitimate operand and that we are supposed to be able to load
it into the register.
supports. */
static void
-find_reloads_address_part (rtx x, rtx *loc, enum reg_class class,
+find_reloads_address_part (rtx x, rtx *loc, enum reg_class rclass,
enum machine_mode mode, int opnum,
enum reload_type type, int ind_levels)
{
if (CONSTANT_P (x)
&& (! LEGITIMATE_CONSTANT_P (x)
- || PREFERRED_RELOAD_CLASS (x, class) == NO_REGS))
+ || PREFERRED_RELOAD_CLASS (x, rclass) == NO_REGS))
{
- rtx tem;
-
- tem = x = force_const_mem (mode, x);
- find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
+ x = force_const_mem (mode, x);
+ find_reloads_address (mode, &x, XEXP (x, 0), &XEXP (x, 0),
opnum, type, ind_levels, 0);
}
else if (GET_CODE (x) == PLUS
&& CONSTANT_P (XEXP (x, 1))
&& (! LEGITIMATE_CONSTANT_P (XEXP (x, 1))
- || PREFERRED_RELOAD_CLASS (XEXP (x, 1), class) == NO_REGS))
+ || PREFERRED_RELOAD_CLASS (XEXP (x, 1), rclass) == NO_REGS))
{
rtx tem;
tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
x = gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), tem);
- find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
+ find_reloads_address (mode, &XEXP (x, 1), XEXP (tem, 0), &XEXP (tem, 0),
opnum, type, ind_levels, 0);
}
- push_reload (x, NULL_RTX, loc, (rtx*) 0, class,
+ push_reload (x, NULL_RTX, loc, (rtx*) 0, rclass,
mode, VOIDmode, 0, 0, opnum, type);
}
\f
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;
+ int reloaded;
/* For big-endian paradoxical subregs, SUBREG_BYTE does not
hold the correct (negative) byte offset. */
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
return x;
}
- find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
- &XEXP (tem, 0), opnum, type,
- ind_levels, insn);
+ reloaded = 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 && !rtx_equal_p (tem, orig))
+ push_reg_equiv_alt_mem (regno, tem);
+
+ /* For some processors an address may be valid in the
+ original mode but not in a smaller mode. For
+ example, ARM accepts a scaled index register in
+ SImode but not in HImode. Similarly, the address may
+ have been valid before the subreg offset was added,
+ but not afterwards. find_reloads_address
+ assumes that we pass it a valid address, and doesn't
+ force a reload. This will probably be fine if
+ find_reloads_address finds some reloads. But if it
+ doesn't find any, then we may have just converted a
+ valid address into an invalid one. Check for that
+ here. */
+ if (reloaded == 0
+ && !strict_memory_address_p (GET_MODE (tem),
+ XEXP (tem, 0)))
+ push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
+ base_reg_class (GET_MODE (tem), MEM, SCRATCH),
+ GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
+ opnum, type);
/* If this is not a toplevel operand, find_reloads doesn't see
this substitution. We have to emit a USE of the pseudo so
rtx reloadreg = rld[r->what].reg_rtx;
if (reloadreg)
{
-#ifdef ENABLE_CHECKING
- /* Internal consistency test. Check that we don't modify
+#ifdef DEBUG_RELOAD
+ /* This checking takes a very long time on some platforms
+ causing the gcc.c-torture/compile/limits-fnargs.c test
+ to time out during testing. See PR 31850.
+
+ Internal consistency test. Check that we don't modify
anything in the equivalence arrays. Whenever something from
those arrays needs to be reloaded, it must be unshared before
being substituted into; the equivalence must not be modified.
CHECK_MODF (reg_equiv_mem);
#undef CHECK_MODF
}
-#endif /* ENABLE_CHECKING */
+#endif /* DEBUG_RELOAD */
- /* If we're replacing a LABEL_REF with a register, add a
- REG_LABEL note to indicate to flow which label this
+ /* If we're replacing a LABEL_REF with a register, there must
+ already be an indication (to e.g. flow) which label this
register refers to. */
- if (GET_CODE (*r->where) == LABEL_REF
- && JUMP_P (insn))
- {
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
- XEXP (*r->where, 0),
- REG_NOTES (insn));
- JUMP_LABEL (insn) = XEXP (*r->where, 0);
- }
+ gcc_assert (GET_CODE (*r->where) != LABEL_REF
+ || !JUMP_P (insn)
+ || find_reg_note (insn,
+ REG_LABEL_OPERAND,
+ XEXP (*r->where, 0))
+ || label_is_jump_target_p (XEXP (*r->where, 0), insn));
/* Encapsulate RELOADREG so its machine mode matches what
used to be there. Note that gen_lowpart_common will
unsigned int inner_regno = subreg_regno (x);
unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[inner_regno][GET_MODE (x)] : 1);
+ ? subreg_nregs (x) : 1);
return endregno > inner_regno && regno < inner_endregno;
}
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x),
GET_MODE (x));
+ endregno = regno + (regno < FIRST_PSEUDO_REGISTER
+ ? subreg_nregs (x) : 1);
+
+ return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
}
else if (REG_P (x))
{
gcc_assert (reg_equiv_constant[regno]);
return 0;
}
+
+ endregno = END_HARD_REGNO (x);
+
+ return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
}
else if (MEM_P (x))
return refers_to_mem_for_reload_p (in);
if (REG_P (in))
return 0;
else if (GET_CODE (in) == PLUS)
- return (reg_overlap_mentioned_for_reload_p (x, XEXP (in, 0))
+ return (rtx_equal_p (x, in)
+ || reg_overlap_mentioned_for_reload_p (x, XEXP (in, 0))
|| reg_overlap_mentioned_for_reload_p (x, XEXP (in, 1)));
else return (reg_overlap_mentioned_for_reload_p (XEXP (x, 0), in)
|| reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in));
}
- endregno = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
-
- return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
+ gcc_unreachable ();
}
/* Return nonzero if anything in X contains a MEM. Look also for pseudo
\f
/* Check the insns before INSN to see if there is a suitable register
containing the same value as GOAL.
- If OTHER is -1, look for a register in class CLASS.
+ If OTHER is -1, look for a register in class RCLASS.
Otherwise, just see if register number OTHER shares GOAL's value.
Return an rtx for the register found, or zero if none is found.
as if it were a constant except that sp is required to be unchanging. */
rtx
-find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
+find_equiv_reg (rtx goal, rtx insn, enum reg_class rclass, int other,
short *reload_reg_p, int goalreg, enum machine_mode mode)
{
rtx p = insn;
}
else if ((unsigned) valueno >= FIRST_PSEUDO_REGISTER)
continue;
- else
- {
- int i;
-
- for (i = hard_regno_nregs[valueno][mode] - 1; i >= 0; i--)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
- valueno + i))
- break;
- if (i >= 0)
- continue;
- }
+ else if (!in_hard_reg_set_p (reg_class_contents[(int) rclass],
+ mode, valueno))
+ continue;
value = valtry;
where = p;
break;
and is also a register that appears in the address of GOAL. */
if (goal_mem && value == SET_DEST (single_set (where))
- && refers_to_regno_for_reload_p (valueno,
- (valueno
- + hard_regno_nregs[valueno][mode]),
+ && refers_to_regno_for_reload_p (valueno, end_hard_regno (mode, valueno),
goal, (rtx*) 0))
return 0;
fprintf (f, "\n\t");
}
- fprintf (f, "%s, ", reg_class_names[(int) rld[r].class]);
+ fprintf (f, "%s, ", reg_class_names[(int) rld[r].rclass]);
fprintf (f, "%s (opnum = %d)",
reload_when_needed_name[(int) rld[r].when_needed],