aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2013-02-07 13:07:37 +1030
committerAlan Modra <amodra@gcc.gnu.org>2013-02-07 13:07:37 +1030
commit921f2deea4f6f491d7e225d70d3787e8b490b18e (patch)
tree74f7dae5dd35b7b9606b665fc48d100c21ef808a /gcc
parentcdf383b6498460f095ff6a385270ebcfcb39a42c (diff)
downloadgcc-921f2deea4f6f491d7e225d70d3787e8b490b18e.zip
gcc-921f2deea4f6f491d7e225d70d3787e8b490b18e.tar.gz
gcc-921f2deea4f6f491d7e225d70d3787e8b490b18e.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/rs6000/rs6000.c110
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr54009.c43
4 files changed, 124 insertions, 39 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 24d2587..148aa67 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 76d7f3d..8b5f030 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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;
-
- if (off != NULL_RTX
- && (INTVAL (off) & 3) != 0
- && (unsigned HOST_WIDE_INT) INTVAL (off) + 0x8000 < 0x10000 - extra)
- {
- if (in_p)
- sri->icode = CODE_FOR_reload_di_load;
+ rtx addr = XEXP (x, 0);
+ rtx off = address_offset (addr);
+
+ if (off != NULL_RTX)
+ {
+ 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;
-
- /* 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 (in_p)
- sri->icode = CODE_FOR_reload_si_load;
+ rtx addr = XEXP (x, 0);
+ rtx off = address_offset (addr);
+
+ if (off != NULL_RTX)
+ {
+ 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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7dc9a02..d3407fd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/gcc.target/powerpc/pr54009.c b/gcc/testsuite/gcc.target/powerpc/pr54009.c
new file mode 100644
index 0000000..9af98ab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr54009.c
@@ -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;
+}