aboutsummaryrefslogtreecommitdiff
path: root/gcc/reload.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/reload.c')
-rw-r--r--gcc/reload.c213
1 files changed, 150 insertions, 63 deletions
diff --git a/gcc/reload.c b/gcc/reload.c
index a5069241cc3..285ddf0b5b6 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -1,6 +1,6 @@
/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
This file is part of GCC.
@@ -243,6 +243,7 @@ static int push_secondary_reload PARAMS ((int, rtx, int, int, enum reg_class,
static enum reg_class find_valid_class PARAMS ((enum machine_mode, int,
unsigned int));
static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode, int));
+static int can_reload_into PARAMS ((rtx, int, enum machine_mode));
static void push_replacement PARAMS ((rtx *, int, enum machine_mode));
static void dup_replacements PARAMS ((rtx *, rtx *));
static void combine_reloads PARAMS ((void));
@@ -258,6 +259,7 @@ static int alternative_allows_memconst PARAMS ((const char *, int));
static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
int, rtx, int *));
static rtx make_memloc PARAMS ((rtx, int));
+static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *));
static int find_reloads_address PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PARAMS ((rtx, rtx));
@@ -818,6 +820,13 @@ reload_inner_reg_of_subreg (x, mode, output)
|| REGNO (inner) >= FIRST_PSEUDO_REGISTER)
return 0;
+ if (!subreg_offset_representable_p
+ (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x)))
+ return 1;
+
/* If INNER is not ok for MODE, then INNER will need reloading. */
if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode))
return 1;
@@ -832,6 +841,59 @@ reload_inner_reg_of_subreg (x, mode, output)
!= (int) HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner))));
}
+/* Return nonzero if IN can be reloaded into REGNO with mode MODE without
+ requiring an extra reload register. The caller has already found that
+ IN contains some reference to REGNO, so check that we can produce the
+ new value in a single step. E.g. if we have
+ (set (reg r13) (plus (reg r13) (const int 1))), and there is an
+ instruction that adds one to a register, this should succeed.
+ However, if we have something like
+ (set (reg r13) (plus (reg r13) (const int 999))), and the constant 999
+ needs to be loaded into a register first, we need a separate reload
+ register.
+ Such PLUS reloads are generated by find_reload_address_part.
+ The out-of-range PLUS expressions are usually introduced in the instruction
+ patterns by register elimination and substituting pseudos without a home
+ by their function-invariant equivalences. */
+static int
+can_reload_into (in, regno, mode)
+ rtx in;
+ int regno;
+ enum machine_mode mode;
+{
+ rtx dst, test_insn;
+ int r = 0;
+ struct recog_data save_recog_data;
+
+ /* For matching constraints, we often get notional input reloads where
+ we want to use the original register as the reload register. I.e.
+ technically this is a non-optional input-output reload, but IN is
+ already a valid register, and has been chosen as the reload register.
+ Speed this up, since it trivially works. */
+ if (GET_CODE (in) == REG)
+ return 1;
+
+ /* To test MEMs properly, we'd have to take into account all the reloads
+ that are already scheduled, which can become quite complicated.
+ And since we've already handled address reloads for this MEM, it
+ should always succeed anyway. */
+ if (GET_CODE (in) == MEM)
+ return 1;
+
+ /* If we can make a simple SET insn that does the job, everything should
+ be fine. */
+ dst = gen_rtx_REG (mode, regno);
+ test_insn = make_insn_raw (gen_rtx_SET (VOIDmode, dst, in));
+ save_recog_data = recog_data;
+ if (recog_memoized (test_insn) >= 0)
+ {
+ extract_insn (test_insn);
+ r = constrain_operands (1);
+ }
+ recog_data = save_recog_data;
+ return r;
+}
+
/* Record one reload that needs to be performed.
IN is an rtx saying where the data are to be found before this instruction.
OUT says where they must be stored after the instruction.
@@ -968,9 +1030,7 @@ push_reload (in, out, inloc, outloc, class,
if (in != 0 && GET_CODE (in) == SUBREG
&& (subreg_lowpart_p (in) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !reg_classes_intersect_p
- (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)),
- inmode))
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class)
#endif
&& (CONSTANT_P (SUBREG_REG (in))
|| GET_CODE (SUBREG_REG (in)) == PLUS
@@ -1080,9 +1140,7 @@ push_reload (in, out, inloc, outloc, class,
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
#ifdef CANNOT_CHANGE_MODE_CLASS
- && !reg_classes_intersect_p
- (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)),
- outmode))
+ && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class)
#endif
&& (CONSTANT_P (SUBREG_REG (out))
|| strict_low
@@ -1528,7 +1586,11 @@ push_reload (in, out, inloc, outloc, class,
regno + offs))
break;
- if (offs == nregs)
+ if (offs == nregs
+ && (! (refers_to_regno_for_reload_p
+ (regno, (regno + HARD_REGNO_NREGS (regno, inmode)),
+ in, (rtx *)0))
+ || can_reload_into (in, regno, inmode)))
{
rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
break;
@@ -2472,6 +2534,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
char pref_or_nothing[MAX_RECOG_OPERANDS];
/* Nonzero for a MEM operand whose entire address needs a reload. */
int address_reloaded[MAX_RECOG_OPERANDS];
+ /* Nonzero for an address operand that needs to be completely reloaded. */
+ int address_operand_reloaded[MAX_RECOG_OPERANDS];
/* Value of enum reload_type to use for operand. */
enum reload_type operand_type[MAX_RECOG_OPERANDS];
/* Value of enum reload_type to use within address of operand. */
@@ -2597,7 +2661,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (i == noperands - 1)
abort ();
- commutative = i;
+ /* We currently only support one commutative pair of
+ operands. Some existing asm code currently uses more
+ than one pair. Previously, that would usually work,
+ but sometimes it would crash the compiler. We
+ continue supporting that case as well as we can by
+ silently ignoring all but the first pair. In the
+ future we may handle it correctly. */
+ if (commutative < 0)
+ commutative = i;
}
else if (ISDIGIT (c))
{
@@ -2650,6 +2722,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
RTX_CODE code = GET_CODE (recog_data.operand[i]);
address_reloaded[i] = 0;
+ address_operand_reloaded[i] = 0;
operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT
: modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT
: RELOAD_OTHER);
@@ -2664,10 +2737,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
else if (constraints[i][0] == 'p'
|| EXTRA_ADDRESS_CONSTRAINT (constraints[i][0]))
{
- find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
- recog_data.operand[i],
- recog_data.operand_loc[i],
- i, operand_type[i], ind_levels, insn);
+ address_operand_reloaded[i]
+ = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
+ recog_data.operand[i],
+ recog_data.operand_loc[i],
+ i, operand_type[i], ind_levels, insn);
/* If we now have a simple operand where we used to have a
PLUS or MULT, re-recognize and try again. */
@@ -2684,6 +2758,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
recog_data.operand[i] = *recog_data.operand_loc[i];
substed_operand[i] = recog_data.operand[i];
+
+ /* Address operands are reloaded in their existing mode,
+ no matter what is specified in the machine description. */
+ operand_mode[i] = GET_MODE (recog_data.operand[i]);
}
else if (code == MEM)
{
@@ -2864,6 +2942,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (GET_CODE (SUBREG_REG (operand)) == REG
&& 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;
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
GET_MODE (SUBREG_REG (operand)),
SUBREG_BYTE (operand),
@@ -2919,26 +3003,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
)
#endif
)
- /* This following hunk of code should no longer be
- needed at all with SUBREG_BYTE. If you need this
- code back, please explain to me why so I can
- fix the real problem. -DaveM */
-#if 0
- /* Subreg of a hard reg which can't handle the subreg's mode
- or which would handle that mode in the wrong number of
- registers for subregging to work. */
- || (GET_CODE (operand) == REG
- && REGNO (operand) < FIRST_PSEUDO_REGISTER
- && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (operand))
- > UNITS_PER_WORD)
- && ((GET_MODE_SIZE (GET_MODE (operand))
- / UNITS_PER_WORD)
- != HARD_REGNO_NREGS (REGNO (operand),
- GET_MODE (operand))))
- || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
- operand_mode[i])))
-#endif
)
force_reload = 1;
}
@@ -2969,9 +3033,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
break;
case '%':
- /* The last operand should not be marked commutative. */
- if (i != noperands - 1)
- commutative = i;
+ /* We only support one commutative marker, the first
+ one. We already set commutative above. */
break;
case '?':
@@ -3283,10 +3346,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
the address into a base register. */
this_alternative[i] = (int) MODE_BASE_REG_CLASS (VOIDmode);
badop = 0;
-
- /* Address constraints are reloaded in Pmode, no matter
- what mode is given in the machine description. */
- operand_mode[i] = Pmode;
break;
}
@@ -3856,6 +3915,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
}
else if (goal_alternative_matched[i] < 0
&& goal_alternative_matches[i] < 0
+ && !address_operand_reloaded[i]
&& optimize)
{
/* For each non-matching operand that's a MEM or a pseudo-register
@@ -4561,6 +4621,27 @@ make_memloc (ad, regno)
return tem;
}
+/* 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. */
+
+static int
+maybe_memory_address_p (mode, ad, part)
+ enum machine_mode mode;
+ rtx ad;
+ 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);
+ *part = tem;
+
+ return retv;
+}
+
/* Record all reloads needed for handling memory address AD
which appears in *LOC in a memory reference to mode MODE
which itself is found in location *MEMREFLOC.
@@ -4841,26 +4922,24 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
that the index needs a reload and find_reloads_address_1 will take care
of it.
- If we decide to do something here, it must be that
- `double_reg_address_ok' is true and that this address rtl was made by
- eliminate_regs. We generate a reload of the fp/sp/ap + constant and
+ Handle all base registers here, not just fp/ap/sp, because on some
+ targets (namely Sparc) we can also get invalid addresses from preventive
+ subreg big-endian corrections made by find_reloads_toplev.
+
+ If we decide to do something, it must be that `double_reg_address_ok'
+ is true. We generate a reload of the base register + constant and
rework the sum so that the reload register will be added to the index.
This is safe because we know the address isn't shared.
- We check for fp/ap/sp as both the first and second operand of the
- innermost PLUS. */
+ We check for the base register as both the first and second operand of
+ the innermost PLUS. */
else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == PLUS
- && (XEXP (XEXP (ad, 0), 0) == frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- || XEXP (XEXP (ad, 0), 0) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
-#endif
- || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
- && ! memory_address_p (mode, ad))
+ && GET_CODE (XEXP (XEXP (ad, 0), 0)) == REG
+ && REGNO (XEXP (XEXP (ad, 0), 0)) < FIRST_PSEUDO_REGISTER
+ && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 0), mode)
+ && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1)))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
plus_constant (XEXP (XEXP (ad, 0), 0),
@@ -4877,15 +4956,10 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
&& GET_CODE (XEXP (ad, 0)) == PLUS
- && (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- || XEXP (XEXP (ad, 0), 1) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
-#endif
- || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
- && ! memory_address_p (mode, ad))
+ && GET_CODE (XEXP (XEXP (ad, 0), 1)) == REG
+ && REGNO (XEXP (XEXP (ad, 0), 1)) < FIRST_PSEUDO_REGISTER
+ && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 1), mode)
+ && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0)))
{
*loc = ad = gen_rtx_PLUS (GET_MODE (ad),
XEXP (XEXP (ad, 0), 0),
@@ -5230,6 +5304,19 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
SUBREG_BYTE (orig_op1),
GET_MODE (orig_op1))));
}
+ /* Plus in the index register may be created only as a result of
+ register remateralization for expresion like &localvar*4. Reload it.
+ It may be possible to combine the displacement on the outer level,
+ but it is probably not worthwhile to do so. */
+ if (context)
+ {
+ find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
+ opnum, ADDR_TYPE (type), ind_levels, insn);
+ push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|| code0 == ZERO_EXTEND || code1 == MEM)