summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/alias.c15
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.target/s390/pr67443.c49
4 files changed, 70 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b35b201b0f7..95479f3793a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2015-10-26 Richard Biener <rguenther@suse.de>
+ Dominik Vogt <vogt@linux.vnet.ibm.com>
+
+ PR middle-end/67443
+ * alias.c (ao_ref_from_mem): Remove promoted subreg handling.
+ Properly prune ref->ref for accesses outside of ref.
+
2015-10-26 Richard Sandiford <richard.sandiford@arm.com>
* gimple-fold.c (replace_stmt_with_simplification): Don't allow
diff --git a/gcc/alias.c b/gcc/alias.c
index 1c58547df72..5c1ad34e088 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -339,15 +339,16 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
|| !MEM_SIZE_KNOWN_P (mem))
return true;
- /* If the base decl is a parameter we can have negative MEM_OFFSET in
- case of promoted subregs on bigendian targets. Trust the MEM_EXPR
- here. */
+ /* If MEM_OFFSET/MEM_SIZE get us outside of ref->offset/ref->max_size
+ drop ref->ref. */
if (MEM_OFFSET (mem) < 0
- && (MEM_SIZE (mem) + MEM_OFFSET (mem)) * BITS_PER_UNIT == ref->size)
- return true;
+ || (ref->max_size != -1
+ && ((MEM_OFFSET (mem) + MEM_SIZE (mem)) * BITS_PER_UNIT
+ > ref->max_size)))
+ ref->ref = NULL_TREE;
- /* Otherwise continue and refine size and offset we got from analyzing
- MEM_EXPR by using MEM_SIZE and MEM_OFFSET. */
+ /* Refine size and offset we got from analyzing MEM_EXPR by using
+ MEM_SIZE and MEM_OFFSET. */
ref->offset += MEM_OFFSET (mem) * BITS_PER_UNIT;
ref->size = MEM_SIZE (mem) * BITS_PER_UNIT;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 73e0a39434a..fd5ade4ac88 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-10-26 Richard Biener <rguenther@suse.de>
+ Dominik Vogt <vogt@linux.vnet.ibm.com>
+
+ PR middle-end/67443
+ * gcc.target/s390/pr67443.c: New testcase.
+
2015-10-26 Christophe Lyon <christophe.lyon@linaro.org>
* gfortran.dg/chmod_1.f90: Add suffix to the temporary filename to
diff --git a/gcc/testsuite/gcc.target/s390/pr67443.c b/gcc/testsuite/gcc.target/s390/pr67443.c
new file mode 100644
index 00000000000..e011a11882f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/pr67443.c
@@ -0,0 +1,49 @@
+/* Test case for PR/67443. */
+
+/* { dg-do run { target s390*-*-* } } */
+/* { dg-prune-output "call-clobbered register used for global register variable" } */
+/* { dg-options "-march=z900 -fPIC -fomit-frame-pointer -O3" } */
+
+#include <assert.h>
+
+/* Block all registers except the first three argument registers. */
+register long r0 asm ("r0");
+register long r1 asm ("r1");
+register long r5 asm ("r5");
+register long r6 asm ("r6");
+register long r7 asm ("r7");
+register long r8 asm ("r8");
+register long r9 asm ("r9");
+register long r10 asm ("r10");
+register long r11 asm ("r11");
+
+struct s_t
+{
+ unsigned f1 : 8;
+ unsigned f2 : 24;
+};
+
+__attribute__ ((noinline))
+void foo (struct s_t *ps, int c, int i)
+{
+ /* Uses r2 as address register. */
+ ps->f1 = c;
+ /* The calculation of the value is so expensive that it's cheaper to spill ps
+ to the stack and reload it later (into a different register).
+ ==> Uses r4 as address register.*/
+ ps->f2 = i + i % 3;
+ /* If dead store elimination fails to detect that the address in r2 during
+ the first assignment is an alias of the address in r4 during the second
+ assignment, it eliminates the first assignment and the f1 field is not
+ written (bug). */
+}
+
+int main (void)
+{
+ struct s_t s = { 0x01u, 0x020304u };
+
+ foo (&s, 0, 0);
+ assert (s.f1 == 0&& s.f2 == 0);
+
+ return 0;
+}