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).