https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67443

--- Comment #16 from Richard Biener <rguenth at gcc dot gnu.org> ---
I see multiple issues with ao_ref_from_mem connected with MEM_OFFSET/MEM_SIZE.
I don't remember exactly what was the issue with the promoted parameters
but it may have been with ranges_overlap_p not dealing with signed offsets
properly (that has been fixed meanwhile).

So I'd start with simply removing

  /* 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;

One issue that remains is that when MEM_OFFSET/MEM_SIZE gets us outside
of the MEM_EXPR object (its offset/size) we have to strip
handled-component-refs
until MEM_OFFSET/MEM_SIZE are again within bounds (or conservatively reset
ref->ref to NULL_TREE).  Either the code adjusting the mem attributes
MEM_OFFSET/MEM_SIZE is supposed to do that already (no idea) or we'll run into
issues.

Basically MEM_SIZE must be <= ref->size, MEM_OFFSET may never be negative
unless ref->offset is zero and if MEM_OFFSET is positive then
MEM_OFFSET + MEM_SIZE must be <= ref->size.

It's of course a tricky area ;)

I believe that

  /* 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;

will ultimatively "save" us here as well (very conservatively though).

So does

Index: gcc/alias.c
===================================================================
--- gcc/alias.c (revision 229022)
+++ gcc/alias.c (working copy)
@@ -339,15 +339,16 @@ ao_ref_from_mem (ao_ref *ref, const_rtx
       || !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;

fix the issue?

Reply via email to