/* 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, 2009
+ 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"
+#include "ira.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 maybe_memory_address_p (enum machine_mode, rtx, rtx *);
+static int maybe_memory_address_addr_space_p (enum machine_mode, rtx,
+ addr_space_t, rtx *);
static int find_reloads_address (enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx);
static rtx subst_reg_equivs (rtx, rtx);
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);
- icode = sri.icode;
+ rclass = targetm.secondary_reload (in_p, x, reload_class, reload_mode, &sri);
+ icode = (enum insn_code) 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);
- icode = sri.icode;
+ rclass = targetm.secondary_reload (in_p, x, rclass, mode, &sri);
+ icode = (enum insn_code) 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
didn't give us a new MEM, make a new one if it isn't valid. */
loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX);
- mem_valid = strict_memory_address_p (mode, XEXP (loc, 0));
+ mem_valid = strict_memory_address_addr_space_p (mode, XEXP (loc, 0),
+ MEM_ADDR_SPACE (loc));
if (! mem_valid && loc == secondary_memlocs[(int) mode])
loc = copy_rtx (loc);
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, (enum reg_class) 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 = (enum reg_class) rclass;
+ best_size = reg_class_size[rclass];
+ best_cost = REGISTER_MOVE_COST (outer, (enum reg_class) 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 "
/* 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);
else
remove_address_replacements (rld[i].in);
}
- rld[i].in = in;
- rld[i].in_reg = in_reg;
+ /* When emitting reloads we don't necessarily look at the in-
+ and outmode, but also directly at the operands (in and out).
+ So we can't simply overwrite them with whatever we have found
+ for this (to-be-merged) reload, we have to "merge" that too.
+ Reusing another reload already verified that we deal with the
+ same operands, just possibly in different modes. So we
+ overwrite the operands only when the new mode is larger.
+ See also PR33613. */
+ if (!rld[i].in
+ || GET_MODE_SIZE (GET_MODE (in))
+ > GET_MODE_SIZE (GET_MODE (rld[i].in)))
+ rld[i].in = in;
+ if (!rld[i].in_reg
+ || (in_reg
+ && GET_MODE_SIZE (GET_MODE (in_reg))
+ > GET_MODE_SIZE (GET_MODE (rld[i].in_reg))))
+ rld[i].in_reg = in_reg;
}
if (out != 0)
{
- rld[i].out = out;
- rld[i].out_reg = outloc ? *outloc : 0;
+ if (!rld[i].out
+ || (out
+ && GET_MODE_SIZE (GET_MODE (out))
+ > GET_MODE_SIZE (GET_MODE (rld[i].out))))
+ rld[i].out = out;
+ if (outloc
+ && (!rld[i].out_reg
+ || GET_MODE_SIZE (GET_MODE (*outloc))
+ > GET_MODE_SIZE (GET_MODE (rld[i].out_reg))))
+ rld[i].out_reg = *outloc;
}
- 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
value for the incoming operand (same as outgoing one). */
if (rld[i].reg_rtx == out
&& (REG_P (in) || CONSTANT_P (in))
- && 0 != find_equiv_reg (in, this_insn, 0, REGNO (out),
+ && 0 != find_equiv_reg (in, this_insn, NO_REGS, REGNO (out),
static_reload_reg_p, i, inmode))
rld[i].in = out;
}
&& 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_LR_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_LR_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;
}
}
return 0;
}
-/* Return 1 if ADDR is a valid memory address for mode MODE,
- and check that each pseudo reg has the proper kind of
- hard reg. */
+/* Return 1 if ADDR is a valid memory address for mode MODE
+ in address space AS, and check that each pseudo reg has the
+ proper kind of hard reg. */
int
-strict_memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr)
+strict_memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx addr, addr_space_t as)
{
+#ifdef GO_IF_LEGITIMATE_ADDRESS
+ gcc_assert (ADDR_SPACE_GENERIC_P (as));
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
return 0;
win:
return 1;
+#else
+ return targetm.addr_space.legitimate_address_p (mode, addr, 1, as);
+#endif
}
\f
/* Like rtx_equal_p except that it allows a REG and a SUBREG to match
if (GET_MODE (x) != GET_MODE (y))
return 0;
+ /* MEMs refering to different address space are not equivalent. */
+ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+ return 0;
+
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_FIXED:
return 0;
case LABEL_REF:
offset = XEXP (offset, 0);
if (GET_CODE (offset) == PLUS)
{
- if (GET_CODE (XEXP (offset, 0)) == CONST_INT)
+ if (CONST_INT_P (XEXP (offset, 0)))
{
base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1));
offset = XEXP (offset, 0);
}
- else if (GET_CODE (XEXP (offset, 1)) == CONST_INT)
+ else if (CONST_INT_P (XEXP (offset, 1)))
{
base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0));
offset = XEXP (offset, 1);
offset = const0_rtx;
}
}
- else if (GET_CODE (offset) != CONST_INT)
+ else if (!CONST_INT_P (offset))
{
base = gen_rtx_PLUS (GET_MODE (base), base, offset);
offset = const0_rtx;
if (all_const && GET_CODE (base) == PLUS)
base = gen_rtx_CONST (GET_MODE (base), base);
- gcc_assert (GET_CODE (offset) == CONST_INT);
+ gcc_assert (CONST_INT_P (offset));
val.start = INTVAL (offset);
val.end = val.start + GET_MODE_SIZE (GET_MODE (x));
}
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];
enum reload_usage { RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE } modified[MAX_RECOG_OPERANDS];
int no_input_reloads = 0, no_output_reloads = 0;
int n_alternatives;
- int this_alternative[MAX_RECOG_OPERANDS];
+ enum reg_class this_alternative[MAX_RECOG_OPERANDS];
char this_alternative_match_win[MAX_RECOG_OPERANDS];
char this_alternative_win[MAX_RECOG_OPERANDS];
char this_alternative_offmemok[MAX_RECOG_OPERANDS];
char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
int goal_alternative_swapped;
int best;
+ int best_small_class_operands_num;
int commutative;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx substed_operand[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)]);
all the operands together against the register constraints. */
best = MAX_RECOG_OPERANDS * 2 + 600;
+ best_small_class_operands_num = 0;
swapped = 0;
goal_alternative_swapped = 0;
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;
if (REG_P (SUBREG_REG (operand))
&& REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
{
- if (!subreg_offset_representable_p
- (REGNO (SUBREG_REG (operand)),
- GET_MODE (SUBREG_REG (operand)),
- SUBREG_BYTE (operand),
- GET_MODE (operand)))
- force_reload = 1;
+ if (simplify_subreg_regno (REGNO (SUBREG_REG (operand)),
+ GET_MODE (SUBREG_REG (operand)),
+ SUBREG_BYTE (operand),
+ GET_MODE (operand)) < 0)
+ force_reload = 1;
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
GET_MODE (SUBREG_REG (operand)),
SUBREG_BYTE (operand),
force_reload = 1;
}
- this_alternative[i] = (int) NO_REGS;
+ this_alternative[i] = NO_REGS;
this_alternative_win[i] = 0;
this_alternative_match_win[i] = 0;
this_alternative_offmemok[i] = 0;
this combination, because we can't reload it. */
if (this_alternative_offmemok[m]
&& MEM_P (recog_data.operand[m])
- && this_alternative[m] == (int) NO_REGS
+ && this_alternative[m] == NO_REGS
&& ! this_alternative_win[m])
bad = 1;
if (this_alternative_win[m])
losers++;
this_alternative_win[m] = 0;
- if (this_alternative[m] == (int) NO_REGS)
+ if (this_alternative[m] == NO_REGS)
bad = 1;
/* But count the pair only once in the total badness of
this alternative, if the pair can be a dummy reload.
case 'p':
/* All necessary reloads for an address_operand
were handled in find_reloads_address. */
- this_alternative[i]
- = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
+ this_alternative[i] = base_reg_class (VOIDmode, ADDRESS,
+ SCRATCH);
win = 1;
badop = 0;
break;
- case 'm':
+ case TARGET_MEM_CONSTRAINT:
if (force_reload)
break;
if (MEM_P (operand)
break;
case 's':
- if (GET_CODE (operand) == CONST_INT
+ if (CONST_INT_P (operand)
|| (GET_CODE (operand) == CONST_DOUBLE
&& GET_MODE (operand) == VOIDmode))
break;
break;
case 'n':
- if (GET_CODE (operand) == CONST_INT
+ if (CONST_INT_P (operand)
|| (GET_CODE (operand) == CONST_DOUBLE
&& GET_MODE (operand) == VOIDmode))
win = 1;
case 'N':
case 'O':
case 'P':
- if (GET_CODE (operand) == CONST_INT
+ if (CONST_INT_P (operand)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
win = 1;
break;
case 'r':
this_alternative[i]
- = (int) reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
+ = reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
goto reg;
default:
/* If we didn't already win, we can reload
the address into a base register. */
- this_alternative[i]
- = (int) base_reg_class (VOIDmode, ADDRESS, SCRATCH);
+ this_alternative[i] = base_reg_class (VOIDmode,
+ ADDRESS,
+ SCRATCH);
badop = 0;
break;
}
}
this_alternative[i]
- = (int) (reg_class_subunion
- [this_alternative[i]]
- [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
+ = (reg_class_subunion
+ [this_alternative[i]]
+ [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
reg:
if (GET_MODE (operand) == BLKmode)
break;
/* If this operand could be handled with a reg,
and some reg is allowed, then this operand can be handled. */
- if (winreg && this_alternative[i] != (int) NO_REGS)
+ if (winreg && this_alternative[i] != NO_REGS)
badop = 0;
/* Record which operands fit this alternative. */
bad = 1;
/* Alternative loses if it has no regs for a reg operand. */
if (REG_P (operand)
- && this_alternative[i] == (int) NO_REGS
+ && this_alternative[i] == NO_REGS
&& this_alternative_matches[i] < 0)
bad = 1;
precisely the same as in the code below that calls
force_const_mem. */
if (CONST_POOL_OK_P (operand)
- && ((PREFERRED_RELOAD_CLASS (operand,
- (enum reg_class) this_alternative[i])
+ && ((PREFERRED_RELOAD_CLASS (operand, this_alternative[i])
== NO_REGS)
|| no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
const_to_mem = 1;
- if (this_alternative[i] != (int) NO_REGS)
+ if (this_alternative[i] != NO_REGS)
losers++;
}
LIMIT_RELOAD_CLASS, but we don't check that
here. */
- if (! CONSTANT_P (operand)
- && (enum reg_class) this_alternative[i] != NO_REGS)
+ if (! CONSTANT_P (operand) && this_alternative[i] != NO_REGS)
{
- if (PREFERRED_RELOAD_CLASS
- (operand, (enum reg_class) this_alternative[i])
+ if (PREFERRED_RELOAD_CLASS (operand, this_alternative[i])
== NO_REGS)
reject = 600;
#ifdef PREFERRED_OUTPUT_RELOAD_CLASS
if (operand_type[i] == RELOAD_FOR_OUTPUT
- && PREFERRED_OUTPUT_RELOAD_CLASS
- (operand, (enum reg_class) this_alternative[i])
- == NO_REGS)
+ && (PREFERRED_OUTPUT_RELOAD_CLASS (operand,
+ this_alternative[i])
+ == NO_REGS))
reject = 600;
#endif
}
because we might otherwise exhaust the class. */
if (! win && ! did_match
- && this_alternative[i] != (int) NO_REGS
+ && this_alternative[i] != NO_REGS
&& GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
&& reg_class_size [(int) preferred_class[i]] > 0
&& ! SMALL_REGISTER_CLASS_P (preferred_class[i]))
common case anyway. */
if (reg_class_subset_p (preferred_class[i],
this_alternative[i]))
- this_alternative[i] = (int) preferred_class[i];
+ this_alternative[i] = preferred_class[i];
else
reject += (2 + 2 * pref_or_nothing[i]);
}
/* If this alternative can be made to work by reloading,
and it needs less reloading than the others checked so far,
record it as the chosen goal for reloading. */
- if (! bad && best > losers)
+ if (! bad)
{
- for (i = 0; i < noperands; i++)
+ bool change_p = false;
+ int small_class_operands_num = 0;
+
+ if (best >= losers)
{
- goal_alternative[i] = this_alternative[i];
- goal_alternative_win[i] = this_alternative_win[i];
- goal_alternative_match_win[i] = this_alternative_match_win[i];
- goal_alternative_offmemok[i] = this_alternative_offmemok[i];
- goal_alternative_matches[i] = this_alternative_matches[i];
- goal_alternative_earlyclobber[i]
- = this_alternative_earlyclobber[i];
+ for (i = 0; i < noperands; i++)
+ small_class_operands_num
+ += SMALL_REGISTER_CLASS_P (this_alternative[i]) ? 1 : 0;
+ if (best > losers
+ || (best == losers
+ /* If the cost of the reloads is the same,
+ prefer alternative which requires minimal
+ number of small register classes for the
+ operands. This improves chances of reloads
+ for insn requiring small register
+ classes. */
+ && (small_class_operands_num
+ < best_small_class_operands_num)))
+ change_p = true;
+ }
+ if (change_p)
+ {
+ for (i = 0; i < noperands; i++)
+ {
+ goal_alternative[i] = this_alternative[i];
+ goal_alternative_win[i] = this_alternative_win[i];
+ goal_alternative_match_win[i]
+ = this_alternative_match_win[i];
+ goal_alternative_offmemok[i]
+ = this_alternative_offmemok[i];
+ goal_alternative_matches[i] = this_alternative_matches[i];
+ goal_alternative_earlyclobber[i]
+ = this_alternative_earlyclobber[i];
+ }
+ goal_alternative_swapped = swapped;
+ best = losers;
+ best_small_class_operands_num = small_class_operands_num;
+ goal_alternative_number = this_alternative_number;
+ goal_earlyclobber = this_earlyclobber;
}
- goal_alternative_swapped = swapped;
- best = losers;
- goal_alternative_number = this_alternative_number;
- goal_earlyclobber = this_earlyclobber;
}
}
address_reloaded[commutative + 1] = t;
memcpy (constraints, recog_data.constraints,
- noperands * sizeof (char *));
+ noperands * sizeof (const char *));
goto try_swapped;
}
else
/* Any constants that aren't allowed and can't be reloaded
into registers are here changed into memory references. */
for (i = 0; i < noperands; i++)
- if (! goal_alternative_win[i]
- && CONST_POOL_OK_P (recog_data.operand[i])
- && ((PREFERRED_RELOAD_CLASS (recog_data.operand[i],
- (enum reg_class) goal_alternative[i])
- == NO_REGS)
- || no_input_reloads)
- && operand_mode[i] != VOIDmode)
+ if (! goal_alternative_win[i])
{
- 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))
- goal_alternative_win[i] = 1;
- }
+ rtx op = recog_data.operand[i];
+ rtx subreg = NULL_RTX;
+ rtx plus = NULL_RTX;
+ enum machine_mode mode = operand_mode[i];
+
+ /* Reloads of SUBREGs of CONSTANT RTXs are handled later in
+ push_reload so we have to let them pass here. */
+ if (GET_CODE (op) == SUBREG)
+ {
+ subreg = op;
+ op = SUBREG_REG (op);
+ mode = GET_MODE (op);
+ }
- /* Likewise any invalid constants appearing as operand of a PLUS
- that is to be reloaded. */
- for (i = 0; i < noperands; i++)
- if (! goal_alternative_win[i]
- && GET_CODE (recog_data.operand[i]) == PLUS
- && CONST_POOL_OK_P (XEXP (recog_data.operand[i], 1))
- && (PREFERRED_RELOAD_CLASS (XEXP (recog_data.operand[i], 1),
- (enum reg_class) goal_alternative[i])
- == NO_REGS)
- && operand_mode[i] != VOIDmode)
- {
- rtx tem = force_const_mem (operand_mode[i],
- XEXP (recog_data.operand[i], 1));
- tem = gen_rtx_PLUS (operand_mode[i],
- XEXP (recog_data.operand[i], 0), tem);
+ if (GET_CODE (op) == PLUS)
+ {
+ plus = op;
+ op = XEXP (op, 1);
+ }
- substed_operand[i] = recog_data.operand[i]
- = find_reloads_toplev (tem, i, address_type[i],
- ind_levels, 0, insn, NULL);
+ if (CONST_POOL_OK_P (op)
+ && ((PREFERRED_RELOAD_CLASS (op,
+ (enum reg_class) goal_alternative[i])
+ == NO_REGS)
+ || no_input_reloads)
+ && mode != VOIDmode)
+ {
+ int this_address_reloaded;
+ rtx tem = force_const_mem (mode, op);
+
+ /* If we stripped a SUBREG or a PLUS above add it back. */
+ if (plus != NULL_RTX)
+ tem = gen_rtx_PLUS (mode, XEXP (plus, 0), tem);
+
+ if (subreg != NULL_RTX)
+ tem = gen_rtx_SUBREG (operand_mode[i], tem, SUBREG_BYTE (subreg));
+
+ this_address_reloaded = 0;
+ substed_operand[i] = recog_data.operand[i]
+ = find_reloads_toplev (tem, i, address_type[i], ind_levels,
+ 0, insn, &this_address_reloaded);
+
+ /* If the alternative accepts constant pool refs directly
+ there will be no reload needed at all. */
+ if (plus == NULL_RTX
+ && subreg == NULL_RTX
+ && 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;
+ }
}
/* Record the values of the earlyclobber operands for the caller. */
&& MEM_P (recog_data.operand[i]))
{
/* If the address to be reloaded is a VOIDmode constant,
- use Pmode as mode of the reload register, as would have
- been done by find_reloads_address. */
+ use the default address mode as mode of the reload register,
+ as would have been done by find_reloads_address. */
enum machine_mode address_mode;
address_mode = GET_MODE (XEXP (recog_data.operand[i], 0));
if (address_mode == VOIDmode)
- address_mode = Pmode;
+ {
+ addr_space_t as = MEM_ADDR_SPACE (recog_data.operand[i]);
+ address_mode = targetm.addr_space.address_mode (as);
+ }
operand_reloadnum[i]
= push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
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. */
/* 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)
+ && CONST_INT_P (XEXP (PATTERN (insn), 0)))
n_reloads = 0;
/* Perhaps an output reload can be combined with another
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 ATTRIBUTE_UNUSED,
+ 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 (x != mem)
+ 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)
- 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 (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;
}
#endif
&& (reg_equiv_address[regno] != 0
|| (reg_equiv_mem[regno] != 0
- && (! strict_memory_address_p (GET_MODE (x),
- XEXP (reg_equiv_mem[regno], 0))
+ && (! strict_memory_address_addr_space_p
+ (GET_MODE (x), XEXP (reg_equiv_mem[regno], 0),
+ MEM_ADDR_SPACE (reg_equiv_mem[regno]))
|| ! offsettable_memref_p (reg_equiv_mem[regno])
|| num_not_at_initial_offset))))
x = find_reloads_subreg_address (x, 1, opnum, type, ind_levels,
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
rtx tem
- = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
+ = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], VOIDmode, NULL_RTX),
+ 0);
/* If TEM might contain a pseudo, we must copy it to avoid
modifying it when we do the substitution for the reload. */
}
/* Returns true if AD could be turned into a valid memory reference
- to mode MODE by reloading the part pointed to by PART into a
- register. */
+ to mode MODE in address space AS by reloading the part pointed to
+ by PART into a register. */
static int
-maybe_memory_address_p (enum machine_mode mode, rtx ad, rtx *part)
+maybe_memory_address_addr_space_p (enum machine_mode mode, rtx ad,
+ addr_space_t as, rtx *part)
{
int retv;
rtx tem = *part;
rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ());
*part = reg;
- retv = memory_address_p (mode, ad);
+ retv = memory_address_addr_space_p (mode, ad, as);
*part = tem;
return retv;
rtx *loc, int opnum, enum reload_type type,
int ind_levels, rtx insn)
{
+ addr_space_t as = memrefloc? MEM_ADDR_SPACE (*memrefloc)
+ : ADDR_SPACE_GENERIC;
int regno;
int removed_and = 0;
int op_index;
{
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 (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
{
tem = make_memloc (ad, regno);
- if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
+ if (! strict_memory_address_addr_space_p (GET_MODE (tem),
+ XEXP (tem, 0),
+ MEM_ADDR_SPACE (tem)))
{
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)
+ if (!rtx_equal_p (tem, orig))
push_reg_equiv_alt_mem (regno, tem);
}
/* We can avoid a reload if the register's equivalent memory
address: only reg or reg+constant. */
if (ind_levels > 0
- && strict_memory_address_p (mode, tem)
+ && strict_memory_address_addr_space_p (mode, tem, as)
&& (REG_P (XEXP (tem, 0))
|| (GET_CODE (XEXP (tem, 0)) == PLUS
&& REG_P (XEXP (XEXP (tem, 0), 0))
return 1;
}
- if (strict_memory_address_p (mode, ad))
+ if (strict_memory_address_addr_space_p (mode, ad, as))
{
/* The address appears valid, so reloads are not needed.
But the address may contain an eliminable register.
/* But first quickly dispose of a common case. */
if (GET_CODE (ad) == PLUS
- && GET_CODE (XEXP (ad, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (ad, 1))
&& REG_P (XEXP (ad, 0))
&& reg_equiv_constant[REGNO (XEXP (ad, 0))] == 0)
return 0;
return 0;
/* Check result for validity after substitution. */
- if (strict_memory_address_p (mode, ad))
+ if (strict_memory_address_addr_space_p (mode, ad, as))
return 0;
}
#ifdef LEGITIMIZE_RELOAD_ADDRESS
do
{
- if (memrefloc)
+ if (memrefloc && ADDR_SPACE_GENERIC_P (as))
{
LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
ind_levels, win);
|| ! (REG_P (XEXP (tem, 0))
|| (GET_CODE (XEXP (tem, 0)) == PLUS
&& REG_P (XEXP (XEXP (tem, 0), 0))
- && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)))
+ && CONST_INT_P (XEXP (XEXP (tem, 0), 1)))))
{
/* Must use TEM here, not AD, since it is the one that will
have any subexpressions reloaded, if needed. */
else if (GET_CODE (ad) == PLUS
&& REG_P (XEXP (ad, 0))
&& REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
- && GET_CODE (XEXP (ad, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (ad, 1))
&& regno_ok_for_base_p (REGNO (XEXP (ad, 0)), mode, PLUS,
CONST_INT))
That will at least work. */
find_reloads_address_part (ad, loc,
base_reg_class (mode, MEM, SCRATCH),
- Pmode, opnum, type, ind_levels);
+ GET_MODE (ad), opnum, type, ind_levels);
}
return ! removed_and;
}
inner_code = GET_CODE (XEXP (ad, 0));
if (!(GET_CODE (ad) == PLUS
- && GET_CODE (XEXP (ad, 1)) == CONST_INT
+ && CONST_INT_P (XEXP (ad, 1))
&& (inner_code == PLUS || inner_code == LO_SUM)))
continue;
|| operand == arg_pointer_rtx
#endif
|| operand == stack_pointer_rtx)
- && ! maybe_memory_address_p (mode, ad,
- &XEXP (XEXP (ad, 0), 1 - op_index)))
+ && ! maybe_memory_address_addr_space_p
+ (mode, ad, as, &XEXP (XEXP (ad, 0), 1 - op_index)))
{
rtx offset_reg;
enum reg_class cls;
tem = ad;
if (GET_CODE (ad) == PLUS)
tem = subst_indexed_address (ad);
- if (tem != ad && strict_memory_address_p (mode, tem))
+ if (tem != ad && strict_memory_address_addr_space_p (mode, tem, as))
{
/* Ok, we win that way. Replace any additional eliminable
registers. */
/* Make sure that didn't make the address invalid again. */
- if (! subst_reg_equivs_changed || strict_memory_address_p (mode, tem))
+ if (! subst_reg_equivs_changed
+ || strict_memory_address_addr_space_p (mode, tem, as))
{
*loc = tem;
return 0;
/* If constants aren't valid addresses, reload the constant address
into a register. */
- if (CONSTANT_P (ad) && ! strict_memory_address_p (mode, ad))
+ if (CONSTANT_P (ad) && ! strict_memory_address_addr_space_p (mode, ad, as))
{
+ enum machine_mode address_mode = GET_MODE (ad);
+ if (address_mode == VOIDmode)
+ address_mode = targetm.addr_space.address_mode (as);
+
/* If AD is an address in the constant pool, the MEM rtx may be shared.
Unshare it so we can safely alter it. */
if (memrefloc && GET_CODE (ad) == SYMBOL_REF
}
find_reloads_address_part (ad, loc, base_reg_class (mode, MEM, SCRATCH),
- Pmode, opnum, type, ind_levels);
+ address_mode, opnum, type, ind_levels);
return ! removed_and;
}
case CONST_INT:
case CONST:
case CONST_DOUBLE:
+ case CONST_FIXED:
case CONST_VECTOR:
case SYMBOL_REF:
case LABEL_REF:
case PLUS:
/* Quickly dispose of a common case. */
if (XEXP (ad, 0) == frame_pointer_rtx
- && GET_CODE (XEXP (ad, 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (ad, 1)))
return ad;
break;
This routine assumes both inputs are already in canonical form. */
rtx
-form_sum (rtx x, rtx y)
+form_sum (enum machine_mode mode, rtx x, rtx y)
{
rtx tem;
- enum machine_mode mode = GET_MODE (x);
-
- if (mode == VOIDmode)
- mode = GET_MODE (y);
- if (mode == VOIDmode)
- mode = Pmode;
+ gcc_assert (GET_MODE (x) == mode || GET_MODE (x) == VOIDmode);
+ gcc_assert (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode);
- if (GET_CODE (x) == CONST_INT)
+ if (CONST_INT_P (x))
return plus_constant (y, INTVAL (x));
- else if (GET_CODE (y) == CONST_INT)
+ else if (CONST_INT_P (y))
return plus_constant (x, INTVAL (y));
else if (CONSTANT_P (x))
tem = x, x = y, y = tem;
if (GET_CODE (x) == PLUS && CONSTANT_P (XEXP (x, 1)))
- return form_sum (XEXP (x, 0), form_sum (XEXP (x, 1), y));
+ return form_sum (mode, XEXP (x, 0), form_sum (mode, XEXP (x, 1), y));
/* Note that if the operands of Y are specified in the opposite
order in the recursive calls below, infinite recursion will occur. */
if (GET_CODE (y) == PLUS && CONSTANT_P (XEXP (y, 1)))
- return form_sum (form_sum (x, XEXP (y, 0)), XEXP (y, 1));
+ return form_sum (mode, form_sum (mode, x, XEXP (y, 0)), XEXP (y, 1));
/* If both constant, encapsulate sum. Otherwise, just form sum. A
constant will have been placed second. */
/* Compute the sum. */
if (op2 != 0)
- op1 = form_sum (op1, op2);
+ op1 = form_sum (GET_MODE (addr), op1, op2);
if (op1 != 0)
- op0 = form_sum (op0, op1);
+ op0 = form_sum (GET_MODE (addr), op0, op1);
return op0;
}
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);
}
auto-modify by a constant then we could try replacing a pseudo
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)))
- 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, RELOAD_OTHER,
- ind_levels, insn);
+ 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)));
RELOAD_OTHER,
ind_levels, insn);
- if (tem != orig)
+ if (!rtx_equal_p (tem, orig))
push_reg_equiv_alt_mem (regno, tem);
/* Then reload the memory location into a base
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
&XEXP (tem, 0), opnum, type,
ind_levels, insn);
- if (tem != orig)
+ 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);
}
}
- /* 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, GET_MODE (x))->insn_code;
if (insn && NONJUMP_INSN_P (insn) && equiv
&& memory_operand (equiv, GET_MODE (equiv))
#ifdef HAVE_cc0
#endif
&& ! (icode != CODE_FOR_nothing
&& ((*insn_data[icode].operand[0].predicate)
- (equiv, Pmode))
+ (equiv, GET_MODE (x)))
&& ((*insn_data[icode].operand[1].predicate)
- (equiv, Pmode))))
+ (equiv, GET_MODE (x)))))
{
/* We use the original pseudo for loc, so that
emit_reload_insns() knows which pseudo this
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 (x != tem)
+ 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 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
base = XEXP (tem, 0);
if (GET_CODE (base) == PLUS)
{
- if (GET_CODE (XEXP (base, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (base, 1))
&& INTVAL (XEXP (base, 1)) % outer_size != 0)
return x;
base = XEXP (base, 0);
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 && tem != orig)
+ 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. Note that this is only
+ a problem if the address in reg_equiv_mem is already
+ invalid in the new mode; other cases would be fixed
+ by find_reloads_address as usual.
+
+ ??? We attempt to handle such cases here by doing an
+ additional reload of the full address after the
+ usual processing by find_reloads_address. Note that
+ this may not work in the general case, but it seems
+ to cover the cases where this situation currently
+ occurs. A more general fix might be to reload the
+ *value* instead of the address, but this would not
+ be expected by the callers of this routine as-is.
+
+ If find_reloads_address already completed replaced
+ the address, there is nothing further to do. */
+ if (reloaded == 0
+ && reg_equiv_mem[regno] != 0
+ && !strict_memory_address_addr_space_p
+ (GET_MODE (x), XEXP (reg_equiv_mem[regno], 0),
+ MEM_ADDR_SPACE (reg_equiv_mem[regno])))
+ 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
that delete_output_reload can see it. */
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;
}
/* If either argument is a constant, then modifying X can not affect IN. */
if (CONSTANT_P (x) || CONSTANT_P (in))
return 0;
- else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
+ else if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
return refers_to_mem_for_reload_p (in);
else if (GET_CODE (x) == SUBREG)
{
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;
while (1)
{
p = PREV_INSN (p);
+ if (p && DEBUG_INSN_P (p))
+ continue;
num++;
if (p == 0 || LABEL_P (p)
|| num > PARAM_VALUE (PARAM_MAX_RELOAD_SEARCH_INSNS))
|| (REG_P (SET_DEST (pat))
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
&& SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0)))
- && GET_CODE (goal) == CONST_INT
+ && CONST_INT_P (goal)
&& 0 != (goaltry
= operand_subword (XEXP (tem, 0), 0, 0,
VOIDmode))
&& REG_P (SET_DEST (pat))
&& GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
&& SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0)))
- && GET_CODE (goal) == CONST_INT
+ && CONST_INT_P (goal)
&& 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
VOIDmode))
&& rtx_equal_p (goal, goaltry)
}
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;
&& GET_CODE (XEXP (addr, 1)) == PLUS
&& XEXP (addr, 0) == XEXP (XEXP (addr, 1), 0)
&& XEXP (addr, 0) == inced
- && GET_CODE (XEXP (XEXP (addr, 1), 1)) == CONST_INT)
+ && CONST_INT_P (XEXP (XEXP (addr, 1), 1)))
{
i = INTVAL (XEXP (XEXP (addr, 1), 1));
return i < 0 ? -i : i;
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],