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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |alias, missed-optimization
             Status|RESOLVED                    |NEW
   Last reconfirmed|                            |2015-05-12
                 CC|                            |rguenth at gcc dot gnu.org
          Component|tree-optimization           |middle-end
         Resolution|FIXED                       |---
     Ever confirmed|0                           |1

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
So what happens is that GCC sees

  _3 = p_2(D)->p1;
  _3->f2 = 9;
  _5 = p_2(D)->p1;
  _5->f2 = 10;

and to remove the first store it first has to prove that _3 and _5 are equal.
CSE cannot prove this because it thinks the store to _3->f2 can clobber the
value at p_2(D)->p1 (if p->p1 points to p).

get_alias_set (_3->f2) returns 0, the alias oracle has special code to also
consider the alias set of the base objects:

  /* Do type-based disambiguation.  */
  if (base1_alias_set != base2_alias_set
      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
    return false;

but their alias sets happen to conflict because struct s2 alias set is a subset
of the struct s1 alias set (which is because alias set zero is a subset of
the struct s1 alias set...):

struct GTY(()) alias_set_entry_d {
  /* The alias set number, as stored in MEM_ALIAS_SET.  */
  alias_set_type alias_set;

  /* Nonzero if would have a child of zero: this effectively makes this
     alias set the same as alias set zero.  */
  int has_zero_child;

(I've always questioned this... - the code that looks at has_zero_child in
alias_set_subset_of / alias_sets_conflict_p).

Index: gcc/alias.c
===================================================================
--- gcc/alias.c (revision 222996)
+++ gcc/alias.c (working copy)
@@ -470,15 +470,13 @@ alias_sets_conflict_p (alias_set_type se
   /* See if the first alias set is a subset of the second.  */
   ase = get_alias_set_entry (set1);
   if (ase != 0
-      && (ase->has_zero_child
-         || ase->children->get (set2)))
+      && ase->children->get (set2))
     return 1;

   /* Now do the same, but with the alias sets reversed.  */
   ase = get_alias_set_entry (set2);
   if (ase != 0
-      && (ase->has_zero_child
-         || ase->children->get (set1)))
+      && ase->children->get (set1))
     return 1;

   /* The two alias sets are distinct and neither one is the

fixes this.  I don't remember what broke (but I remember trying this for a few
times - maybe with also changing alias_set_subset_of which isn't that obvious).

Reply via email to