This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR67443
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Dominik Vogt <vogt at linux dot vnet dot ibm dot com>
- Date: Wed, 21 Oct 2015 14:56:05 +0200 (CEST)
- Subject: [PATCH] Fix PR67443
- Authentication-results: sourceware.org; auth=none
The following patch fixes PR67443, ao_ref_from_mem's special handling
of some negative MEM_OFFSET cases being wrong in general. The patch
removes the special-casing and places an additional safety net
for MEM_EXPR handlings that rely on component bounds being honored.
The patch might pessimize the mentioned "promoted subreg parameter"
handling as for negative MEM_OFFSET we now run into
/* If MEM_OFFSET and MEM_SIZE get us outside of the base object of
the MEM_EXPR punt. This happens for STRICT_ALIGNMENT targets a lot.
*/
if (MEM_EXPR (mem) != get_spill_slot_decl (false)
&& (ref->offset < 0
|| (DECL_P (ref->base)
&& (DECL_SIZE (ref->base) == NULL_TREE
|| TREE_CODE (DECL_SIZE (ref->base)) != INTEGER_CST
|| wi::ltu_p (wi::to_offset (DECL_SIZE (ref->base)),
ref->offset + ref->size)))))
return false;
but I can't see how the previous handling was correct with regard
to overlaps in the parameter area.
Bootstrapped and tested on x86_64-unknown-linux-gnu and
powerpc64-linux-gnu by me and on s390[x]-linux by Dominik.
Eventually we'll get another testcase so I'll leave this for
comments a while and will commit somewhen later this week.
Thanks,
Richard.
2015-10-21 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.
Index: gcc/alias.c
===================================================================
*** gcc/alias.c (revision 229119)
--- gcc/alias.c (working copy)
*************** ao_ref_from_mem (ao_ref *ref, const_rtx
*** 339,353 ****
|| !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) < 0
! && (MEM_SIZE (mem) + MEM_OFFSET (mem)) * BITS_PER_UNIT == ref->size)
! return true;
! /* Otherwise continue and 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;
--- 339,354 ----
|| !MEM_SIZE_KNOWN_P (mem))
return true;
! /* If MEM_OFFSET/MEM_SIZE get us outside of ref->offset/ref->max_size
! drop ref->ref. */
if (MEM_OFFSET (mem) < 0
! || (ref->max_size != -1
! && ((MEM_OFFSET (mem) + MEM_SIZE (mem)) * BITS_PER_UNIT
! > ref->max_size)))
! ref->ref = NULL_TREE;
! /* 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;
Index: gcc/testsuite/gcc.target/s390/pr67443.c
===================================================================
*** gcc/testsuite/gcc.target/s390/pr67443.c (revision 0)
--- gcc/testsuite/gcc.target/s390/pr67443.c (working copy)
***************
*** 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;
+ }