re PR target/54009 (incorrect code generated for DFmode lo_sum mem)
gcc/ PR target/54009 * config/rs6000/rs6000.c (mem_operand_gpr): Check that LO_SUM addresses won't wrap when offsetting. (rs6000_secondary_reload): Provide secondary reloads needed for wrapping LO_SUM addresses. gcc/testsuite/ PR target/54009 * gcc.target/powerpc/pr54009.c: New test. From-SVN: r195836
This commit is contained in:
parent
cdf383b649
commit
921f2deea4
@ -1,3 +1,11 @@
|
||||
2013-02-07 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR target/54009
|
||||
* config/rs6000/rs6000.c (mem_operand_gpr): Check that LO_SUM
|
||||
addresses won't wrap when offsetting.
|
||||
(rs6000_secondary_reload): Provide secondary reloads needed for
|
||||
wrapping LO_SUM addresses.
|
||||
|
||||
2013-02-06 Thomas Schwinge <thomas@codesourcery.com>
|
||||
|
||||
* config/gnu.h (GNU_USER_TARGET_OS_CPP_BUILTINS): Never define
|
||||
|
@ -5135,17 +5135,14 @@ mem_operand_gpr (rtx op, enum machine_mode mode)
|
||||
if (TARGET_POWERPC64 && (offset & 3) != 0)
|
||||
return false;
|
||||
|
||||
if (GET_CODE (addr) == LO_SUM)
|
||||
/* We know by alignment that ABI_AIX medium/large model toc refs
|
||||
will not cross a 32k boundary, since all entries in the
|
||||
constant pool are naturally aligned and we check alignment for
|
||||
other medium model toc-relative addresses. For ABI_V4 and
|
||||
ABI_DARWIN lo_sum addresses, we just check that 64-bit
|
||||
offsets are 4-byte aligned. */
|
||||
return true;
|
||||
|
||||
extra = GET_MODE_SIZE (mode) - UNITS_PER_WORD;
|
||||
gcc_assert (extra >= 0);
|
||||
|
||||
if (GET_CODE (addr) == LO_SUM)
|
||||
/* For lo_sum addresses, we must allow any offset except one that
|
||||
causes a wrap, so test only the low 16 bits. */
|
||||
offset = ((offset & 0xffff) ^ 0x8000) - 0x8000;
|
||||
|
||||
return offset + 0x8000 < 0x10000u - extra;
|
||||
}
|
||||
|
||||
@ -13823,19 +13820,36 @@ rs6000_secondary_reload (bool in_p,
|
||||
&& MEM_P (x)
|
||||
&& GET_MODE_SIZE (GET_MODE (x)) >= UNITS_PER_WORD)
|
||||
{
|
||||
rtx off = address_offset (XEXP (x, 0));
|
||||
unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
|
||||
rtx addr = XEXP (x, 0);
|
||||
rtx off = address_offset (addr);
|
||||
|
||||
if (off != NULL_RTX
|
||||
&& (INTVAL (off) & 3) != 0
|
||||
&& (unsigned HOST_WIDE_INT) INTVAL (off) + 0x8000 < 0x10000 - extra)
|
||||
if (off != NULL_RTX)
|
||||
{
|
||||
if (in_p)
|
||||
sri->icode = CODE_FOR_reload_di_load;
|
||||
unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
|
||||
unsigned HOST_WIDE_INT offset = INTVAL (off);
|
||||
|
||||
/* We need a secondary reload when our legitimate_address_p
|
||||
says the address is good (as otherwise the entire address
|
||||
will be reloaded), and the offset is not a multiple of
|
||||
four or we have an address wrap. Address wrap will only
|
||||
occur for LO_SUMs since legitimate_offset_address_p
|
||||
rejects addresses for 16-byte mems that will wrap. */
|
||||
if (GET_CODE (addr) == LO_SUM
|
||||
? (1 /* legitimate_address_p allows any offset for lo_sum */
|
||||
&& ((offset & 3) != 0
|
||||
|| ((offset & 0xffff) ^ 0x8000) >= 0x10000 - extra))
|
||||
: (offset + 0x8000 < 0x10000 - extra /* legitimate_address_p */
|
||||
&& (offset & 3) != 0))
|
||||
{
|
||||
if (in_p)
|
||||
sri->icode = CODE_FOR_reload_di_load;
|
||||
else
|
||||
sri->icode = CODE_FOR_reload_di_store;
|
||||
sri->extra_cost = 2;
|
||||
ret = NO_REGS;
|
||||
}
|
||||
else
|
||||
sri->icode = CODE_FOR_reload_di_store;
|
||||
sri->extra_cost = 2;
|
||||
ret = NO_REGS;
|
||||
default_p = true;
|
||||
}
|
||||
else
|
||||
default_p = true;
|
||||
@ -13845,25 +13859,43 @@ rs6000_secondary_reload (bool in_p,
|
||||
&& MEM_P (x)
|
||||
&& GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
|
||||
{
|
||||
rtx off = address_offset (XEXP (x, 0));
|
||||
unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
|
||||
rtx addr = XEXP (x, 0);
|
||||
rtx off = address_offset (addr);
|
||||
|
||||
/* We need a secondary reload only when our legitimate_address_p
|
||||
says the address is good (as otherwise the entire address
|
||||
will be reloaded). So for mode sizes of 8 and 16 this will
|
||||
be when the offset is in the ranges [0x7ffc,0x7fff] and
|
||||
[0x7ff4,0x7ff7] respectively. Note that the address we see
|
||||
here may have been manipulated by legitimize_reload_address. */
|
||||
if (off != NULL_RTX
|
||||
&& ((unsigned HOST_WIDE_INT) INTVAL (off) - (0x8000 - extra)
|
||||
< UNITS_PER_WORD))
|
||||
if (off != NULL_RTX)
|
||||
{
|
||||
if (in_p)
|
||||
sri->icode = CODE_FOR_reload_si_load;
|
||||
unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
|
||||
unsigned HOST_WIDE_INT offset = INTVAL (off);
|
||||
|
||||
/* We need a secondary reload when our legitimate_address_p
|
||||
says the address is good (as otherwise the entire address
|
||||
will be reloaded), and we have a wrap.
|
||||
|
||||
legitimate_lo_sum_address_p allows LO_SUM addresses to
|
||||
have any offset so test for wrap in the low 16 bits.
|
||||
|
||||
legitimate_offset_address_p checks for the range
|
||||
[-0x8000,0x7fff] for mode size of 8 and [-0x8000,0x7ff7]
|
||||
for mode size of 16. We wrap at [0x7ffc,0x7fff] and
|
||||
[0x7ff4,0x7fff] respectively, so test for the
|
||||
intersection of these ranges, [0x7ffc,0x7fff] and
|
||||
[0x7ff4,0x7ff7] respectively.
|
||||
|
||||
Note that the address we see here may have been
|
||||
manipulated by legitimize_reload_address. */
|
||||
if (GET_CODE (addr) == LO_SUM
|
||||
? ((offset & 0xffff) ^ 0x8000) >= 0x10000 - extra
|
||||
: offset - (0x8000 - extra) < UNITS_PER_WORD)
|
||||
{
|
||||
if (in_p)
|
||||
sri->icode = CODE_FOR_reload_si_load;
|
||||
else
|
||||
sri->icode = CODE_FOR_reload_si_store;
|
||||
sri->extra_cost = 2;
|
||||
ret = NO_REGS;
|
||||
}
|
||||
else
|
||||
sri->icode = CODE_FOR_reload_si_store;
|
||||
sri->extra_cost = 2;
|
||||
ret = NO_REGS;
|
||||
default_p = true;
|
||||
}
|
||||
else
|
||||
default_p = true;
|
||||
|
@ -1,5 +1,7 @@
|
||||
2013-02-07 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR target/54009
|
||||
* gcc.target/powerpc/pr54009.c: New test.
|
||||
PR target/54131
|
||||
* gfortran.dg/pr54131.f: New test.
|
||||
|
||||
|
43
gcc/testsuite/gcc.target/powerpc/pr54009.c
Normal file
43
gcc/testsuite/gcc.target/powerpc/pr54009.c
Normal file
@ -0,0 +1,43 @@
|
||||
/* { dg-do compile { target { powerpc*-*-* } } } */
|
||||
/* { dg-require-effective-target powerpc_fprs } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-final { scan-assembler-not "\[\+\]32768" } } */
|
||||
|
||||
/* -O2 -m32 store to x.d in w was
|
||||
lis 9,x+32764@ha
|
||||
stw 10,x+32764@l(9)
|
||||
stw 11,x+32768@l(9) <-- wrap! */
|
||||
|
||||
struct big {
|
||||
char a[32764];
|
||||
double d __attribute__ ((aligned (4)));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern struct big x;
|
||||
double y;
|
||||
|
||||
void r (void)
|
||||
{
|
||||
double tmp = x.d;
|
||||
#if 1
|
||||
asm ("#": "+r" (tmp)
|
||||
: : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
|
||||
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
|
||||
"fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
|
||||
"fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31");
|
||||
#endif
|
||||
y = tmp;
|
||||
}
|
||||
|
||||
void w (void)
|
||||
{
|
||||
double tmp = y;
|
||||
#if 1
|
||||
asm ("#": "+r" (tmp)
|
||||
: : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
|
||||
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
|
||||
"fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
|
||||
"fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31");
|
||||
#endif
|
||||
x.d = tmp;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user