This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: reload displacement optimization
- To: rth at cygnus dot com
- Subject: Re: reload displacement optimization
- From: Joern Rennecke <amylaar at cygnus dot co dot uk>
- Date: Tue, 10 Mar 1998 13:50:26 +0000 (GMT)
- Cc: egcs at cygnus dot com
> While looking into some problems in reload this evening (which I could
> not reproduce, annoyingly), I noticed that reload would produce, when
> a displacement off of a base register is out of range,
>
> lda $6,-31856
> ldah $6,1($6)
> addq $6,$30,$6
> ldq $12,0($6)
>
> when
>
> ldah $6,1($30)
> ldq $12,-31856($6)
>
> is sufficient.
>
> The solution, I believe, is to teach find_reloads_address about
> this new way to break up an address. The following patch does this,
> but in a blatently machine dependent way.
>
> Can anyone think of a way to properly conditionalize this, and
> to break up the address?
I made a new macro LEGITIMIZE_RELOAD_ADDRESS for the SH and i386 some time
ago, but since Kenner doesn't care enough about embedded targets and the
i386 didn't make a convincing case, it never got submitted.
Could you fit your optimization into this framework?
------------------- old patch follows ----------------------------------
The text size of the i386 stage1 cc1 minus the size of reload.o
(reload.c was changed) shrank by 208 bytes, or 0.018% .
Nice, but I think we need some better RISC workstation results to make a
convincing case.
diff -p -r ss-961031/config/i386/i386.h ss-961031-leg-rel/config/i386/i386.h
*** ss-961031/config/i386/i386.h Tue Oct 15 16:21:03 1996
--- ss-961031-leg-rel/config/i386/i386.h Tue Nov 5 23:18:09 1996
*************** do { \
*** 1638,1643 ****
--- 1638,1704 ----
goto WIN; \
}
+ #define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)\
+ do { \
+ if (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == REG && GET_CODE (XEXP (X, 1)) == REG \
+ && REGNO (XEXP (X, 0)) >= FIRST_PSEUDO_REGISTER \
+ && REGNO (XEXP (X, 1)) >= FIRST_PSEUDO_REGISTER) \
+ { \
+ int reg0 = REGNO (XEXP (X, 0)); \
+ int reg1 = REGNO (XEXP (X, 1)); \
+ \
+ /* pic handling isn't implemented for this macro yet, so \
+ bail out if one of the operands might require it. */ \
+ if (flag_pic \
+ && ((reg_equiv_constant[reg0] \
+ && SYMBOLIC_CONST (reg_equiv_constant[reg0])) \
+ || (reg_equiv_constant[reg1] \
+ && SYMBOLIC_CONST (reg_equiv_constant[reg1])) \
+ || reg_equiv_memory_loc[reg0] \
+ || reg_equiv_memory_loc[reg1])) \
+ break; \
+ \
+ if (reg_equiv_memory_loc[reg0]) \
+ X = gen_rtx (PLUS, Pmode, \
+ eliminate_regs (reg_equiv_memory_loc[reg0], Pmode, \
+ NULL_RTX), \
+ XEXP (X, 1)); \
+ if (reg_equiv_memory_loc[reg1]) \
+ X = gen_rtx (PLUS, Pmode, XEXP (X, 0), \
+ eliminate_regs (reg_equiv_memory_loc[reg1], Pmode, \
+ NULL_RTX)); \
+ if (reg_equiv_constant[reg0]) \
+ { \
+ X = gen_rtx (PLUS, Pmode, XEXP (X, 1), reg_equiv_constant[reg0]);\
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ INDEX_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM), \
+ (TYPE)); \
+ goto win; \
+ } \
+ if (reg_equiv_constant[reg1]) \
+ { \
+ X = gen_rtx (PLUS, Pmode, XEXP (X, 0), reg_equiv_constant[reg1]);\
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ INDEX_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM), \
+ (TYPE)); \
+ goto win; \
+ } \
+ push_reload (X, NULL_RTX, &X, NULL_PTR, INDEX_REG_CLASS, Pmode, \
+ VOIDmode, 0, 0, (OPNUM), (TYPE)); \
+ goto win; \
+ } \
+ if (GET_CODE (X) == PLUS \
+ && (GET_CODE (XEXP (X, 0)) == MEM \
+ || GET_CODE (XEXP (X, 1)) == MEM)) \
+ { \
+ /* We created this before from reg_equiv_memory_loc. */ \
+ push_reload (X, NULL_RTX, &X, NULL_PTR, INDEX_REG_CLASS, Pmode, \
+ VOIDmode, 0, 0, (OPNUM), (TYPE)); \
+ goto win; \
+ } \
+ } while (0);
+
#define REWRITE_ADDRESS(x) rewrite_address(x)
/* Nonzero if the constant value X is a legitimate general operand
diff -p -r ss-961031/config/sh/sh.h ss-961031-leg-rel/config/sh/sh.h
*** ss-961031/config/sh/sh.h Fri Nov 1 20:22:33 1996
--- ss-961031-leg-rel/config/sh/sh.h Tue Nov 5 23:19:10 1996
*************** extern struct rtx_def *sh_builtin_savere
*** 1119,1124 ****
--- 1119,1177 ----
} \
}
+ #define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
+ { \
+ if (GET_CODE (X) == PLUS \
+ && (GET_MODE_SIZE (MODE) == 4 || GET_MODE_SIZE (MODE) == 8) \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && BASE_REGISTER_RTX_P (XEXP (X, 0)) \
+ && ! (TARGET_SH3E && MODE == SFmode)) \
+ { \
+ rtx index_rtx = XEXP (X, 1); \
+ HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; \
+ rtx sum; \
+ \
+ /* Instead of offset_base 128..131 use 124..127, so that \
+ simple add suffices. */ \
+ if (offset > 127) \
+ { \
+ offset_base = ((offset + 4) & ~60) - 4; \
+ } \
+ else \
+ offset_base = offset & ~60; \
+ /* Sometimes the normal form does not suit DImode. We \
+ could avoid that by using smaller ranges, but that \
+ would give less optimized code when SImode is \
+ prevalent. */ \
+ if (GET_MODE_SIZE (MODE) + offset - offset_base <= 64) \
+ { \
+ sum = gen_rtx (PLUS, Pmode, XEXP (X, 0), \
+ GEN_INT (offset_base)); \
+ X = gen_rtx (PLUS, Pmode, sum, GEN_INT (offset - offset_base));\
+ push_reload (sum, NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM), \
+ (TYPE)); \
+ goto WIN; \
+ } \
+ } \
+ /* We must re-recognize what we created before. */ \
+ else if (GET_CODE (X) == PLUS \
+ && (GET_MODE_SIZE (MODE) == 4 || GET_MODE_SIZE (MODE) == 8) \
+ && GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
+ && BASE_REGISTER_RTX_P (XEXP (XEXP (X, 0), 0)) \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && ! (TARGET_SH3E && MODE == SFmode)) \
+ { \
+ /* Because this address is so complex, we know it must have \
+ been created by LEGITIMIZE_RELOAD_ADDRESS before; thus, \
+ it is already unshared, and needs no further unsharing. */ \
+ push_reload (XEXP ((X), 0), NULL_RTX, &XEXP ((X), 0), NULL_PTR, \
+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM), (TYPE));\
+ goto WIN; \
+ } \
+ }
+
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for. */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
diff -p -r ss-961031/reload.c ss-961031-leg-rel/reload.c
*** ss-961031/reload.c Fri Nov 1 20:22:40 1996
--- ss-961031-leg-rel/reload.c Tue Nov 5 23:19:53 1996
*************** find_reloads_address (mode, memrefloc, a
*** 4253,4258 ****
--- 4253,4272 ----
return 0;
}
+ #ifdef LEGITIMIZE_RELOAD_ADDRESS
+ if (memrefloc)
+ LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
+ ind_levels, win);
+ if (0)
+ {
+ win:
+ *memrefloc = copy_rtx (*memrefloc);
+ XEXP (*memrefloc, 0) = ad;
+ move_replacements (&ad, &XEXP (*memrefloc, 0));
+ return 1;
+ }
+ #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
*************** copy_replacements (x, y)
*** 5124,5129 ****
--- 5138,5162 ----
r->mode = replacements[j].mode;
}
}
+ }
+
+ /* 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.
diff -p -r ss-961031/reload.h ss-961031-leg-rel/reload.h
*** ss-961031/reload.h Thu Jun 15 13:00:35 1995
--- ss-961031-leg-rel/reload.h Tue Nov 5 23:19:53 1996
*************** extern void subst_reloads PROTO((void));
*** 176,181 ****
--- 176,185 ----
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 *));
diff -p -r ss-961031/tm.texi ss-961031-leg-rel/tm.texi
*** ss-961031/tm.texi Tue Oct 15 16:21:16 1996
--- ss-961031-leg-rel/tm.texi Wed Nov 6 02:57:28 1996
*************** address. The compiler has standard ways
*** 4026,4031 ****
--- 4026,4075 ----
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.
+ Another example: For a 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 adjactend some stack
+ slots can be made identical, and thus be shared.
+
+ The macro definition may use
+
+ @example
+ strict_memory_address_p (@var{mode}, @var{x});
+ @end example
+
+ @noindent
+ 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.
+
@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