reload.c (find_reloads_address): Try LEGITIMIZE_RELOAD_ADDRESS.
* reload.c (find_reloads_address): Try LEGITIMIZE_RELOAD_ADDRESS. (move_replacements): New function. * reload.h: Prototype it. * alpha.h (LEGITIMIZE_RELOAD_ADDRESS): New definition. Co-Authored-By: Richard Henderson <rth@cygnus.com> From-SVN: r18947
This commit is contained in:
parent
ce4d78eb2f
commit
a9a2595b58
@ -1,3 +1,12 @@
|
||||
Thu Apr 2 02:37:07 1998 Joern Rennecke (amylaar@cygnus.co.uk)
|
||||
Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* reload.c (find_reloads_address): Try LEGITIMIZE_RELOAD_ADDRESS.
|
||||
(move_replacements): New function.
|
||||
* reload.h: Prototype it.
|
||||
|
||||
* alpha.h (LEGITIMIZE_RELOAD_ADDRESS): New definition.
|
||||
|
||||
Thu Apr 2 01:01:34 1998 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* configure (alpha-*-linuxecoff, alpha-*-linux-gnulibc1):
|
||||
|
@ -1467,6 +1467,46 @@ extern void alpha_init_expanders ();
|
||||
} \
|
||||
}
|
||||
|
||||
/* Try a machine-dependent way of reloading an illegitimate address
|
||||
operand. If we find one, push the reload and jump to WIN. This
|
||||
macro is used in only one place: `find_reloads_address' in reload.c.
|
||||
|
||||
For the Alpha, we wish to handle large displacements off a base
|
||||
register by splitting the addend across an ldah and the mem insn.
|
||||
This cuts number of extra insns needed from 3 to 1. */
|
||||
|
||||
#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
|
||||
do { \
|
||||
if (GET_CODE (X) == PLUS \
|
||||
&& GET_CODE (XEXP (X, 0)) == REG \
|
||||
&& REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \
|
||||
&& REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \
|
||||
&& GET_CODE (XEXP (X, 1)) == CONST_INT) \
|
||||
{ \
|
||||
HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \
|
||||
HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; \
|
||||
HOST_WIDE_INT high \
|
||||
= (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; \
|
||||
\
|
||||
/* Check for 32-bit overflow. */ \
|
||||
if (high + low != val) \
|
||||
break; \
|
||||
\
|
||||
/* Reload the high part into a base reg; leave the low part \
|
||||
in the mem directly. */ \
|
||||
\
|
||||
X = gen_rtx_PLUS (GET_MODE (X), \
|
||||
gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \
|
||||
GEN_INT (high)), \
|
||||
GEN_INT (low)); \
|
||||
\
|
||||
push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
|
||||
BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
|
||||
OPNUM, TYPE); \
|
||||
goto WIN; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Go to LABEL if ADDR (a legitimate address expression)
|
||||
has an effect that depends on the machine mode it is used for.
|
||||
On the Alpha this is true only for the unaligned modes. We can
|
||||
|
37
gcc/reload.c
37
gcc/reload.c
@ -4422,6 +4422,24 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LEGITIMIZE_RELOAD_ADDRESS
|
||||
do
|
||||
{
|
||||
if (memrefloc)
|
||||
{
|
||||
LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
|
||||
ind_levels, win);
|
||||
}
|
||||
break;
|
||||
win:
|
||||
*memrefloc = copy_rtx (*memrefloc);
|
||||
XEXP (*memrefloc, 0) = ad;
|
||||
move_replacements (&ad, &XEXP (*memrefloc, 0));
|
||||
return 1;
|
||||
}
|
||||
while (0);
|
||||
#endif
|
||||
|
||||
/* The address is not valid. We have to figure out why. One possibility
|
||||
is that it is itself a MEM. This can happen when the frame pointer is
|
||||
being eliminated, a pseudo is not allocated to a hard register, and the
|
||||
@ -5372,6 +5390,25 @@ copy_replacements (x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Change any replacements being done to *X to be done to *Y */
|
||||
|
||||
void
|
||||
move_replacements (x, y)
|
||||
rtx *x;
|
||||
rtx *y;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_replacements; i++)
|
||||
if (replacements[i].subreg_loc == x)
|
||||
replacements[i].subreg_loc = y;
|
||||
else if (replacements[i].where == x)
|
||||
{
|
||||
replacements[i].where = y;
|
||||
replacements[i].subreg_loc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If LOC was scheduled to be replaced by something, return the replacement.
|
||||
Otherwise, return *LOC. */
|
||||
|
@ -187,6 +187,9 @@ extern void subst_reloads PROTO((void));
|
||||
the RTL. */
|
||||
extern void copy_replacements PROTO((rtx, rtx));
|
||||
|
||||
/* Change any replacements being done to *X to be done to *Y */
|
||||
extern void move_replacements PROTO((rtx *x, rtx *y));
|
||||
|
||||
/* If LOC was scheduled to be replaced by something, return the replacement.
|
||||
Otherwise, return *LOC. */
|
||||
extern rtx find_replacement PROTO((rtx *));
|
||||
|
45
gcc/tm.texi
45
gcc/tm.texi
@ -4223,6 +4223,51 @@ address. The compiler has standard ways of doing so in all cases. In
|
||||
fact, it is safe for this macro to do nothing. But often a
|
||||
machine-dependent strategy can generate better code.
|
||||
|
||||
@findex LEGITIMIZE_RELOAD_ADDRESS
|
||||
@item LEGITIMIZE_RELOAD_ADDRESS (@var{x}, @var{mode}, @var{opnum}, @var{type}, @var{ind_levels}, @var{win})
|
||||
A C compound statement that attempts to replace @var{x}, which is an address
|
||||
that needs reloading, with a valid memory address for an operand of mode
|
||||
@var{mode}. @var{win} will be a C statement label elsewhere in the code.
|
||||
It is not necessary to define this macro, but it might be useful for
|
||||
performance reasons.
|
||||
|
||||
For example, on the i386, it is sometimes possible to use a single
|
||||
reload register instead of two by reloading a sum of two pseudo
|
||||
registers into a register. On the other hand, for number of RISC
|
||||
processors offsets are limited so that often an intermediate address
|
||||
needs to be generated in order to address a stack slot. By defining
|
||||
LEGITIMIZE_RELOAD_ADDRESS appropriately, the intermediate addresses
|
||||
generated for adjacent some stack slots can be made identical, and thus
|
||||
be shared.
|
||||
|
||||
@findex strict_memory_address_p
|
||||
The macro definition may use @code{strict_memory_address_p} to test if
|
||||
the address has become legitimate.
|
||||
|
||||
@findex push_reload
|
||||
It may use @code{push_reload} to indicate parts that need reloading.
|
||||
@var{opnum}, @var{type} and @var{ind_levels} are usually suitable to be
|
||||
passed unaltered to push_reload.
|
||||
|
||||
The code generated by this macro should not alter the substructure of
|
||||
@var{x}. If it transforms @var{x} into a more legitimate form, it
|
||||
should assign @var{x} (which will always be a C variable) a new value.
|
||||
This also applies to parts that you change indirectly by calling
|
||||
@code{push_reload}.
|
||||
|
||||
@findex copy_rtx
|
||||
If you want to change only a part of @var{x}, one standard way of doing
|
||||
this is to use @code{copy_rtx}. Note, however, that is unshares only a
|
||||
single level of rtl. Thus, if the part to be changed is not at the
|
||||
top level, you'll need to replace first the top leve
|
||||
It is not necessary for this macro to come up with a legitimate
|
||||
address; but often a machine-dependent strategy can generate better code.
|
||||
|
||||
@emph{Note}: This macro should be used with caution. It is necessary
|
||||
to know something of how reload works in order to effectively use this,
|
||||
and it is quite easy to produce macros that build in too much knowledge
|
||||
of reload internals.
|
||||
|
||||
@findex GO_IF_MODE_DEPENDENT_ADDRESS
|
||||
@item GO_IF_MODE_DEPENDENT_ADDRESS (@var{addr}, @var{label})
|
||||
A C statement or compound statement with a conditional @code{goto
|
||||
|
Loading…
x
Reference in New Issue
Block a user