mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-29 22:15:03 +08:00
re PR target/50751 (SH Target: Displacement addressing does not work for QImode and HImode)
PR target/50751 * config/sh/sh.c (sh_legitimize_address, sh_legitimize_reload_address): Rearrange conditional logic. Move displacement address calculations to ... (sh_find_mov_disp_adjust): ... this new function. From-SVN: r185894
This commit is contained in:
parent
719e1e80d4
commit
8c6d71c06b
@ -1,3 +1,11 @@
|
|||||||
|
2012-03-27 Oleg Endo <olegendo@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR target/50751
|
||||||
|
* config/sh/sh.c (sh_legitimize_address, sh_legitimize_reload_address):
|
||||||
|
Rearrange conditional logic. Move displacement address calculations
|
||||||
|
to ...
|
||||||
|
(sh_find_mov_disp_adjust): ... this new function.
|
||||||
|
|
||||||
2012-03-27 H.J. Lu <hongjiu.lu@intel.com>
|
2012-03-27 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* config/arm/arm.opt (mapcs): Remove MaskExists.
|
* config/arm/arm.opt (mapcs): Remove MaskExists.
|
||||||
|
@ -9783,13 +9783,80 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|||||||
return orig;
|
return orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try machine-dependent ways of modifying an illegitimate address
|
/* Given a (logical) mode size and an offset in bytes, try to find a the
|
||||||
to be legitimate. If we find one, return the new, valid address.
|
appropriate displacement value for a mov insn. On SH the displacements
|
||||||
Otherwise, return X.
|
are limited to max. 60 bytes for SImode, max. 30 bytes in HImode and max.
|
||||||
|
15 bytes in QImode. To compensate this we create a new base address by
|
||||||
|
adding an adjustment value to it.
|
||||||
|
|
||||||
For the SH, if X is almost suitable for indexing, but the offset is
|
If the originally requested offset is greater than 127 we prefer using
|
||||||
out of range, convert it into a normal form so that CSE has a chance
|
values 124..127 over 128..131 to increase opportunities to use the
|
||||||
of reducing the number of address registers used. */
|
add #imm, Rn insn.
|
||||||
|
|
||||||
|
In some cases it is possible that a requested offset might seem unaligned
|
||||||
|
or inappropriate for the mode size, like offset = 2 and mode size = 4.
|
||||||
|
This is compensated by adjusting the base address so that the effective
|
||||||
|
address of the displacement move insn will be aligned.
|
||||||
|
|
||||||
|
This is not the best possible way of rebasing the base address, as it
|
||||||
|
does not look at other present displacement addressings around it.
|
||||||
|
In some cases this can create more base address adjustments than would
|
||||||
|
actually be necessary. */
|
||||||
|
|
||||||
|
struct disp_adjust
|
||||||
|
{
|
||||||
|
rtx offset_adjust;
|
||||||
|
rtx mov_disp;
|
||||||
|
int max_mov_disp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct disp_adjust
|
||||||
|
sh_find_mov_disp_adjust (int mode_sz, HOST_WIDE_INT offset)
|
||||||
|
{
|
||||||
|
struct disp_adjust res = { NULL_RTX, NULL_RTX, 0 };
|
||||||
|
|
||||||
|
/* The max. available mode for actual move insns is SImode.
|
||||||
|
Larger accesses will be split into multiple loads/stores. */
|
||||||
|
const int max_mov_sz = GET_MODE_SIZE (SImode);
|
||||||
|
|
||||||
|
const int mov_insn_size = mode_sz >= max_mov_sz ? max_mov_sz : mode_sz;
|
||||||
|
const HOST_WIDE_INT max_disp = 15 * mov_insn_size;
|
||||||
|
HOST_WIDE_INT align_modifier = offset > 127 ? mov_insn_size : 0;
|
||||||
|
|
||||||
|
HOST_WIDE_INT offset_adjust;
|
||||||
|
|
||||||
|
/* In some cases this actually does happen and we must check for it. */
|
||||||
|
if (mode_sz < 1 || mode_sz > 8)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
/* FIXME: HImode with displacement addressing is not supported yet.
|
||||||
|
Make it purposefully fail for now. */
|
||||||
|
if (mov_insn_size == 2)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
/* Keeps the previous behavior for QImode displacement addressing.
|
||||||
|
This just decides how the offset is re-based. Removing this special
|
||||||
|
case will result in slightly bigger code on average, but it's not that
|
||||||
|
bad actually. */
|
||||||
|
if (mov_insn_size == 1)
|
||||||
|
align_modifier = 0;
|
||||||
|
|
||||||
|
res.max_mov_disp = max_disp + mov_insn_size;
|
||||||
|
|
||||||
|
offset_adjust = ((offset + align_modifier) & ~max_disp) - align_modifier;
|
||||||
|
|
||||||
|
if (mode_sz + offset - offset_adjust <= res.max_mov_disp)
|
||||||
|
{
|
||||||
|
res.offset_adjust = GEN_INT (offset_adjust);
|
||||||
|
res.mov_disp = GEN_INT (offset - offset_adjust);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to modify an illegitimate address and make it legitimate.
|
||||||
|
If we find one, return the new, valid address.
|
||||||
|
Otherwise, return the original address. */
|
||||||
|
|
||||||
static rtx
|
static rtx
|
||||||
sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
|
sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
|
||||||
@ -9797,66 +9864,33 @@ sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
|
|||||||
if (flag_pic)
|
if (flag_pic)
|
||||||
x = legitimize_pic_address (oldx, mode, NULL_RTX);
|
x = legitimize_pic_address (oldx, mode, NULL_RTX);
|
||||||
|
|
||||||
if (GET_CODE (x) == PLUS
|
if (TARGET_SHMEDIA)
|
||||||
&& (GET_MODE_SIZE (mode) == 4
|
return x;
|
||||||
|| GET_MODE_SIZE (mode) == 8)
|
|
||||||
&& CONST_INT_P (XEXP (x, 1))
|
if (((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
|
||||||
&& BASE_REGISTER_RTX_P (XEXP (x, 0))
|
|| (TARGET_SH2E && mode == SFmode))
|
||||||
&& ! TARGET_SHMEDIA
|
return x;
|
||||||
&& ! ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
|
|
||||||
&& ! (TARGET_SH2E && mode == SFmode))
|
if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1))
|
||||||
|
&& BASE_REGISTER_RTX_P (XEXP (x, 0)))
|
||||||
{
|
{
|
||||||
rtx index_rtx = XEXP (x, 1);
|
const int mode_sz = GET_MODE_SIZE (mode);
|
||||||
HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base;
|
struct disp_adjust adj = sh_find_mov_disp_adjust (mode_sz,
|
||||||
rtx sum;
|
INTVAL (XEXP (x, 1)));
|
||||||
|
|
||||||
/* On rare occasions, we might get an unaligned pointer
|
if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX)
|
||||||
that is indexed in a way to give an aligned address.
|
|
||||||
Therefore, keep the lower two bits in offset_base. */
|
|
||||||
/* 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 = expand_binop (Pmode, add_optab, XEXP (x, 0),
|
|
||||||
GEN_INT (offset_base), NULL_RTX, 0,
|
|
||||||
OPTAB_LIB_WIDEN);
|
|
||||||
|
|
||||||
return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This could be generalized for SImode, HImode, QImode displacement
|
|
||||||
addressing. */
|
|
||||||
if (mode == QImode && GET_CODE (x) == PLUS
|
|
||||||
&& BASE_REGISTER_RTX_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
|
|
||||||
{
|
|
||||||
rtx index_rtx = XEXP (x, 1);
|
|
||||||
HOST_WIDE_INT offset = INTVAL (index_rtx);
|
|
||||||
HOST_WIDE_INT offset_base = offset & ~15;
|
|
||||||
|
|
||||||
if (offset - offset_base <= 16)
|
|
||||||
{
|
{
|
||||||
rtx sum = expand_binop (Pmode, add_optab, XEXP (x, 0),
|
rtx sum = expand_binop (Pmode, add_optab, XEXP (x, 0),
|
||||||
GEN_INT (offset_base), NULL_RTX, 0,
|
adj.offset_adjust, NULL_RTX, 0,
|
||||||
OPTAB_LIB_WIDEN);
|
OPTAB_LIB_WIDEN);
|
||||||
|
return gen_rtx_PLUS (Pmode, sum, adj.mov_disp);
|
||||||
return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to replace *P, which is an address that needs reloading, with
|
/* Attempt to replace *p, which is an address that needs reloading, with
|
||||||
a valid memory address for an operand of mode MODE.
|
a valid memory address for an operand of mode MODE.
|
||||||
Like for sh_legitimize_address, for the SH we try to get a normal form
|
Like for sh_legitimize_address, for the SH we try to get a normal form
|
||||||
of the address. That will allow inheritance of the address reloads. */
|
of the address. That will allow inheritance of the address reloads. */
|
||||||
@ -9866,75 +9900,71 @@ sh_legitimize_reload_address (rtx *p, enum machine_mode mode, int opnum,
|
|||||||
int itype)
|
int itype)
|
||||||
{
|
{
|
||||||
enum reload_type type = (enum reload_type) itype;
|
enum reload_type type = (enum reload_type) itype;
|
||||||
|
const int mode_sz = GET_MODE_SIZE (mode);
|
||||||
|
|
||||||
if (GET_CODE (*p) == PLUS
|
if (TARGET_SHMEDIA)
|
||||||
&& (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)
|
return false;
|
||||||
&& CONST_INT_P (XEXP (*p, 1))
|
|
||||||
|
if (GET_CODE (*p) == PLUS && CONST_INT_P (XEXP (*p, 1))
|
||||||
&& MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true)
|
&& MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true)
|
||||||
&& ! TARGET_SHMEDIA
|
|
||||||
&& ! (TARGET_SH4 && mode == DFmode)
|
|
||||||
&& ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS)
|
&& ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS)
|
||||||
&& (ALLOW_INDEXED_ADDRESS
|
&& (ALLOW_INDEXED_ADDRESS
|
||||||
|| XEXP (*p, 0) == stack_pointer_rtx
|
|| XEXP (*p, 0) == stack_pointer_rtx
|
||||||
|| XEXP (*p, 0) == hard_frame_pointer_rtx))
|
|| XEXP (*p, 0) == hard_frame_pointer_rtx))
|
||||||
{
|
{
|
||||||
rtx index_rtx = XEXP (*p, 1);
|
const HOST_WIDE_INT offset = INTVAL (XEXP (*p, 1));
|
||||||
HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base;
|
struct disp_adjust adj = sh_find_mov_disp_adjust (mode_sz, offset);
|
||||||
rtx sum;
|
|
||||||
|
|
||||||
if (TARGET_SH2A && mode == DFmode && (offset & 0x7))
|
if (TARGET_SH2A && mode == DFmode && (offset & 0x7))
|
||||||
{
|
{
|
||||||
push_reload (*p, NULL_RTX, p, NULL,
|
push_reload (*p, NULL_RTX, p, NULL,
|
||||||
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
||||||
goto win;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TARGET_SH2E && mode == SFmode)
|
if (TARGET_SH2E && mode == SFmode)
|
||||||
{
|
{
|
||||||
*p = copy_rtx (*p);
|
*p = copy_rtx (*p);
|
||||||
push_reload (*p, NULL_RTX, p, NULL,
|
push_reload (*p, NULL_RTX, p, NULL,
|
||||||
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
||||||
goto win;
|
return true;
|
||||||
}
|
}
|
||||||
/* Instead of offset_base 128..131 use 124..127, so that
|
|
||||||
simple add suffices. */
|
/* FIXME: Do not allow to legitimize QImode and HImode displacement
|
||||||
if (offset > 127)
|
moves because then reload has a problem figuring the constraint
|
||||||
offset_base = ((offset + 4) & ~60) - 4;
|
that the move insn target/source reg must be R0.
|
||||||
else
|
Or maybe some handling is wrong in sh_secondary_reload for this
|
||||||
offset_base = offset & ~60;
|
to work properly? */
|
||||||
/* Sometimes the normal form does not suit DImode. We could avoid
|
if ((mode_sz == 4 || mode_sz == 8)
|
||||||
that by using smaller ranges, but that would give less optimized
|
&& ! (TARGET_SH4 && mode == DFmode)
|
||||||
code when SImode is prevalent. */
|
&& adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX)
|
||||||
if (GET_MODE_SIZE (mode) + offset - offset_base <= 64)
|
|
||||||
{
|
{
|
||||||
sum = gen_rtx_PLUS (Pmode, XEXP (*p, 0), GEN_INT (offset_base));
|
rtx sum = gen_rtx_PLUS (Pmode, XEXP (*p, 0), adj.offset_adjust);
|
||||||
*p = gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base));
|
*p = gen_rtx_PLUS (Pmode, sum, adj.mov_disp);
|
||||||
push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL,
|
push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL,
|
||||||
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
||||||
goto win;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We must re-recognize what we created before. */
|
/* We must re-recognize what we created before. */
|
||||||
else if (GET_CODE (*p) == PLUS
|
if (GET_CODE (*p) == PLUS
|
||||||
&& (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)
|
&& (mode_sz == 4 || mode_sz == 8)
|
||||||
&& GET_CODE (XEXP (*p, 0)) == PLUS
|
&& GET_CODE (XEXP (*p, 0)) == PLUS
|
||||||
&& CONST_INT_P (XEXP (XEXP (*p, 0), 1))
|
&& CONST_INT_P (XEXP (XEXP (*p, 0), 1))
|
||||||
&& MAYBE_BASE_REGISTER_RTX_P (XEXP (XEXP (*p, 0), 0), true)
|
&& MAYBE_BASE_REGISTER_RTX_P (XEXP (XEXP (*p, 0), 0), true)
|
||||||
&& CONST_INT_P (XEXP (*p, 1))
|
&& CONST_INT_P (XEXP (*p, 1))
|
||||||
&& ! TARGET_SHMEDIA
|
&& ! (TARGET_SH2E && mode == SFmode))
|
||||||
&& ! (TARGET_SH2E && mode == SFmode))
|
|
||||||
{
|
{
|
||||||
/* Because this address is so complex, we know it must have
|
/* Because this address is so complex, we know it must have
|
||||||
been created by LEGITIMIZE_RELOAD_ADDRESS before; thus,
|
been created by LEGITIMIZE_RELOAD_ADDRESS before; thus,
|
||||||
it is already unshared, and needs no further unsharing. */
|
it is already unshared, and needs no further unsharing. */
|
||||||
push_reload (XEXP (*p, 0), NULL_RTX, &XEXP (*p, 0), NULL,
|
push_reload (XEXP (*p, 0), NULL_RTX, &XEXP (*p, 0), NULL,
|
||||||
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type);
|
||||||
goto win;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
win:
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In the name of slightly smaller debug output, and to cater to
|
/* In the name of slightly smaller debug output, and to cater to
|
||||||
|
Loading…
Reference in New Issue
Block a user